From 580b5baf215e7615680b5b3dc85e2cb9d0fa04ba Mon Sep 17 00:00:00 2001 From: Ioannis Kakavas Date: Tue, 27 Nov 2018 23:35:42 +0200 Subject: [PATCH] Add realm information for Authenticate API (#35648) - Add the authentication realm and lookup realm name and type in the response for the _authenticate API - The authentication realm is set as the lookup realm too (instead of setting the lookup realm to null or empty ) when no lookup realm is used. --- .../client/security/AuthenticateResponse.java | 82 ++++++++++++++++--- .../SecurityDocumentationIT.java | 8 ++ .../security/AuthenticateResponseTests.java | 48 +++++++++-- .../high-level/security/authenticate.asciidoc | 14 +++- .../rest-api/security/authenticate.asciidoc | 14 +++- .../action/user/AuthenticateResponse.java | 27 ++++-- .../core/security/authc/Authentication.java | 29 ++++++- .../xpack/core/security/user/User.java | 4 + .../user/TransportAuthenticateAction.java | 6 +- .../rest/action/RestAuthenticateAction.java | 2 +- .../TransportAuthenticateActionTests.java | 12 ++- .../security/authc/TokenAuthIntegTests.java | 8 +- .../authc/esnative/NativeRealmIntegTests.java | 6 +- .../action/RestAuthenticateActionTests.java | 7 +- .../authc/ldap/ActiveDirectoryRunAsIT.java | 2 +- 15 files changed, 222 insertions(+), 47 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/AuthenticateResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/AuthenticateResponse.java index 62f1cc0955bd1..b3b8fc2c23591 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/AuthenticateResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/AuthenticateResponse.java @@ -46,27 +46,43 @@ public final class AuthenticateResponse { static final ParseField FULL_NAME = new ParseField("full_name"); static final ParseField EMAIL = new ParseField("email"); static final ParseField ENABLED = new ParseField("enabled"); + static final ParseField AUTHENTICATION_REALM = new ParseField("authentication_realm"); + static final ParseField LOOKUP_REALM = new ParseField("lookup_realm"); + static final ParseField REALM_NAME = new ParseField("name"); + static final ParseField REALM_TYPE = new ParseField("type"); @SuppressWarnings("unchecked") private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( "client_security_authenticate_response", a -> new AuthenticateResponse(new User((String) a[0], ((List) a[1]), (Map) a[2], - (String) a[3], (String) a[4]), (Boolean) a[5])); + (String) a[3], (String) a[4]), (Boolean) a[5], (RealmInfo) a[6], (RealmInfo) a[7])); static { + final ConstructingObjectParser realmInfoParser = new ConstructingObjectParser<>("realm_info", + a -> new RealmInfo((String) a[0], (String) a[1])); + realmInfoParser.declareString(constructorArg(), REALM_NAME); + realmInfoParser.declareString(constructorArg(), REALM_TYPE); PARSER.declareString(constructorArg(), USERNAME); PARSER.declareStringArray(constructorArg(), ROLES); PARSER.>declareObject(constructorArg(), (parser, c) -> parser.map(), METADATA); PARSER.declareStringOrNull(optionalConstructorArg(), FULL_NAME); PARSER.declareStringOrNull(optionalConstructorArg(), EMAIL); PARSER.declareBoolean(constructorArg(), ENABLED); + PARSER.declareObject(constructorArg(), realmInfoParser, AUTHENTICATION_REALM); + PARSER.declareObject(constructorArg(), realmInfoParser, LOOKUP_REALM); } private final User user; private final boolean enabled; + private final RealmInfo authenticationRealm; + private final RealmInfo lookupRealm; - public AuthenticateResponse(User user, boolean enabled) { + + public AuthenticateResponse(User user, boolean enabled, RealmInfo authenticationRealm, + RealmInfo lookupRealm) { this.user = user; this.enabled = enabled; + this.authenticationRealm = authenticationRealm; + this.lookupRealm = lookupRealm; } /** @@ -85,25 +101,69 @@ public boolean enabled() { return enabled; } + /** + * @return the realm that authenticated the user + */ + public RealmInfo getAuthenticationRealm() { + return authenticationRealm; + } + + /** + * @return the realm where the user information was looked up + */ + public RealmInfo getLookupRealm() { + return lookupRealm; + } + @Override public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final AuthenticateResponse that = (AuthenticateResponse) o; - return user.equals(that.user) && enabled == that.enabled; + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AuthenticateResponse that = (AuthenticateResponse) o; + return enabled == that.enabled && + Objects.equals(user, that.user) && + Objects.equals(authenticationRealm, that.authenticationRealm) && + Objects.equals(lookupRealm, that.lookupRealm); } @Override public int hashCode() { - return Objects.hash(user, enabled); + return Objects.hash(user, enabled, authenticationRealm, lookupRealm); } public static AuthenticateResponse fromXContent(XContentParser parser) throws IOException { return PARSER.parse(parser, null); } + public static class RealmInfo { + private String name; + private String type; + + RealmInfo(String name, String type) { + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RealmInfo realmInfo = (RealmInfo) o; + return Objects.equals(name, realmInfo.name) && + Objects.equals(type, realmInfo.type); + } + + @Override + public int hashCode() { + return Objects.hash(name, type); + } + } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java index 130ab83ebdad6..d44e91652ecfb 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java @@ -532,6 +532,10 @@ public void testAuthenticate() throws Exception { //tag::authenticate-response User user = response.getUser(); // <1> boolean enabled = response.enabled(); // <2> + final String authenticationRealmName = response.getAuthenticationRealm().getName(); // <3> + final String authenticationRealmType = response.getAuthenticationRealm().getType(); // <4> + final String lookupRealmName = response.getLookupRealm().getName(); // <5> + final String lookupRealmType = response.getLookupRealm().getType(); // <6> //end::authenticate-response assertThat(user.getUsername(), is("test_user")); @@ -540,6 +544,10 @@ public void testAuthenticate() throws Exception { assertThat(user.getEmail(), nullValue()); assertThat(user.getMetadata().isEmpty(), is(true)); assertThat(enabled, is(true)); + assertThat(authenticationRealmName, is("default_file")); + assertThat(authenticationRealmType, is("file")); + assertThat(lookupRealmName, is("default_file")); + assertThat(lookupRealmType, is("file")); } { diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/AuthenticateResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/AuthenticateResponseTests.java index 1931ce3f69883..f09340fa09ffd 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/AuthenticateResponseTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/AuthenticateResponseTests.java @@ -70,7 +70,14 @@ protected AuthenticateResponse createTestInstance() { final String fullName = randomFrom(random(), null, randomAlphaOfLengthBetween(0, 4)); final String email = randomFrom(random(), null, randomAlphaOfLengthBetween(0, 4)); final boolean enabled = randomBoolean(); - return new AuthenticateResponse(new User(username, roles, metadata, fullName, email), enabled); + final String authenticationRealmName = randomAlphaOfLength(5); + final String authenticationRealmType = randomFrom("file", "native", "ldap", "active_directory", "saml", "kerberos"); + final String lookupRealmName = randomAlphaOfLength(5); + final String lookupRealmType = randomFrom("file", "native", "ldap", "active_directory", "saml", "kerberos"); + return new AuthenticateResponse( + new User(username, roles, metadata, fullName, email), enabled, + new AuthenticateResponse.RealmInfo(authenticationRealmName, authenticationRealmType), + new AuthenticateResponse.RealmInfo(lookupRealmName, lookupRealmType)); } private void toXContent(AuthenticateResponse response, XContentBuilder builder) throws IOException { @@ -87,6 +94,14 @@ private void toXContent(AuthenticateResponse response, XContentBuilder builder) builder.field(AuthenticateResponse.EMAIL.getPreferredName(), user.getEmail()); } builder.field(AuthenticateResponse.ENABLED.getPreferredName(), enabled); + builder.startObject(AuthenticateResponse.AUTHENTICATION_REALM.getPreferredName()); + builder.field(AuthenticateResponse.REALM_NAME.getPreferredName(), response.getAuthenticationRealm().getName()); + builder.field(AuthenticateResponse.REALM_TYPE.getPreferredName(), response.getAuthenticationRealm().getType()); + builder.endObject(); + builder.startObject(AuthenticateResponse.LOOKUP_REALM.getPreferredName()); + builder.field(AuthenticateResponse.REALM_NAME.getPreferredName(), response.getLookupRealm().getName()); + builder.field(AuthenticateResponse.REALM_TYPE.getPreferredName(), response.getLookupRealm().getType()); + builder.endObject(); builder.endObject(); } @@ -94,34 +109,49 @@ private AuthenticateResponse copy(AuthenticateResponse response) { final User originalUser = response.getUser(); final User copyUser = new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(), originalUser.getFullName(), originalUser.getEmail()); - return new AuthenticateResponse(copyUser, response.enabled()); + return new AuthenticateResponse(copyUser, response.enabled(), response.getAuthenticationRealm(), + response.getLookupRealm()); } private AuthenticateResponse mutate(AuthenticateResponse response) { final User originalUser = response.getUser(); - switch (randomIntBetween(1, 6)) { + switch (randomIntBetween(1, 8)) { case 1: return new AuthenticateResponse(new User(originalUser.getUsername() + "wrong", originalUser.getRoles(), - originalUser.getMetadata(), originalUser.getFullName(), originalUser.getEmail()), response.enabled()); + originalUser.getMetadata(), originalUser.getFullName(), originalUser.getEmail()), response.enabled(), + response.getAuthenticationRealm(), response.getLookupRealm()); case 2: final Collection wrongRoles = new ArrayList<>(originalUser.getRoles()); wrongRoles.add(randomAlphaOfLengthBetween(1, 4)); return new AuthenticateResponse(new User(originalUser.getUsername(), wrongRoles, originalUser.getMetadata(), - originalUser.getFullName(), originalUser.getEmail()), response.enabled()); + originalUser.getFullName(), originalUser.getEmail()), response.enabled(), response.getAuthenticationRealm(), + response.getLookupRealm()); case 3: final Map wrongMetadata = new HashMap<>(originalUser.getMetadata()); wrongMetadata.put("wrong_string", randomAlphaOfLengthBetween(0, 4)); return new AuthenticateResponse(new User(originalUser.getUsername(), originalUser.getRoles(), wrongMetadata, - originalUser.getFullName(), originalUser.getEmail()), response.enabled()); + originalUser.getFullName(), originalUser.getEmail()), response.enabled(), response.getAuthenticationRealm(), + response.getLookupRealm()); case 4: return new AuthenticateResponse(new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(), - originalUser.getFullName() + "wrong", originalUser.getEmail()), response.enabled()); + originalUser.getFullName() + "wrong", originalUser.getEmail()), response.enabled(), + response.getAuthenticationRealm(), response.getLookupRealm()); case 5: return new AuthenticateResponse(new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(), - originalUser.getFullName(), originalUser.getEmail() + "wrong"), response.enabled()); + originalUser.getFullName(), originalUser.getEmail() + "wrong"), response.enabled(), + response.getAuthenticationRealm(), response.getLookupRealm()); case 6: return new AuthenticateResponse(new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(), - originalUser.getFullName(), originalUser.getEmail()), !response.enabled()); + originalUser.getFullName(), originalUser.getEmail()), !response.enabled(), response.getAuthenticationRealm(), + response.getLookupRealm()); + case 7: + return new AuthenticateResponse(new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(), + originalUser.getFullName(), originalUser.getEmail()), response.enabled(), response.getAuthenticationRealm(), + new AuthenticateResponse.RealmInfo(randomAlphaOfLength(5), randomAlphaOfLength(5))); + case 8: + return new AuthenticateResponse(new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(), + originalUser.getFullName(), originalUser.getEmail()), response.enabled(), + new AuthenticateResponse.RealmInfo(randomAlphaOfLength(5), randomAlphaOfLength(5)), response.getLookupRealm()); } throw new IllegalStateException("Bad random number"); } diff --git a/docs/java-rest/high-level/security/authenticate.asciidoc b/docs/java-rest/high-level/security/authenticate.asciidoc index e50c64bf9d0f5..4d4467a03b4d2 100644 --- a/docs/java-rest/high-level/security/authenticate.asciidoc +++ b/docs/java-rest/high-level/security/authenticate.asciidoc @@ -24,10 +24,14 @@ This method does not require a request object. The client waits for the [id="{upid}-{api}-response"] ==== Response -The returned +{response}+ contains two fields. Firstly, the `user` field +The returned +{response}+ contains four fields. The `user` field , accessed with `getUser`, contains all the information about this -authenticated user. The other field, `enabled`, tells if this user is actually -usable or has been temporalily deactivated. +authenticated user. The field `enabled`, tells if this user is actually +usable or has been temporarily deactivated. The field `authentication_realm`, +accessed with `getAuthenticationRealm` contains the name and type of the +Realm that has authenticated the user and the field `lookup_realm`, +accessed with `getLookupRealm` contains the name and type of the Realm where +the user information were retrieved from. ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- @@ -36,6 +40,10 @@ include-tagged::{doc-tests-file}[{api}-response] <1> `getUser` retrieves the `User` instance containing the information, see {javadoc-client}/security/user/User.html. <2> `enabled` tells if this user is usable or is deactivated. +<3> `getAuthenticationRealm().getName()` retrieves the name of the realm that authenticated the user. +<4> `getAuthenticationRealm().getType()` retrieves the type of the realm that authenticated the user. +<5> `getLookupRealm().getName()` retrieves the name of the realm from where the user information is looked up. +<6> `getLookupRealm().getType()` retrieves the type of the realm from where the user information is looked up. [id="{upid}-{api}-async"] ==== Asynchronous Execution diff --git a/x-pack/docs/en/rest-api/security/authenticate.asciidoc b/x-pack/docs/en/rest-api/security/authenticate.asciidoc index ab259762332f9..1975a9dde790b 100644 --- a/x-pack/docs/en/rest-api/security/authenticate.asciidoc +++ b/x-pack/docs/en/rest-api/security/authenticate.asciidoc @@ -13,8 +13,8 @@ authenticate a user and retrieve information about the authenticated user. ==== Description -A successful call returns a JSON structure that shows what roles are assigned -to the user as well as any assigned metadata. +A successful call returns a JSON structure that shows user information such as their username, the roles that are +assigned to the user, any assigned metadata, and information about the realms that authenticated and authorized the user. If the user cannot be authenticated, this API returns a 401 status code. @@ -41,7 +41,15 @@ The following example output provides information about the "rdeniro" user: "full_name": null, "email": null, "metadata": { }, - "enabled": true + "enabled": true, + "authentication_realm": { + "name" : "default_file", + "type" : "file" + }, + "lookup_realm": { + "name" : "default_file", + "type" : "file" + } } -------------------------------------------------- // TESTRESPONSE[s/"rdeniro"/"$body.username"/] diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/user/AuthenticateResponse.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/user/AuthenticateResponse.java index 0cf7ace1103d0..45a99265b11c9 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/user/AuthenticateResponse.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/user/AuthenticateResponse.java @@ -5,36 +5,49 @@ */ package org.elasticsearch.xpack.core.security.action.user; +import org.elasticsearch.Version; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.core.security.authc.Authentication; import org.elasticsearch.xpack.core.security.user.User; import java.io.IOException; public class AuthenticateResponse extends ActionResponse { - private User user; + private Authentication authentication; public AuthenticateResponse() {} - public AuthenticateResponse(User user) { - this.user = user; + public AuthenticateResponse(Authentication authentication){ + this.authentication = authentication; } - public User user() { - return user; + public Authentication authentication() { + return authentication; } @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); - User.writeTo(user, out); + if (out.getVersion().before(Version.V_7_0_0)) { + User.writeTo(authentication.getUser(), out); + } else { + authentication.writeTo(out); + } } @Override public void readFrom(StreamInput in) throws IOException { super.readFrom(in); - user = User.readFrom(in); + if (in.getVersion().before(Version.V_7_0_0)) { + final User user = User.readFrom(in); + final Authentication.RealmRef unknownRealm = new Authentication.RealmRef("__unknown", "__unknown", "__unknown"); + authentication = new Authentication(user, unknownRealm, unknownRealm); + } else { + authentication = new Authentication(in); + } } + } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java index 161d9d449990f..b9dbe0a948ff2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java @@ -11,6 +11,8 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.security.user.InternalUserSerializationHelper; import org.elasticsearch.xpack.core.security.user.User; @@ -20,7 +22,7 @@ // TODO(hub-cap) Clean this up after moving User over - This class can re-inherit its field AUTHENTICATION_KEY in AuthenticationField. // That interface can be removed -public class Authentication { +public class Authentication implements ToXContentObject { private final User user; private final RealmRef authenticatedBy; @@ -163,6 +165,31 @@ public int hashCode() { return result; } + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(User.Fields.USERNAME.getPreferredName(), user.principal()); + builder.array(User.Fields.ROLES.getPreferredName(), user.roles()); + builder.field(User.Fields.FULL_NAME.getPreferredName(), user.fullName()); + builder.field(User.Fields.EMAIL.getPreferredName(), user.email()); + builder.field(User.Fields.METADATA.getPreferredName(), user.metadata()); + builder.field(User.Fields.ENABLED.getPreferredName(), user.enabled()); + builder.startObject(User.Fields.AUTHENTICATION_REALM.getPreferredName()); + builder.field(User.Fields.REALM_NAME.getPreferredName(), getAuthenticatedBy().getName()); + builder.field(User.Fields.REALM_TYPE.getPreferredName(), getAuthenticatedBy().getType()); + builder.endObject(); + builder.startObject(User.Fields.LOOKUP_REALM.getPreferredName()); + if (getLookedUpBy() != null) { + builder.field(User.Fields.REALM_NAME.getPreferredName(), getLookedUpBy().getName()); + builder.field(User.Fields.REALM_TYPE.getPreferredName(), getLookedUpBy().getType()); + } else { + builder.field(User.Fields.REALM_NAME.getPreferredName(), getAuthenticatedBy().getName()); + builder.field(User.Fields.REALM_TYPE.getPreferredName(), getAuthenticatedBy().getType()); + } + builder.endObject(); + return builder.endObject(); + } + public static class RealmRef { private final String nodeName; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/User.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/User.java index 028b14f882aab..e9bca56dee126 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/User.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/User.java @@ -230,6 +230,10 @@ public interface Fields { ParseField METADATA = new ParseField("metadata"); ParseField ENABLED = new ParseField("enabled"); ParseField TYPE = new ParseField("type"); + ParseField AUTHENTICATION_REALM = new ParseField("authentication_realm"); + ParseField LOOKUP_REALM = new ParseField("lookup_realm"); + ParseField REALM_TYPE = new ParseField("type"); + ParseField REALM_NAME = new ParseField("name"); } } 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 a213eefe8efe6..f1697bca0ab22 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 @@ -16,6 +16,7 @@ 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.SystemUser; import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.core.security.user.XPackUser; @@ -34,7 +35,8 @@ public TransportAuthenticateAction(TransportService transportService, ActionFilt @Override protected void doExecute(Task task, AuthenticateRequest request, ActionListener listener) { - final User runAsUser = securityContext.getUser(); + final Authentication authentication = securityContext.getAuthentication(); + final User runAsUser = authentication == null ? null : authentication.getUser(); final User authUser = runAsUser == null ? null : runAsUser.authenticatedUser(); if (authUser == null) { listener.onFailure(new ElasticsearchSecurityException("did not find an authenticated user")); @@ -43,7 +45,7 @@ protected void doExecute(Task task, AuthenticateRequest request, ActionListener< } else if (SystemUser.is(runAsUser) || XPackUser.is(runAsUser)) { listener.onFailure(new IllegalArgumentException("user [" + runAsUser.principal() + "] is internal")); } else { - listener.onResponse(new AuthenticateResponse(runAsUser)); + listener.onResponse(new AuthenticateResponse(authentication)); } } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateAction.java index b280b3a89a204..033066b7c159d 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateAction.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateAction.java @@ -54,7 +54,7 @@ public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient c new RestBuilderListener(channel) { @Override public RestResponse buildResponse(AuthenticateResponse authenticateResponse, XContentBuilder builder) throws Exception { - authenticateResponse.user().toXContent(builder, ToXContent.EMPTY_PARAMS); + authenticateResponse.authentication().toXContent(builder, ToXContent.EMPTY_PARAMS); return new BytesRestResponse(RestStatus.OK, builder); } }); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportAuthenticateActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportAuthenticateActionTests.java index 5ba8a18dacf3f..135181d09f557 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportAuthenticateActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportAuthenticateActionTests.java @@ -16,6 +16,7 @@ import org.elasticsearch.xpack.core.security.SecurityContext; 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.ElasticUser; import org.elasticsearch.xpack.core.security.user.KibanaUser; import org.elasticsearch.xpack.core.security.user.SystemUser; @@ -37,7 +38,9 @@ public class TransportAuthenticateActionTests extends ESTestCase { public void testInternalUser() { SecurityContext securityContext = mock(SecurityContext.class); - when(securityContext.getUser()).thenReturn(randomFrom(SystemUser.INSTANCE, XPackUser.INSTANCE)); + final Authentication authentication = new Authentication(randomFrom(SystemUser.INSTANCE, XPackUser.INSTANCE), + new Authentication.RealmRef("native", "default_native", "node1"), null); + when(securityContext.getAuthentication()).thenReturn(authentication); TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null, TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet()); TransportAuthenticateAction action = new TransportAuthenticateAction(transportService, @@ -88,9 +91,12 @@ public void onFailure(Exception e) { assertThat(throwableRef.get().getMessage(), containsString("did not find an authenticated user")); } - public void testValidUser() { + public void testValidAuthentication(){ final User user = randomFrom(new ElasticUser(true), new KibanaUser(true), new User("joe")); + final Authentication authentication = new Authentication(user, new Authentication.RealmRef("native_realm", "native", "node1"), + null); SecurityContext securityContext = mock(SecurityContext.class); + when(securityContext.getAuthentication()).thenReturn(authentication); when(securityContext.getUser()).thenReturn(user); TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null, TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet()); @@ -112,7 +118,7 @@ public void onFailure(Exception e) { }); assertThat(responseRef.get(), notNullValue()); - assertThat(responseRef.get().user(), sameInstance(user)); + assertThat(responseRef.get().authentication(), sameInstance(authentication)); assertThat(throwableRef.get(), nullValue()); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java index e6cc2dcccdfaa..0b000dd07dace 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java @@ -322,7 +322,7 @@ public void testCreateThenRefreshAsDifferentUser() { request.username(SecuritySettingsSource.TEST_SUPERUSER); client.execute(AuthenticateAction.INSTANCE, request, authFuture); AuthenticateResponse response = authFuture.actionGet(); - assertEquals(SecuritySettingsSource.TEST_SUPERUSER, response.user().principal()); + assertEquals(SecuritySettingsSource.TEST_SUPERUSER, response.authentication().getUser().principal()); authFuture = new PlainActionFuture<>(); request = new AuthenticateRequest(); @@ -330,7 +330,7 @@ public void testCreateThenRefreshAsDifferentUser() { client.filterWithHeader(Collections.singletonMap("Authorization", "Bearer " + createTokenResponse.getTokenString())) .execute(AuthenticateAction.INSTANCE, request, authFuture); response = authFuture.actionGet(); - assertEquals(SecuritySettingsSource.TEST_USER_NAME, response.user().principal()); + assertEquals(SecuritySettingsSource.TEST_USER_NAME, response.authentication().getUser().principal()); authFuture = new PlainActionFuture<>(); request = new AuthenticateRequest(); @@ -338,7 +338,7 @@ public void testCreateThenRefreshAsDifferentUser() { client.filterWithHeader(Collections.singletonMap("Authorization", "Bearer " + refreshResponse.getTokenString())) .execute(AuthenticateAction.INSTANCE, request, authFuture); response = authFuture.actionGet(); - assertEquals(SecuritySettingsSource.TEST_USER_NAME, response.user().principal()); + assertEquals(SecuritySettingsSource.TEST_USER_NAME, response.authentication().getUser().principal()); } public void testClientCredentialsGrant() throws Exception { @@ -357,7 +357,7 @@ public void testClientCredentialsGrant() throws Exception { client.filterWithHeader(Collections.singletonMap("Authorization", "Bearer " + createTokenResponse.getTokenString())) .execute(AuthenticateAction.INSTANCE, request, authFuture); AuthenticateResponse response = authFuture.get(); - assertEquals(SecuritySettingsSource.TEST_SUPERUSER, response.user().principal()); + assertEquals(SecuritySettingsSource.TEST_SUPERUSER, response.authentication().getUser().principal()); // invalidate PlainActionFuture invalidateResponseFuture = new PlainActionFuture<>(); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmIntegTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmIntegTests.java index c2a7ea495a18b..d8d3a3f3ccb24 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmIntegTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmIntegTests.java @@ -64,6 +64,7 @@ import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_SECURITY_INDEX; import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.mockito.Mockito.mock; @@ -576,7 +577,10 @@ public void testOperationsOnReservedUsers() throws Exception { basicAuthHeaderValue(username, getReservedPassword()))) .execute(AuthenticateAction.INSTANCE, new AuthenticateRequest(username)) .get(); - assertThat(authenticateResponse.user().principal(), is(username)); + assertThat(authenticateResponse.authentication().getUser().principal(), is(username)); + assertThat(authenticateResponse.authentication().getAuthenticatedBy().getName(), equalTo("reserved")); + assertThat(authenticateResponse.authentication().getAuthenticatedBy().getType(), equalTo("reserved")); + assertNull(authenticateResponse.authentication().getLookedUpBy()); } public void testOperationsOnReservedRoles() throws Exception { 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 13a124e4bdc96..a6a304df12378 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 @@ -58,8 +58,13 @@ public void testAuthenticateApi() throws Exception { options.addHeader("Authorization", basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME, new SecureString(SecuritySettingsSourceField.TEST_PASSWORD.toCharArray()))); request.setOptions(options); - ObjectPath objectPath = ObjectPath.createFromResponse(getRestClient().performRequest(request)); + Response a = getRestClient().performRequest(request); + ObjectPath objectPath = ObjectPath.createFromResponse(a); assertThat(objectPath.evaluate("username").toString(), equalTo(SecuritySettingsSource.TEST_USER_NAME)); + assertThat(objectPath.evaluate("authentication_realm.name").toString(), equalTo("file")); + assertThat(objectPath.evaluate("authentication_realm.type").toString(), equalTo("file")); + assertThat(objectPath.evaluate("lookup_realm.name").toString(), equalTo("file")); + assertThat(objectPath.evaluate("lookup_realm.type").toString(), equalTo("file")); List roles = objectPath.evaluate("roles"); assertThat(roles.size(), is(1)); assertThat(roles, contains(SecuritySettingsSource.TEST_ROLE)); diff --git a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRunAsIT.java b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRunAsIT.java index 2aabe2a464b94..46f89e40622a5 100644 --- a/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRunAsIT.java +++ b/x-pack/qa/third-party/active-directory/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRunAsIT.java @@ -65,7 +65,7 @@ public void testRunAs() throws Exception { final AuthenticateRequest request = new AuthenticateRequest(avenger); final ActionFuture future = runAsClient(avenger).execute(AuthenticateAction.INSTANCE, request); final AuthenticateResponse response = future.get(30, TimeUnit.SECONDS); - assertThat(response.user().principal(), Matchers.equalTo(avenger)); + assertThat(response.authentication().getUser().principal(), Matchers.equalTo(avenger)); } protected Client runAsClient(String user) {