Skip to content

Commit 8d0bae6

Browse files
authored
Make hashed token ids url safe (#42651)
This commit changes the way token ids are hashed so that the output is url safe without requiring encoding. This follows the pattern that we use for document ids that are autogenerated, see UUIDs and the associated classes for additional details.
1 parent 2bc4363 commit 8d0bae6

File tree

6 files changed

+24
-6
lines changed

6 files changed

+24
-6
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/Hasher.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,14 +360,14 @@ public boolean verify(SecureString text, char[] hash) {
360360
public char[] hash(SecureString text) {
361361
MessageDigest md = MessageDigests.sha256();
362362
md.update(CharArrays.toUtf8Bytes(text.getChars()));
363-
return Base64.getEncoder().encodeToString(md.digest()).toCharArray();
363+
return Base64.getUrlEncoder().withoutPadding().encodeToString(md.digest()).toCharArray();
364364
}
365365

366366
@Override
367367
public boolean verify(SecureString text, char[] hash) {
368368
MessageDigest md = MessageDigests.sha256();
369369
md.update(CharArrays.toUtf8Bytes(text.getChars()));
370-
return CharArrays.constantTimeEquals(Base64.getEncoder().encodeToString(md.digest()).toCharArray(), hash);
370+
return CharArrays.constantTimeEquals(Base64.getUrlEncoder().withoutPadding().encodeToString(md.digest()).toCharArray(), hash);
371371
}
372372
},
373373

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public final class TokenService {
181181
TimeValue.MINUS_ONE, Property.NodeScope);
182182

183183
static final String TOKEN_DOC_TYPE = "token";
184-
private static final int HASHED_TOKEN_LENGTH = 44;
184+
private static final int HASHED_TOKEN_LENGTH = 43;
185185
// UUIDs are 16 bytes encoded base64 without padding, therefore the length is (16 / 3) * 4 + ((16 % 3) * 8 + 5) / 6 chars
186186
private static final int TOKEN_LENGTH = 22;
187187
private static final String TOKEN_DOC_ID_PREFIX = TOKEN_DOC_TYPE + "_";

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,17 @@
5353
import org.elasticsearch.xpack.core.security.user.User;
5454
import org.elasticsearch.xpack.core.watcher.watch.ClockMock;
5555
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
56-
import org.junit.After;
5756
import org.elasticsearch.xpack.security.test.SecurityMocks;
5857
import org.hamcrest.Matchers;
58+
import org.junit.After;
5959
import org.junit.AfterClass;
6060
import org.junit.Before;
6161
import org.junit.BeforeClass;
6262

63+
import javax.crypto.SecretKey;
6364
import java.io.IOException;
65+
import java.net.URLEncoder;
66+
import java.nio.charset.StandardCharsets;
6467
import java.security.GeneralSecurityException;
6568
import java.time.Clock;
6669
import java.time.Instant;
@@ -70,8 +73,6 @@
7073
import java.util.HashMap;
7174
import java.util.Map;
7275

73-
import javax.crypto.SecretKey;
74-
7576
import static java.time.Clock.systemUTC;
7677
import static org.elasticsearch.repositories.ESBlobStoreTestCase.randomBytes;
7778
import static org.elasticsearch.test.ClusterServiceUtils.setState;
@@ -721,6 +722,11 @@ public void testCannotValidateTokenIfLicenseDoesNotAllowTokens() throws Exceptio
721722
assertThat(authToken, Matchers.nullValue());
722723
}
723724

725+
public void testHashedTokenIsUrlSafe() {
726+
final String hashedId = TokenService.hashTokenString(UUIDs.randomBase64UUID());
727+
assertEquals(hashedId, URLEncoder.encode(hashedId, StandardCharsets.UTF_8));
728+
}
729+
724730
private TokenService createTokenService(Settings settings, Clock clock) throws GeneralSecurityException {
725731
return new TokenService(settings, clock, client, licenseState, securityMainIndex, securityTokensIndex, clusterService);
726732
}

x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/TokenBackwardsCompatibilityIT.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import org.apache.http.HttpHeaders;
99
import org.apache.http.HttpHost;
10+
import org.apache.lucene.util.LuceneTestCase.AwaitsFix;
1011
import org.elasticsearch.Version;
1112
import org.elasticsearch.client.Request;
1213
import org.elasticsearch.client.RequestOptions;
@@ -25,6 +26,7 @@
2526
import java.util.List;
2627
import java.util.Map;
2728

29+
@AwaitsFix(bugUrl = "need to backport #42651")
2830
public class TokenBackwardsCompatibilityIT extends AbstractUpgradeTestCase {
2931

3032
private Collection<RestClient> twoClients = null;

x-pack/qa/rolling-upgrade/src/test/resources/rest-api-spec/test/mixed_cluster/50_token_auth.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
"Get the indexed token and use if to authenticate":
33
- skip:
44
features: headers
5+
version: " - 7.99.99"
6+
reason: "Need to backport PR #42651"
57

68
- do:
79
cluster.health:
@@ -59,6 +61,8 @@
5961
"Get the indexed refreshed access token and use if to authenticate":
6062
- skip:
6163
features: headers
64+
version: " - 7.99.99"
65+
reason: "Need to backport PR #42651"
6266

6367
- do:
6468
get:
@@ -111,6 +115,8 @@
111115
"Get the indexed refresh token and use it to get another access token and authenticate":
112116
- skip:
113117
features: headers
118+
version: " - 7.99.99"
119+
reason: "Need to backport PR #42651"
114120

115121
- do:
116122
get:

x-pack/qa/rolling-upgrade/src/test/resources/rest-api-spec/test/upgraded_cluster/50_token_auth.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
"Get the indexed token and use if to authenticate":
33
- skip:
44
features: headers
5+
version: " - 8.0.0"
6+
reason: "Need to backport PR #42651"
57

68
- do:
79
cluster.health:
@@ -49,6 +51,8 @@
4951
"Get the indexed refresh token and use if to get another access token and authenticate":
5052
- skip:
5153
features: headers
54+
version: " - 8.0.0"
55+
reason: "Need to backport PR #42651"
5256

5357
- do:
5458
get:

0 commit comments

Comments
 (0)