Skip to content

Commit c7854e4

Browse files
committed
Preserve thread context during authentication. (#34290)
There may be values in the thread context that ought to be preseved for later use, even if one or more realms perform asynchronous authentication. This commit changes the AuthenticationService to wrap the potentially asynchronous calls in a ContextPreservingActionListener that retains the original thread context for the authentication.
1 parent db99325 commit c7854e4

File tree

2 files changed

+20
-9
lines changed

2 files changed

+20
-9
lines changed

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.apache.logging.log4j.util.Supplier;
1010
import org.elasticsearch.ElasticsearchSecurityException;
1111
import org.elasticsearch.action.ActionListener;
12+
import org.elasticsearch.action.support.ContextPreservingActionListener;
1213
import org.elasticsearch.common.Nullable;
1314
import org.elasticsearch.common.collect.Tuple;
1415
import org.elasticsearch.common.component.AbstractComponent;
@@ -292,9 +293,9 @@ private void consumeToken(AuthenticationToken token) {
292293
}
293294
};
294295
final IteratingActionListener<User, Realm> authenticatingListener =
295-
new IteratingActionListener<>(ActionListener.wrap(
296-
(user) -> consumeUser(user, messages),
297-
(e) -> listener.onFailure(request.exceptionProcessingRequest(e, token))),
296+
new IteratingActionListener<>(ContextPreservingActionListener.wrapPreservingContext(ActionListener.wrap(
297+
(user) -> consumeUser(user, messages),
298+
(e) -> listener.onFailure(request.exceptionProcessingRequest(e, token))), threadContext),
298299
realmAuthenticatingConsumer, realmsList, threadContext);
299300
try {
300301
authenticatingListener.run();

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java

+16-6
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ public void testRealmLookupThrowingExceptionRest() throws Exception {
718718
when(secondRealm.supports(token)).thenReturn(true);
719719
mockAuthenticate(secondRealm, token, new User("lookup user", new String[]{"user"}));
720720
mockRealmLookupReturnsNull(firstRealm, "run_as");
721-
doThrow(authenticationError("realm doesn't want to " + "lookup"))
721+
doThrow(authenticationError("realm doesn't want to lookup"))
722722
.when(secondRealm).lookupUser(eq("run_as"), any(ActionListener.class));
723723

724724
try {
@@ -1027,12 +1027,22 @@ void assertThreadContextContainsAuthentication(Authentication authentication) th
10271027
}
10281028

10291029
private void mockAuthenticate(Realm realm, AuthenticationToken token, User user) {
1030-
doAnswer((i) -> {
1031-
ActionListener listener = (ActionListener) i.getArguments()[1];
1032-
if (user == null) {
1033-
listener.onResponse(AuthenticationResult.notHandled());
1030+
final boolean separateThread = randomBoolean();
1031+
doAnswer(i -> {
1032+
ActionListener<AuthenticationResult> listener = (ActionListener<AuthenticationResult>) i.getArguments()[1];
1033+
Runnable run = () -> {
1034+
if (user == null) {
1035+
listener.onResponse(AuthenticationResult.notHandled());
1036+
} else {
1037+
listener.onResponse(AuthenticationResult.success(user));
1038+
}
1039+
};
1040+
if (separateThread) {
1041+
final Thread thread = new Thread(run);
1042+
thread.start();
1043+
thread.join();
10341044
} else {
1035-
listener.onResponse(AuthenticationResult.success(user));
1045+
run.run();
10361046
}
10371047
return null;
10381048
}).when(realm).authenticate(eq(token), any(ActionListener.class));

0 commit comments

Comments
 (0)