Skip to content

Commit 1bb2a15

Browse files
authored
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 4dacfa9 commit 1bb2a15

File tree

2 files changed

+19
-8
lines changed

2 files changed

+19
-8
lines changed

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

Lines changed: 4 additions & 3 deletions
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;
@@ -294,9 +295,9 @@ private void consumeToken(AuthenticationToken token) {
294295
}
295296
};
296297
final IteratingActionListener<User, Realm> authenticatingListener =
297-
new IteratingActionListener<>(ActionListener.wrap(
298-
(user) -> consumeUser(user, messages),
299-
(e) -> listener.onFailure(request.exceptionProcessingRequest(e, token))),
298+
new IteratingActionListener<>(ContextPreservingActionListener.wrapPreservingContext(ActionListener.wrap(
299+
(user) -> consumeUser(user, messages),
300+
(e) -> listener.onFailure(request.exceptionProcessingRequest(e, token))), threadContext),
300301
realmAuthenticatingConsumer, realmsList, threadContext);
301302
try {
302303
authenticatingListener.run();

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ public void testRealmLookupThrowingExceptionRest() throws Exception {
716716
when(secondRealm.supports(token)).thenReturn(true);
717717
mockAuthenticate(secondRealm, token, new User("lookup user", new String[]{"user"}));
718718
mockRealmLookupReturnsNull(firstRealm, "run_as");
719-
doThrow(authenticationError("realm doesn't want to " + "lookup"))
719+
doThrow(authenticationError("realm doesn't want to lookup"))
720720
.when(secondRealm).lookupUser(eq("run_as"), any(ActionListener.class));
721721

722722
try {
@@ -1029,12 +1029,22 @@ void assertThreadContextContainsAuthentication(Authentication authentication) th
10291029

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

0 commit comments

Comments
 (0)