diff --git a/x-pack/plugin/security/qa/basic-enable-security/src/test/java/org/elasticsearch/xpack/security/EnableSecurityOnBasicLicenseIT.java b/x-pack/plugin/security/qa/basic-enable-security/src/test/java/org/elasticsearch/xpack/security/EnableSecurityOnBasicLicenseIT.java index f3ce68e85a0..7d7b1d84a2b 100644 --- a/x-pack/plugin/security/qa/basic-enable-security/src/test/java/org/elasticsearch/xpack/security/EnableSecurityOnBasicLicenseIT.java +++ b/x-pack/plugin/security/qa/basic-enable-security/src/test/java/org/elasticsearch/xpack/security/EnableSecurityOnBasicLicenseIT.java @@ -132,7 +132,8 @@ public class EnableSecurityOnBasicLicenseIT extends ESRestTestCase { final Map auth = getAsMap("/_security/_authenticate"); // From file realm, configured in build.gradle assertThat(ObjectPath.evaluate(auth, "username"), equalTo("security_test_user")); - assertThat(ObjectPath.evaluate(auth, "roles"), contains("security_test_role")); + // The anonymous role is granted by anonymous access enabled in build.gradle + assertThat(ObjectPath.evaluate(auth, "roles"), contains("security_test_role", "anonymous")); } private void checkAllowedWrite(String indexName) throws IOException { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java index 36f1fbf21be..155685aa23e 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -448,6 +448,7 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin, final NativeRoleMappingStore nativeRoleMappingStore = new NativeRoleMappingStore(settings, client, securityIndex.get(), scriptService); final AnonymousUser anonymousUser = new AnonymousUser(settings); + components.add(anonymousUser); final ReservedRealm reservedRealm = new ReservedRealm(environment, settings, nativeUsersStore, anonymousUser, securityIndex.get(), threadPool); final SecurityExtension.SecurityComponents extensionComponents = new ExtensionComponents(environment, client, clusterService, diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/user/TransportAuthenticateAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/user/TransportAuthenticateAction.java index a51717cf3a1..db626e1b7a0 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/user/TransportAuthenticateAction.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/user/TransportAuthenticateAction.java @@ -17,18 +17,24 @@ import org.elasticsearch.xpack.core.security.action.user.AuthenticateAction; import org.elasticsearch.xpack.core.security.action.user.AuthenticateRequest; import org.elasticsearch.xpack.core.security.action.user.AuthenticateResponse; import org.elasticsearch.xpack.core.security.authc.Authentication; +import org.elasticsearch.xpack.core.security.user.AnonymousUser; import org.elasticsearch.xpack.core.security.user.SystemUser; import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.core.security.user.XPackUser; +import java.util.stream.Stream; + public class TransportAuthenticateAction extends HandledTransportAction { private final SecurityContext securityContext; + private final AnonymousUser anonymousUser; @Inject - public TransportAuthenticateAction(TransportService transportService, ActionFilters actionFilters, SecurityContext securityContext) { + public TransportAuthenticateAction(TransportService transportService, ActionFilters actionFilters, SecurityContext securityContext, + AnonymousUser anonymousUser) { super(AuthenticateAction.NAME, transportService, actionFilters, AuthenticateRequest::new); this.securityContext = securityContext; + this.anonymousUser = anonymousUser; } @Override @@ -43,7 +49,32 @@ public class TransportAuthenticateAction extends HandledTransportAction null, null, Collections.emptySet()); TransportAuthenticateAction action = new TransportAuthenticateAction(transportService, - mock(ActionFilters.class), securityContext); + mock(ActionFilters.class), securityContext, prepareAnonymousUser()); final AtomicReference throwableRef = new AtomicReference<>(); final AtomicReference responseRef = new AtomicReference<>(); @@ -70,7 +71,7 @@ public class TransportAuthenticateActionTests extends ESTestCase { TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null, TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet()); TransportAuthenticateAction action = new TransportAuthenticateAction(transportService, - mock(ActionFilters.class), securityContext); + mock(ActionFilters.class), securityContext, prepareAnonymousUser()); final AtomicReference throwableRef = new AtomicReference<>(); final AtomicReference responseRef = new AtomicReference<>(); @@ -98,10 +99,12 @@ public class TransportAuthenticateActionTests extends ESTestCase { SecurityContext securityContext = mock(SecurityContext.class); when(securityContext.getAuthentication()).thenReturn(authentication); when(securityContext.getUser()).thenReturn(user); + + final AnonymousUser anonymousUser = prepareAnonymousUser(); TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null, TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet()); TransportAuthenticateAction action = new TransportAuthenticateAction(transportService, - mock(ActionFilters.class), securityContext); + mock(ActionFilters.class), securityContext, anonymousUser); final AtomicReference throwableRef = new AtomicReference<>(); final AtomicReference responseRef = new AtomicReference<>(); @@ -118,7 +121,35 @@ public class TransportAuthenticateActionTests extends ESTestCase { }); assertThat(responseRef.get(), notNullValue()); - assertThat(responseRef.get().authentication(), sameInstance(authentication)); + if (anonymousUser.enabled()) { + final Authentication auth = responseRef.get().authentication(); + final User authUser = auth.getUser(); + org.elasticsearch.common.collect.List.of(authUser.roles()).containsAll( + org.elasticsearch.common.collect.List.of(authentication.getUser().roles())); + org.elasticsearch.common.collect.List.of(authUser.roles()).containsAll( + org.elasticsearch.common.collect.List.of(anonymousUser.roles())); + assertThat(authUser.authenticatedUser(), sameInstance(user.authenticatedUser())); + assertThat(auth.getAuthenticatedBy(), sameInstance(auth.getAuthenticatedBy())); + assertThat(auth.getLookedUpBy(), sameInstance(auth.getLookedUpBy())); + assertThat(auth.getVersion(), sameInstance(auth.getVersion())); + assertThat(auth.getAuthenticationType(), sameInstance(auth.getAuthenticationType())); + assertThat(auth.getMetadata(), sameInstance(auth.getMetadata())); + } else { + assertThat(responseRef.get().authentication(), sameInstance(authentication)); + } assertThat(throwableRef.get(), nullValue()); } + + private AnonymousUser prepareAnonymousUser() { + final AnonymousUser anonymousUser = mock(AnonymousUser.class); + if (randomBoolean()) { + when(anonymousUser.enabled()).thenReturn(true); + when(anonymousUser.roles()).thenReturn( + randomList(1, 4, () -> randomAlphaOfLengthBetween(4, 12)).toArray(new String[0])); + } else { + when(anonymousUser.enabled()).thenReturn(false); + } + return anonymousUser; + } + } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateActionTests.java index e2d2e096d20..871bcbe3be5 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateActionTests.java @@ -67,8 +67,13 @@ public class RestAuthenticateActionTests extends SecurityIntegTestCase { assertThat(objectPath.evaluate("lookup_realm.type").toString(), equalTo("file")); assertThat(objectPath.evaluate("authentication_type").toString(), equalTo("realm")); List roles = objectPath.evaluate("roles"); - assertThat(roles.size(), is(1)); - assertThat(roles, contains(SecuritySettingsSource.TEST_ROLE)); + if (anonymousEnabled) { + assertThat(roles.size(), is(3)); + assertThat(roles, contains(SecuritySettingsSource.TEST_ROLE, SecuritySettingsSource.TEST_ROLE, "foo")); + } else { + assertThat(roles.size(), is(1)); + assertThat(roles, contains(SecuritySettingsSource.TEST_ROLE)); + } } public void testAuthenticateApiWithoutAuthentication() throws Exception {