diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java index 8d08a0dba58..42cab54b0ca 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java @@ -554,6 +554,13 @@ public class AuthenticationService { */ // pkg-private for tests void handleNullToken() { + List unlicensedRealms = realms.getUnlicensedRealms(); + if (unlicensedRealms.isEmpty() == false) { + logger.warn("No authentication credential could be extracted using realms [{}]." + + " Realms [{}] were skipped because they are not permitted on the current license", + Strings.collectionToCommaDelimitedString(defaultOrderedRealmList), + Strings.collectionToCommaDelimitedString(unlicensedRealms)); + } final Authentication authentication; if (fallbackUser != null) { logger.trace("No valid credentials found in request [{}], using fallback [{}]", request, fallbackUser.principal()); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java index f5919e81dce..6e1adcc8020 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java @@ -5,6 +5,9 @@ */ package org.elasticsearch.xpack.security.authc; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.SetOnce; import org.elasticsearch.ElasticsearchException; @@ -34,6 +37,7 @@ import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; @@ -51,6 +55,7 @@ import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.test.ClusterServiceUtils; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.MockLogAppender; import org.elasticsearch.test.rest.FakeRestRequest; import org.elasticsearch.threadpool.FixedExecutorBuilder; import org.elasticsearch.threadpool.TestThreadPool; @@ -84,6 +89,7 @@ import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm; import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.junit.After; import org.junit.Before; +import org.mockito.Mockito; import java.io.IOException; import java.net.InetAddress; @@ -181,9 +187,11 @@ public class AuthenticationServiceTests extends ESTestCase { firstRealm = mock(Realm.class); when(firstRealm.type()).thenReturn(FIRST_REALM_TYPE); when(firstRealm.name()).thenReturn(FIRST_REALM_NAME); + when(firstRealm.toString()).thenReturn(FIRST_REALM_NAME + "/" + FIRST_REALM_TYPE); secondRealm = mock(Realm.class); when(secondRealm.type()).thenReturn(SECOND_REALM_TYPE); when(secondRealm.name()).thenReturn(SECOND_REALM_NAME); + when(secondRealm.toString()).thenReturn(SECOND_REALM_NAME + "/" + SECOND_REALM_TYPE); Settings settings = Settings.builder() .put("path.home", createTempDir()) .put("node.name", "authc_test") @@ -275,18 +283,37 @@ public class AuthenticationServiceTests extends ESTestCase { } public void testTokenMissing() throws Exception { - final String reqId = AuditUtil.getOrGenerateRequestId(threadContext); - PlainActionFuture future = new PlainActionFuture<>(); - Authenticator authenticator = service.createAuthenticator("_action", transportRequest, true, future); - authenticator.extractToken((token) -> { - assertThat(token, nullValue()); - authenticator.handleNullToken(); - }); + final Logger unlicensedRealmsLogger = LogManager.getLogger(AuthenticationService.class); + final MockLogAppender mockAppender = new MockLogAppender(); + mockAppender.start(); + try { + Loggers.addAppender(unlicensedRealmsLogger, mockAppender); + mockAppender.addExpectation(new MockLogAppender.SeenEventExpectation( + "unlicensed realms", + AuthenticationService.class.getName(), Level.WARN, + "No authentication credential could be extracted using realms [file_realm/file]. " + + "Realms [second_realm/second] were skipped because they are not permitted on the current license" + )); - ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, () -> future.actionGet()); - assertThat(e.getMessage(), containsString("missing authentication credentials")); - verify(auditTrail).anonymousAccessDenied(reqId, "_action", transportRequest); - verifyNoMoreInteractions(auditTrail); + Mockito.doReturn(org.elasticsearch.common.collect.List.of(secondRealm)).when(realms).getUnlicensedRealms(); + Mockito.doReturn(org.elasticsearch.common.collect.List.of(firstRealm)).when(realms).asList(); + final String reqId = AuditUtil.getOrGenerateRequestId(threadContext); + PlainActionFuture future = new PlainActionFuture<>(); + Authenticator authenticator = service.createAuthenticator("_action", transportRequest, true, future); + authenticator.extractToken((token) -> { + assertThat(token, nullValue()); + authenticator.handleNullToken(); + }); + + ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, () -> future.actionGet()); + assertThat(e.getMessage(), containsString("missing authentication credentials")); + verify(auditTrail).anonymousAccessDenied(reqId, "_action", transportRequest); + verifyNoMoreInteractions(auditTrail); + mockAppender.assertAllExpectationsMatched(); + } finally { + Loggers.removeAppender(unlicensedRealmsLogger, mockAppender); + mockAppender.stop(); + } } public void testAuthenticateBothSupportSecondSucceeds() throws Exception {