|
@@ -6,6 +6,7 @@
|
|
|
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;
|
|
@@ -23,6 +24,8 @@ 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;
|
|
@@ -51,7 +54,11 @@ 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;
|
|
@@ -61,6 +68,7 @@ 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;
|
|
@@ -151,7 +159,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
authentication = token.getAuthentication();
|
|
|
|
|
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", randomFrom("Bearer ", "BEARER ", "bearer ") + tokenService.getUserTokenString(token));
|
|
|
+ requestContext.putHeader("Authorization", randomFrom("Bearer ", "BEARER ", "bearer ") + tokenService.getAccessTokenAsString(token));
|
|
|
|
|
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
|
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
|
@@ -198,7 +206,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
authentication = token.getAuthentication();
|
|
|
|
|
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
|
|
+ requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, token));
|
|
|
|
|
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
|
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
|
@@ -219,10 +227,10 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
tokenService.createUserToken(authentication, authentication, newTokenFuture, Collections.emptyMap(), true);
|
|
|
final UserToken newToken = newTokenFuture.get().v1();
|
|
|
assertNotNull(newToken);
|
|
|
- assertNotEquals(tokenService.getUserTokenString(newToken), tokenService.getUserTokenString(token));
|
|
|
+ assertNotEquals(getDeprecatedAccessTokenString(tokenService, newToken), getDeprecatedAccessTokenString(tokenService, token));
|
|
|
|
|
|
requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(newToken));
|
|
|
+ requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, newToken));
|
|
|
mockGetTokenFromId(newToken, false);
|
|
|
|
|
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
|
@@ -247,7 +255,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<>();
|
|
@@ -258,7 +266,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
authentication = token.getAuthentication();
|
|
|
|
|
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
|
|
+ requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, token));
|
|
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
|
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
|
|
otherTokenService.getAndValidateToken(requestContext, future);
|
|
@@ -289,7 +297,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
authentication = token.getAuthentication();
|
|
|
|
|
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
|
|
+ requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, token));
|
|
|
|
|
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
|
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
|
@@ -316,7 +324,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
tokenService.createUserToken(authentication, authentication, newTokenFuture, Collections.emptyMap(), true);
|
|
|
final UserToken newToken = newTokenFuture.get().v1();
|
|
|
assertNotNull(newToken);
|
|
|
- assertNotEquals(tokenService.getUserTokenString(newToken), tokenService.getUserTokenString(token));
|
|
|
+ assertNotEquals(getDeprecatedAccessTokenString(tokenService, newToken), getDeprecatedAccessTokenString(tokenService, token));
|
|
|
|
|
|
metaData = tokenService.pruneKeys(1);
|
|
|
tokenService.refreshMetaData(metaData);
|
|
@@ -329,7 +337,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
}
|
|
|
|
|
|
requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(newToken));
|
|
|
+ requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, newToken));
|
|
|
mockGetTokenFromId(newToken, false);
|
|
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
|
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
|
@@ -351,7 +359,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
authentication = token.getAuthentication();
|
|
|
|
|
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
|
|
+ requestContext.putHeader("Authorization", "Bearer " + getDeprecatedAccessTokenString(tokenService, token));
|
|
|
|
|
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
|
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
|
@@ -362,8 +370,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(Settings.EMPTY, systemUTC(), client, securityIndex,
|
|
|
- clusterService);
|
|
|
+ TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex,
|
|
|
+ clusterService);
|
|
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
|
|
anotherService.getAndValidateToken(requestContext, future);
|
|
|
assertNull(future.get());
|
|
@@ -377,10 +385,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(tokenService.getUserTokenString(token), notNullValue());
|
|
|
+ assertThat(getDeprecatedAccessTokenString(tokenService, token), notNullValue());
|
|
|
|
|
|
tokenService.clearActiveKeyCache();
|
|
|
- assertThat(tokenService.getUserTokenString(token), notNullValue());
|
|
|
+ assertThat(getDeprecatedAccessTokenString(tokenService, token), notNullValue());
|
|
|
}
|
|
|
|
|
|
public void testInvalidatedToken() throws Exception {
|
|
@@ -395,7 +403,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
mockGetTokenFromId(token, true);
|
|
|
|
|
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
|
|
+ requestContext.putHeader("Authorization", "Bearer " + tokenService.getAccessTokenAsString(token));
|
|
|
|
|
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
|
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
|
@@ -449,7 +457,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
authentication = token.getAuthentication();
|
|
|
|
|
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
|
|
+ requestContext.putHeader("Authorization", "Bearer " + tokenService.getAccessTokenAsString(token));
|
|
|
|
|
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
|
|
// the clock is still frozen, so the cookie should be valid
|
|
@@ -559,7 +567,7 @@ public class TokenServiceTests extends ESTestCase {
|
|
|
//mockGetTokenFromId(token, false);
|
|
|
|
|
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
|
|
- requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
|
|
|
+ requestContext.putHeader("Authorization", "Bearer " + tokenService.getAccessTokenAsString(token));
|
|
|
|
|
|
doAnswer(invocationOnMock -> {
|
|
|
ActionListener<GetResponse> listener = (ActionListener<GetResponse>) invocationOnMock.getArguments()[1];
|
|
@@ -598,7 +606,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.getUserTokenString(expired);
|
|
|
+ String userTokenString = tokenService.getAccessTokenAsString(expired);
|
|
|
PlainActionFuture<Tuple<Authentication, Map<String, Object>>> authFuture = new PlainActionFuture<>();
|
|
|
tokenService.getAuthenticationAndMetaData(userTokenString, authFuture);
|
|
|
Authentication retrievedAuth = authFuture.actionGet().v1();
|
|
@@ -639,4 +647,28 @@ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|