Revert "Support concurrent refresh of refresh tokens (#39559)"
This reverts commit e2599214e0
.
This commit is contained in:
parent
39a401b827
commit
0c6b7cfb77
|
@ -7,7 +7,6 @@
|
|||
package org.elasticsearch.xpack.core.security.authc.support;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
@ -33,9 +32,10 @@ public class TokensInvalidationResult implements ToXContentObject, Writeable {
|
|||
private final List<String> invalidatedTokens;
|
||||
private final List<String> previouslyInvalidatedTokens;
|
||||
private final List<ElasticsearchException> errors;
|
||||
private final int attemptCount;
|
||||
|
||||
public TokensInvalidationResult(List<String> invalidatedTokens, List<String> previouslyInvalidatedTokens,
|
||||
@Nullable List<ElasticsearchException> errors) {
|
||||
@Nullable List<ElasticsearchException> errors, int attemptCount) {
|
||||
Objects.requireNonNull(invalidatedTokens, "invalidated_tokens must be provided");
|
||||
this.invalidatedTokens = invalidatedTokens;
|
||||
Objects.requireNonNull(previouslyInvalidatedTokens, "previously_invalidated_tokens must be provided");
|
||||
|
@ -45,19 +45,18 @@ public class TokensInvalidationResult implements ToXContentObject, Writeable {
|
|||
} else {
|
||||
this.errors = Collections.emptyList();
|
||||
}
|
||||
this.attemptCount = attemptCount;
|
||||
}
|
||||
|
||||
public TokensInvalidationResult(StreamInput in) throws IOException {
|
||||
this.invalidatedTokens = in.readStringList();
|
||||
this.previouslyInvalidatedTokens = in.readStringList();
|
||||
this.errors = in.readList(StreamInput::readException);
|
||||
if (in.getVersion().before(Version.V_7_1_0)) {
|
||||
in.readVInt();
|
||||
}
|
||||
this.attemptCount = in.readVInt();
|
||||
}
|
||||
|
||||
public static TokensInvalidationResult emptyResult() {
|
||||
return new TokensInvalidationResult(Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
|
||||
return new TokensInvalidationResult(Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,6 +72,10 @@ public class TokensInvalidationResult implements ToXContentObject, Writeable {
|
|||
return errors;
|
||||
}
|
||||
|
||||
public int getAttemptCount() {
|
||||
return attemptCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject()
|
||||
|
@ -97,8 +100,6 @@ public class TokensInvalidationResult implements ToXContentObject, Writeable {
|
|||
out.writeStringCollection(invalidatedTokens);
|
||||
out.writeStringCollection(previouslyInvalidatedTokens);
|
||||
out.writeCollection(errors, StreamOutput::writeException);
|
||||
if (out.getVersion().before(Version.V_7_1_0)) {
|
||||
out.writeVInt(5);
|
||||
}
|
||||
out.writeVInt(attemptCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,13 +199,6 @@
|
|||
"refreshed" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
"refresh_time": {
|
||||
"type": "date",
|
||||
"format": "epoch_millis"
|
||||
},
|
||||
"superseded_by": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"invalidated" : {
|
||||
"type" : "boolean"
|
||||
},
|
||||
|
|
|
@ -29,7 +29,8 @@ public class InvalidateTokenResponseTests extends ESTestCase {
|
|||
TokensInvalidationResult result = new TokensInvalidationResult(Arrays.asList(generateRandomStringArray(20, 15, false)),
|
||||
Arrays.asList(generateRandomStringArray(20, 15, false)),
|
||||
Arrays.asList(new ElasticsearchException("foo", new IllegalArgumentException("this is an error message")),
|
||||
new ElasticsearchException("bar", new IllegalArgumentException("this is an error message2"))));
|
||||
new ElasticsearchException("bar", new IllegalArgumentException("this is an error message2"))),
|
||||
randomIntBetween(0, 5));
|
||||
InvalidateTokenResponse response = new InvalidateTokenResponse(result);
|
||||
try (BytesStreamOutput output = new BytesStreamOutput()) {
|
||||
response.writeTo(output);
|
||||
|
@ -46,7 +47,8 @@ public class InvalidateTokenResponseTests extends ESTestCase {
|
|||
}
|
||||
|
||||
result = new TokensInvalidationResult(Arrays.asList(generateRandomStringArray(20, 15, false)),
|
||||
Arrays.asList(generateRandomStringArray(20, 15, false)), Collections.emptyList());
|
||||
Arrays.asList(generateRandomStringArray(20, 15, false)),
|
||||
Collections.emptyList(), randomIntBetween(0, 5));
|
||||
response = new InvalidateTokenResponse(result);
|
||||
try (BytesStreamOutput output = new BytesStreamOutput()) {
|
||||
response.writeTo(output);
|
||||
|
@ -66,7 +68,8 @@ public class InvalidateTokenResponseTests extends ESTestCase {
|
|||
List previouslyInvalidatedTokens = Arrays.asList(generateRandomStringArray(20, 15, false));
|
||||
TokensInvalidationResult result = new TokensInvalidationResult(invalidatedTokens, previouslyInvalidatedTokens,
|
||||
Arrays.asList(new ElasticsearchException("foo", new IllegalArgumentException("this is an error message")),
|
||||
new ElasticsearchException("bar", new IllegalArgumentException("this is an error message2"))));
|
||||
new ElasticsearchException("bar", new IllegalArgumentException("this is an error message2"))),
|
||||
randomIntBetween(0, 5));
|
||||
InvalidateTokenResponse response = new InvalidateTokenResponse(result);
|
||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
|
|
|
@ -63,7 +63,7 @@ public final class TransportSamlAuthenticateAction extends HandledTransportActio
|
|||
final Map<String, Object> tokenMeta = (Map<String, Object>) result.getMetadata().get(SamlRealm.CONTEXT_TOKEN_DATA);
|
||||
tokenService.createUserToken(authentication, originatingAuthentication,
|
||||
ActionListener.wrap(tuple -> {
|
||||
final String tokenString = tokenService.getAccessTokenAsString(tuple.v1());
|
||||
final String tokenString = tokenService.getUserTokenString(tuple.v1());
|
||||
final TimeValue expiresIn = tokenService.getExpirationDelay();
|
||||
listener.onResponse(
|
||||
new SamlAuthenticateResponse(authentication.getUser().principal(), tokenString, tuple.v2(), expiresIn));
|
||||
|
|
|
@ -89,7 +89,7 @@ public final class TransportCreateTokenAction extends HandledTransportAction<Cre
|
|||
boolean includeRefreshToken, ActionListener<CreateTokenResponse> listener) {
|
||||
try {
|
||||
tokenService.createUserToken(authentication, originatingAuth, ActionListener.wrap(tuple -> {
|
||||
final String tokenStr = tokenService.getAccessTokenAsString(tuple.v1());
|
||||
final String tokenStr = tokenService.getUserTokenString(tuple.v1());
|
||||
final String scope = getResponseScopeValue(request.getScope());
|
||||
|
||||
final CreateTokenResponse response =
|
||||
|
|
|
@ -31,7 +31,7 @@ public class TransportRefreshTokenAction extends HandledTransportAction<CreateTo
|
|||
@Override
|
||||
protected void doExecute(Task task, CreateTokenRequest request, ActionListener<CreateTokenResponse> listener) {
|
||||
tokenService.refreshToken(request.getRefreshToken(), ActionListener.wrap(tuple -> {
|
||||
final String tokenStr = tokenService.getAccessTokenAsString(tuple.v1());
|
||||
final String tokenStr = tokenService.getUserTokenString(tuple.v1());
|
||||
final String scope = getResponseScopeValue(request.getScope());
|
||||
|
||||
final CreateTokenResponse response =
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -242,7 +242,7 @@ public class TransportSamlLogoutActionTests extends SamlTestCase {
|
|||
tokenService.createUserToken(authentication, authentication, future, tokenMetaData, true);
|
||||
final UserToken userToken = future.actionGet().v1();
|
||||
mockGetTokenFromId(userToken, false, client);
|
||||
final String tokenString = tokenService.getAccessTokenAsString(userToken);
|
||||
final String tokenString = tokenService.getUserTokenString(userToken);
|
||||
|
||||
final SamlLogoutRequest request = new SamlLogoutRequest();
|
||||
request.setToken(tokenString);
|
||||
|
|
|
@ -1109,7 +1109,7 @@ public class AuthenticationServiceTests extends ESTestCase {
|
|||
Authentication originatingAuth = new Authentication(new User("creator"), new RealmRef("test", "test", "test"), null);
|
||||
tokenService.createUserToken(expected, originatingAuth, tokenFuture, Collections.emptyMap(), true);
|
||||
}
|
||||
String token = tokenService.getAccessTokenAsString(tokenFuture.get().v1());
|
||||
String token = tokenService.getUserTokenString(tokenFuture.get().v1());
|
||||
when(client.prepareMultiGet()).thenReturn(new MultiGetRequestBuilder(client, MultiGetAction.INSTANCE));
|
||||
mockGetTokenFromId(tokenFuture.get().v1(), false, client);
|
||||
when(securityIndex.isAvailable()).thenReturn(true);
|
||||
|
@ -1192,7 +1192,7 @@ public class AuthenticationServiceTests extends ESTestCase {
|
|||
Authentication originatingAuth = new Authentication(new User("creator"), new RealmRef("test", "test", "test"), null);
|
||||
tokenService.createUserToken(expected, originatingAuth, tokenFuture, Collections.emptyMap(), true);
|
||||
}
|
||||
String token = tokenService.getAccessTokenAsString(tokenFuture.get().v1());
|
||||
String token = tokenService.getUserTokenString(tokenFuture.get().v1());
|
||||
mockGetTokenFromId(tokenFuture.get().v1(), true, client);
|
||||
doAnswer(invocationOnMock -> {
|
||||
((Runnable) invocationOnMock.getArguments()[1]).run();
|
||||
|
|
|
@ -5,14 +5,11 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security.authc;
|
||||
|
||||
import org.apache.directory.api.util.Strings;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.support.PlainActionFuture;
|
||||
import org.elasticsearch.action.support.WriteRequest;
|
||||
import org.elasticsearch.action.update.UpdateResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
|
@ -26,7 +23,6 @@ import org.elasticsearch.test.SecuritySettingsSource;
|
|||
import org.elasticsearch.test.SecuritySettingsSourceField;
|
||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.action.token.CreateTokenRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.token.CreateTokenResponse;
|
||||
import org.elasticsearch.xpack.core.security.action.token.InvalidateTokenRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.token.InvalidateTokenResponse;
|
||||
|
@ -42,13 +38,7 @@ import org.junit.Before;
|
|||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
@ -340,7 +330,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
|
|||
assertEquals("token has been invalidated", e.getHeader("error_description").get(0));
|
||||
}
|
||||
|
||||
public void testRefreshingMultipleTimesFails() throws Exception {
|
||||
public void testRefreshingMultipleTimes() {
|
||||
Client client = client().filterWithHeader(Collections.singletonMap("Authorization",
|
||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
|
||||
SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING)));
|
||||
|
@ -353,101 +343,12 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
|
|||
assertNotNull(createTokenResponse.getRefreshToken());
|
||||
CreateTokenResponse refreshResponse = securityClient.prepareRefreshToken(createTokenResponse.getRefreshToken()).get();
|
||||
assertNotNull(refreshResponse);
|
||||
// We now have two documents, the original(now refreshed) token doc and the new one with the new access doc
|
||||
AtomicReference<String> docId = new AtomicReference<>();
|
||||
assertBusy(() -> {
|
||||
SearchResponse searchResponse = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
|
||||
.setSource(SearchSourceBuilder.searchSource()
|
||||
.query(QueryBuilders.boolQuery()
|
||||
.must(QueryBuilders.termQuery("doc_type", "token"))
|
||||
.must(QueryBuilders.termQuery("refresh_token.refreshed", "true"))))
|
||||
.setSize(1)
|
||||
.setTerminateAfter(1)
|
||||
.get();
|
||||
assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
|
||||
docId.set(searchResponse.getHits().getAt(0).getId());
|
||||
});
|
||||
|
||||
// hack doc to modify the refresh time to 50 seconds ago so that we don't hit the lenient refresh case
|
||||
Instant refreshed = Instant.now();
|
||||
Instant aWhileAgo = refreshed.minus(50L, ChronoUnit.SECONDS);
|
||||
assertTrue(Instant.now().isAfter(aWhileAgo));
|
||||
UpdateResponse updateResponse = client.prepareUpdate(SecurityIndexManager.SECURITY_INDEX_NAME, "doc", docId.get())
|
||||
.setDoc("refresh_token", Collections.singletonMap("refresh_time", aWhileAgo.toEpochMilli()))
|
||||
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
||||
.setFetchSource("refresh_token", Strings.EMPTY_STRING)
|
||||
.get();
|
||||
assertNotNull(updateResponse);
|
||||
Map<String, Object> refreshTokenMap = (Map<String, Object>) updateResponse.getGetResult().sourceAsMap().get("refresh_token");
|
||||
assertTrue(
|
||||
Instant.ofEpochMilli((long) refreshTokenMap.get("refresh_time")).isBefore(Instant.now().minus(30L, ChronoUnit.SECONDS)));
|
||||
ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class,
|
||||
() -> securityClient.prepareRefreshToken(createTokenResponse.getRefreshToken()).get());
|
||||
assertEquals("invalid_grant", e.getMessage());
|
||||
assertEquals(RestStatus.BAD_REQUEST, e.status());
|
||||
assertEquals("token has already been refreshed more than 30 seconds in the past", e.getHeader("error_description").get(0));
|
||||
}
|
||||
|
||||
public void testRefreshingMultipleTimesWithinWindowSucceeds() throws Exception {
|
||||
Client client = client().filterWithHeader(Collections.singletonMap("Authorization",
|
||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
|
||||
SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING)));
|
||||
SecurityClient securityClient = new SecurityClient(client);
|
||||
Set<String> refreshTokens = new HashSet<>();
|
||||
Set<String> accessTokens = new HashSet<>();
|
||||
CreateTokenResponse createTokenResponse = securityClient.prepareCreateToken()
|
||||
.setGrantType("password")
|
||||
.setUsername(SecuritySettingsSource.TEST_USER_NAME)
|
||||
.setPassword(new SecureString(SecuritySettingsSourceField.TEST_PASSWORD.toCharArray()))
|
||||
.get();
|
||||
assertNotNull(createTokenResponse.getRefreshToken());
|
||||
final int numberOfProcessors = Runtime.getRuntime().availableProcessors();
|
||||
final int numberOfThreads = scaledRandomIntBetween((numberOfProcessors + 1) / 2, numberOfProcessors * 3);
|
||||
List<Thread> threads = new ArrayList<>(numberOfThreads);
|
||||
final CountDownLatch readyLatch = new CountDownLatch(numberOfThreads + 1);
|
||||
final CountDownLatch completedLatch = new CountDownLatch(numberOfThreads);
|
||||
AtomicBoolean failed = new AtomicBoolean();
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
threads.add(new Thread(() -> {
|
||||
// Each thread gets its own client so that more than one nodes will be hit
|
||||
Client threadClient = client().filterWithHeader(Collections.singletonMap("Authorization",
|
||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
|
||||
SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING)));
|
||||
SecurityClient threadSecurityClient = new SecurityClient(threadClient);
|
||||
CreateTokenRequest refreshRequest =
|
||||
threadSecurityClient.prepareRefreshToken(createTokenResponse.getRefreshToken()).request();
|
||||
readyLatch.countDown();
|
||||
try {
|
||||
readyLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
completedLatch.countDown();
|
||||
return;
|
||||
}
|
||||
threadSecurityClient.refreshToken(refreshRequest, ActionListener.wrap(result -> {
|
||||
accessTokens.add(result.getTokenString());
|
||||
refreshTokens.add(result.getRefreshToken());
|
||||
logger.info("received access token [{}] and refresh token [{}]", result.getTokenString(), result.getRefreshToken());
|
||||
completedLatch.countDown();
|
||||
}, e -> {
|
||||
failed.set(true);
|
||||
completedLatch.countDown();
|
||||
logger.error("caught exception", e);
|
||||
}));
|
||||
}));
|
||||
}
|
||||
for (Thread thread : threads) {
|
||||
thread.start();
|
||||
}
|
||||
readyLatch.countDown();
|
||||
readyLatch.await();
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
completedLatch.await();
|
||||
assertThat(failed.get(), equalTo(false));
|
||||
assertThat(accessTokens.size(), equalTo(1));
|
||||
assertThat(refreshTokens.size(), equalTo(1));
|
||||
assertEquals("token has already been refreshed", e.getHeader("error_description").get(0));
|
||||
}
|
||||
|
||||
public void testRefreshAsDifferentUser() {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package org.elasticsearch.xpack.security.authc;
|
||||
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.NoShardAvailableActionException;
|
||||
import org.elasticsearch.action.get.GetAction;
|
||||
|
@ -24,8 +23,6 @@ import org.elasticsearch.client.Client;
|
|||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.io.stream.OutputStreamStreamOutput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
|
@ -54,11 +51,7 @@ import org.junit.AfterClass;
|
|||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
@ -68,7 +61,6 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.crypto.CipherOutputStream;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import static java.time.Clock.systemUTC;
|
||||
|
@ -159,7 +151,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
authentication = token.getAuthentication();
|
||||
|
||||
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", randomFrom("Bearer ", "BEARER ", "bearer ") + tokenService.getAccessTokenAsString(token));
|
||||
requestContext.putHeader("Authorization", randomFrom("Bearer ", "BEARER ", "bearer ") + tokenService.getUserTokenString(token));
|
||||
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||
|
@ -206,7 +198,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
authentication = token.getAuthentication();
|
||||
|
||||
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, token));
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
||||
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||
|
@ -227,10 +219,10 @@ public class TokenServiceTests extends ESTestCase {
|
|||
tokenService.createUserToken(authentication, authentication, newTokenFuture, Collections.emptyMap(), true);
|
||||
final UserToken newToken = newTokenFuture.get().v1();
|
||||
assertNotNull(newToken);
|
||||
assertNotEquals(getDeprecatedAccessTokenString(tokenService, newToken), getDeprecatedAccessTokenString(tokenService, token));
|
||||
assertNotEquals(tokenService.getUserTokenString(newToken), tokenService.getUserTokenString(token));
|
||||
|
||||
requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, newToken));
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(newToken));
|
||||
mockGetTokenFromId(newToken, false);
|
||||
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
|
@ -255,7 +247,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
rotateKeys(tokenService);
|
||||
}
|
||||
TokenService otherTokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex,
|
||||
clusterService);
|
||||
clusterService);
|
||||
otherTokenService.refreshMetaData(tokenService.getTokenMetaData());
|
||||
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||
|
@ -266,7 +258,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
authentication = token.getAuthentication();
|
||||
|
||||
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, token));
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||
otherTokenService.getAndValidateToken(requestContext, future);
|
||||
|
@ -297,7 +289,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
authentication = token.getAuthentication();
|
||||
|
||||
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, token));
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
||||
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||
|
@ -324,7 +316,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
tokenService.createUserToken(authentication, authentication, newTokenFuture, Collections.emptyMap(), true);
|
||||
final UserToken newToken = newTokenFuture.get().v1();
|
||||
assertNotNull(newToken);
|
||||
assertNotEquals(getDeprecatedAccessTokenString(tokenService, newToken), getDeprecatedAccessTokenString(tokenService, token));
|
||||
assertNotEquals(tokenService.getUserTokenString(newToken), tokenService.getUserTokenString(token));
|
||||
|
||||
metaData = tokenService.pruneKeys(1);
|
||||
tokenService.refreshMetaData(metaData);
|
||||
|
@ -337,7 +329,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, newToken));
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(newToken));
|
||||
mockGetTokenFromId(newToken, false);
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||
|
@ -359,7 +351,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
authentication = token.getAuthentication();
|
||||
|
||||
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, token));
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
||||
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||
|
@ -370,8 +362,8 @@ public class TokenServiceTests extends ESTestCase {
|
|||
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
// verify a second separate token service with its own passphrase cannot verify
|
||||
TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex,
|
||||
clusterService);
|
||||
TokenService anotherService = new TokenService(Settings.EMPTY, systemUTC(), client, securityIndex,
|
||||
clusterService);
|
||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||
anotherService.getAndValidateToken(requestContext, future);
|
||||
assertNull(future.get());
|
||||
|
@ -385,10 +377,10 @@ public class TokenServiceTests extends ESTestCase {
|
|||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||
tokenService.createUserToken(authentication, authentication, tokenFuture, Collections.emptyMap(), true);
|
||||
UserToken token = tokenFuture.get().v1();
|
||||
assertThat(getDeprecatedAccessTokenString(tokenService, token), notNullValue());
|
||||
assertThat(tokenService.getUserTokenString(token), notNullValue());
|
||||
|
||||
tokenService.clearActiveKeyCache();
|
||||
assertThat(getDeprecatedAccessTokenString(tokenService, token), notNullValue());
|
||||
assertThat(tokenService.getUserTokenString(token), notNullValue());
|
||||
}
|
||||
|
||||
public void testInvalidatedToken() throws Exception {
|
||||
|
@ -403,7 +395,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
mockGetTokenFromId(token, true);
|
||||
|
||||
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getAccessTokenAsString(token));
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
||||
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||
|
@ -457,7 +449,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
authentication = token.getAuthentication();
|
||||
|
||||
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getAccessTokenAsString(token));
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
||||
|
||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||
// the clock is still frozen, so the cookie should be valid
|
||||
|
@ -567,7 +559,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
//mockGetTokenFromId(token, false);
|
||||
|
||||
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getAccessTokenAsString(token));
|
||||
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
||||
|
||||
doAnswer(invocationOnMock -> {
|
||||
ActionListener<GetResponse> listener = (ActionListener<GetResponse>) invocationOnMock.getArguments()[1];
|
||||
|
@ -606,7 +598,7 @@ public class TokenServiceTests extends ESTestCase {
|
|||
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||
UserToken expired = new UserToken(authentication, Instant.now().minus(3L, ChronoUnit.DAYS));
|
||||
mockGetTokenFromId(expired, false);
|
||||
String userTokenString = tokenService.getAccessTokenAsString(expired);
|
||||
String userTokenString = tokenService.getUserTokenString(expired);
|
||||
PlainActionFuture<Tuple<Authentication, Map<String, Object>>> authFuture = new PlainActionFuture<>();
|
||||
tokenService.getAuthenticationAndMetaData(userTokenString, authFuture);
|
||||
Authentication retrievedAuth = authFuture.actionGet().v1();
|
||||
|
@ -647,28 +639,4 @@ public class TokenServiceTests extends ESTestCase {
|
|||
assertEquals(expected.getMetadata(), result.getMetadata());
|
||||
assertEquals(AuthenticationType.TOKEN, result.getAuthenticationType());
|
||||
}
|
||||
|
||||
protected String getDeprecatedAccessTokenString(TokenService tokenService, UserToken userToken) throws IOException,
|
||||
GeneralSecurityException {
|
||||
try (ByteArrayOutputStream os = new ByteArrayOutputStream(TokenService.MINIMUM_BASE64_BYTES);
|
||||
OutputStream base64 = Base64.getEncoder().wrap(os);
|
||||
StreamOutput out = new OutputStreamStreamOutput(base64)) {
|
||||
out.setVersion(Version.V_7_0_0);
|
||||
TokenService.KeyAndCache keyAndCache = tokenService.getActiveKeyCache();
|
||||
Version.writeVersion(Version.V_7_0_0, out);
|
||||
out.writeByteArray(keyAndCache.getSalt().bytes);
|
||||
out.writeByteArray(keyAndCache.getKeyHash().bytes);
|
||||
final byte[] initializationVector = tokenService.getNewInitializationVector();
|
||||
out.writeByteArray(initializationVector);
|
||||
try (CipherOutputStream encryptedOutput =
|
||||
new CipherOutputStream(out, tokenService.getEncryptionCipher(initializationVector, keyAndCache, Version.V_7_0_0));
|
||||
StreamOutput encryptedStreamOutput = new OutputStreamStreamOutput(encryptedOutput)) {
|
||||
encryptedStreamOutput.setVersion(Version.V_7_0_0);
|
||||
encryptedStreamOutput.writeString(userToken.getId());
|
||||
encryptedStreamOutput.close();
|
||||
return new String(os.toByteArray(), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ public class TokensInvalidationResultTests extends ESTestCase {
|
|||
TokensInvalidationResult result = new TokensInvalidationResult(Arrays.asList("token1", "token2"),
|
||||
Arrays.asList("token3", "token4"),
|
||||
Arrays.asList(new ElasticsearchException("foo", new IllegalStateException("bar")),
|
||||
new ElasticsearchException("boo", new IllegalStateException("far"))));
|
||||
new ElasticsearchException("boo", new IllegalStateException("far"))),
|
||||
randomIntBetween(0, 5));
|
||||
|
||||
try (XContentBuilder builder = JsonXContent.contentBuilder()) {
|
||||
result.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
|
@ -55,8 +56,9 @@ public class TokensInvalidationResultTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testToXcontentWithNoErrors() throws Exception{
|
||||
TokensInvalidationResult result = new TokensInvalidationResult(Arrays.asList("token1", "token2"), Collections.emptyList(),
|
||||
Collections.emptyList());
|
||||
TokensInvalidationResult result = new TokensInvalidationResult(Arrays.asList("token1", "token2"),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(), randomIntBetween(0, 5));
|
||||
try (XContentBuilder builder = JsonXContent.contentBuilder()) {
|
||||
result.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
assertThat(Strings.toString(builder),
|
||||
|
|
Loading…
Reference in New Issue