diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/AuthenticationResult.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/AuthenticationResult.java
index 0f073ef4ae398..355a96dd19c39 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/AuthenticationResult.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/AuthenticationResult.java
@@ -8,6 +8,8 @@
import org.elasticsearch.common.Nullable;
import org.elasticsearch.xpack.core.security.user.User;
+import java.util.Collections;
+import java.util.Map;
import java.util.Objects;
/**
@@ -21,7 +23,9 @@
*
*/
public final class AuthenticationResult {
- private static final AuthenticationResult NOT_HANDLED = new AuthenticationResult(Status.CONTINUE, null, null, null);
+ private static final AuthenticationResult NOT_HANDLED = new AuthenticationResult(Status.CONTINUE, null, null, null, null);
+
+ public static String THREAD_CONTEXT_KEY = "_xpack_security_auth_result";
public enum Status {
SUCCESS,
@@ -33,12 +37,15 @@ public enum Status {
private final User user;
private final String message;
private final Exception exception;
+ private final Map metadata;
- private AuthenticationResult(Status status, @Nullable User user, @Nullable String message, @Nullable Exception exception) {
+ private AuthenticationResult(Status status, @Nullable User user, @Nullable String message, @Nullable Exception exception,
+ @Nullable Map metadata) {
this.status = status;
this.user = user;
this.message = message;
this.exception = exception;
+ this.metadata = metadata == null ? Collections.emptyMap() : Collections.unmodifiableMap(metadata);
}
public Status getStatus() {
@@ -57,6 +64,10 @@ public Exception getException() {
return exception;
}
+ public Map getMetadata() {
+ return metadata;
+ }
+
/**
* Creates an {@code AuthenticationResult} that indicates that the supplied {@link User}
* has been successfully authenticated.
@@ -69,7 +80,16 @@ public Exception getException() {
*/
public static AuthenticationResult success(User user) {
Objects.requireNonNull(user);
- return new AuthenticationResult(Status.SUCCESS, user, null, null);
+ return success(user, null);
+ }
+
+ /**
+ * Creates a successful result, with optional metadata
+ *
+ * @see #success(User)
+ */
+ public static AuthenticationResult success(User user, @Nullable Map metadata) {
+ return new AuthenticationResult(Status.SUCCESS, user, null, null, metadata);
}
/**
@@ -96,7 +116,7 @@ public static AuthenticationResult notHandled() {
*/
public static AuthenticationResult unsuccessful(String message, @Nullable Exception cause) {
Objects.requireNonNull(message);
- return new AuthenticationResult(Status.CONTINUE, null, message, cause);
+ return new AuthenticationResult(Status.CONTINUE, null, message, cause, null);
}
/**
@@ -110,7 +130,7 @@ public static AuthenticationResult unsuccessful(String message, @Nullable Except
*
*/
public static AuthenticationResult terminate(String message, @Nullable Exception cause) {
- return new AuthenticationResult(Status.TERMINATE, null, message, cause);
+ return new AuthenticationResult(Status.TERMINATE, null, message, cause, null);
}
public boolean isAuthenticated() {
diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/saml/TransportSamlAuthenticateAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/saml/TransportSamlAuthenticateAction.java
index 9dd18be510f54..13fbe248bdc48 100644
--- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/saml/TransportSamlAuthenticateAction.java
+++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/saml/TransportSamlAuthenticateAction.java
@@ -22,6 +22,7 @@
import org.elasticsearch.xpack.core.security.action.saml.SamlAuthenticateRequest;
import org.elasticsearch.xpack.core.security.action.saml.SamlAuthenticateResponse;
import org.elasticsearch.xpack.core.security.authc.Authentication;
+import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.TokenService;
import org.elasticsearch.xpack.security.authc.saml.SamlRealm;
@@ -54,7 +55,12 @@ protected void doExecute(Task task, SamlAuthenticateRequest request, ActionListe
Authentication originatingAuthentication = Authentication.getAuthentication(threadContext);
try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
authenticationService.authenticate(SamlAuthenticateAction.NAME, request, saml, ActionListener.wrap(authentication -> {
- final Map tokenMeta = threadContext.getTransient(SamlRealm.CONTEXT_TOKEN_DATA);
+ AuthenticationResult result = threadContext.getTransient(AuthenticationResult.THREAD_CONTEXT_KEY);
+ if (result == null) {
+ listener.onFailure(new IllegalStateException("Cannot find AuthenticationResult on thread context"));
+ return;
+ }
+ final Map tokenMeta = (Map) result.getMetadata().get(SamlRealm.CONTEXT_TOKEN_DATA);
tokenService.createUserToken(authentication, originatingAuthentication,
ActionListener.wrap(tuple -> {
final String tokenString = tokenService.getUserTokenString(tuple.v1());
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 037ed11ac1df2..d5242fab45fac 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
@@ -140,6 +140,7 @@ class Authenticator {
private RealmRef authenticatedBy = null;
private RealmRef lookedupBy = null;
private AuthenticationToken authenticationToken = null;
+ private AuthenticationResult authenticationResult = null;
Authenticator(RestRequest request, ActionListener listener) {
this(new AuditableRestRequest(auditTrail, failureHandler, threadContext, request), null, listener);
@@ -267,6 +268,7 @@ private void consumeToken(AuthenticationToken token) {
if (result.getStatus() == AuthenticationResult.Status.SUCCESS) {
// user was authenticated, populate the authenticated by information
authenticatedBy = new RealmRef(realm.name(), realm.type(), nodeName);
+ authenticationResult = result;
userListener.onResponse(result.getUser());
} else {
// the user was not authenticated, call this so we can audit the correct event
@@ -360,6 +362,7 @@ private void consumeUser(User user, Map> message
});
listener.onFailure(request.authenticationFailed(authenticationToken));
} else {
+ threadContext.putTransient(AuthenticationResult.THREAD_CONTEXT_KEY, authenticationResult);
if (runAsEnabled) {
final String runAsUsername = threadContext.getHeader(AuthenticationServiceField.RUN_AS_USER_HEADER);
if (runAsUsername != null && runAsUsername.isEmpty() == false) {
diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlRealm.java
index 36ad208df2b33..7c982e6b1b396 100644
--- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlRealm.java
+++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlRealm.java
@@ -426,7 +426,10 @@ private void buildUser(SamlAttributes attributes, ActionListener tokenMetadata = createTokenMetadata(attributes.name(), attributes.session());
ActionListener wrappedListener = ActionListener.wrap(auth -> {
if (auth.isAuthenticated()) {
- config.threadContext().putTransient(CONTEXT_TOKEN_DATA, tokenMetadata);
+ // Add the SAML token details as metadata on the authentication
+ Map metadata = new HashMap<>(auth.getMetadata());
+ metadata.put(CONTEXT_TOKEN_DATA, tokenMetadata);
+ auth = AuthenticationResult.success(auth.getUser(), metadata);
}
baseListener.onResponse(auth);
}, baseListener::onFailure);