Separate username and signature truncation fields
This commit is contained in:
parent
e4da59c236
commit
7b331edcde
|
@ -22,6 +22,8 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
|
|
||||||
private static final String DELIMITER = ":";
|
private static final String DELIMITER = ":";
|
||||||
|
|
||||||
|
private static final int TRUNCATED_SIGNATURE_LENGTH = 10;
|
||||||
|
|
||||||
private final byte[] key;
|
private final byte[] key;
|
||||||
|
|
||||||
private final byte[] userDerivationKey;
|
private final byte[] userDerivationKey;
|
||||||
|
@ -36,7 +38,7 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
|
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
private final int truncateLength;
|
private final int derivedUsernameTruncateLength;
|
||||||
|
|
||||||
public static ExternalServiceCredentialsGenerator.Builder builder(final byte[] key) {
|
public static ExternalServiceCredentialsGenerator.Builder builder(final byte[] key) {
|
||||||
return new Builder(key);
|
return new Builder(key);
|
||||||
|
@ -47,7 +49,7 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
final byte[] userDerivationKey,
|
final byte[] userDerivationKey,
|
||||||
final boolean prependUsername,
|
final boolean prependUsername,
|
||||||
final boolean truncateSignature,
|
final boolean truncateSignature,
|
||||||
final int truncateLength,
|
final int derivedUsernameTruncateLength,
|
||||||
final String usernameTimestampPrefix,
|
final String usernameTimestampPrefix,
|
||||||
final Function<Instant, Instant> usernameTimestampTruncator,
|
final Function<Instant, Instant> usernameTimestampTruncator,
|
||||||
final Clock clock) {
|
final Clock clock) {
|
||||||
|
@ -58,7 +60,7 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
this.usernameTimestampPrefix = usernameTimestampPrefix;
|
this.usernameTimestampPrefix = usernameTimestampPrefix;
|
||||||
this.usernameTimestampTruncator = usernameTimestampTruncator;
|
this.usernameTimestampTruncator = usernameTimestampTruncator;
|
||||||
this.clock = requireNonNull(clock);
|
this.clock = requireNonNull(clock);
|
||||||
this.truncateLength = truncateLength;
|
this.derivedUsernameTruncateLength = derivedUsernameTruncateLength;
|
||||||
|
|
||||||
if (hasUsernameTimestampPrefix() ^ hasUsernameTimestampTruncator()) {
|
if (hasUsernameTimestampPrefix() ^ hasUsernameTimestampTruncator()) {
|
||||||
throw new RuntimeException("Configured to have only one of (usernameTimestampPrefix, usernameTimestampTruncator)");
|
throw new RuntimeException("Configured to have only one of (usernameTimestampPrefix, usernameTimestampTruncator)");
|
||||||
|
@ -102,7 +104,7 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
|
|
||||||
private ExternalServiceCredentials generate(final String identity) {
|
private ExternalServiceCredentials generate(final String identity) {
|
||||||
final String username = shouldDeriveUsername()
|
final String username = shouldDeriveUsername()
|
||||||
? hmac256TruncatedToHexString(userDerivationKey, identity, truncateLength)
|
? hmac256TruncatedToHexString(userDerivationKey, identity, derivedUsernameTruncateLength)
|
||||||
: identity;
|
: identity;
|
||||||
|
|
||||||
final long currentTimeSeconds = currentTimeSeconds();
|
final long currentTimeSeconds = currentTimeSeconds();
|
||||||
|
@ -110,7 +112,7 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
final String dataToSign = usernameIsTimestamp() ? username : username + DELIMITER + currentTimeSeconds;
|
final String dataToSign = usernameIsTimestamp() ? username : username + DELIMITER + currentTimeSeconds;
|
||||||
|
|
||||||
final String signature = truncateSignature
|
final String signature = truncateSignature
|
||||||
? hmac256TruncatedToHexString(key, dataToSign, truncateLength)
|
? hmac256TruncatedToHexString(key, dataToSign, TRUNCATED_SIGNATURE_LENGTH)
|
||||||
: hmac256ToHexString(key, dataToSign);
|
: hmac256ToHexString(key, dataToSign);
|
||||||
|
|
||||||
final String token = (prependUsername ? dataToSign : currentTimeSeconds) + DELIMITER + signature;
|
final String token = (prependUsername ? dataToSign : currentTimeSeconds) + DELIMITER + signature;
|
||||||
|
@ -173,7 +175,7 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
|
|
||||||
final String signedData = usernameIsTimestamp() ? credentials.username() : credentials.username() + DELIMITER + timestampSeconds;
|
final String signedData = usernameIsTimestamp() ? credentials.username() : credentials.username() + DELIMITER + timestampSeconds;
|
||||||
final String expectedSignature = truncateSignature
|
final String expectedSignature = truncateSignature
|
||||||
? hmac256TruncatedToHexString(key, signedData, truncateLength)
|
? hmac256TruncatedToHexString(key, signedData, TRUNCATED_SIGNATURE_LENGTH)
|
||||||
: hmac256ToHexString(key, signedData);
|
: hmac256ToHexString(key, signedData);
|
||||||
|
|
||||||
// if the signature is valid it's safe to parse the `timestampSeconds` string into Long
|
// if the signature is valid it's safe to parse the `timestampSeconds` string into Long
|
||||||
|
@ -225,7 +227,7 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
|
|
||||||
private boolean truncateSignature = true;
|
private boolean truncateSignature = true;
|
||||||
|
|
||||||
private int truncateLength = 10;
|
private int derivedUsernameTruncateLength = 10;
|
||||||
|
|
||||||
private String usernameTimestampPrefix = null;
|
private String usernameTimestampPrefix = null;
|
||||||
|
|
||||||
|
@ -249,9 +251,9 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder withTruncateLength(int truncateLength) {
|
public Builder withDerivedUsernameTruncateLength(int truncateLength) {
|
||||||
Validate.inclusiveBetween(10, 32, truncateLength);
|
Validate.inclusiveBetween(10, 32, truncateLength);
|
||||||
this.truncateLength = truncateLength;
|
this.derivedUsernameTruncateLength = truncateLength;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +275,7 @@ public class ExternalServiceCredentialsGenerator {
|
||||||
|
|
||||||
public ExternalServiceCredentialsGenerator build() {
|
public ExternalServiceCredentialsGenerator build() {
|
||||||
return new ExternalServiceCredentialsGenerator(
|
return new ExternalServiceCredentialsGenerator(
|
||||||
key, userDerivationKey, prependUsername, truncateSignature, truncateLength, usernameTimestampPrefix, usernameTimestampTruncator, clock);
|
key, userDerivationKey, prependUsername, truncateSignature, derivedUsernameTruncateLength, usernameTimestampPrefix, usernameTimestampTruncator, clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class SecureValueRecovery2Controller {
|
||||||
.builder(cfg.userAuthenticationTokenSharedSecret())
|
.builder(cfg.userAuthenticationTokenSharedSecret())
|
||||||
.withUserDerivationKey(cfg.userIdTokenSharedSecret())
|
.withUserDerivationKey(cfg.userIdTokenSharedSecret())
|
||||||
.prependUsername(false)
|
.prependUsername(false)
|
||||||
.withTruncateLength(16)
|
.withDerivedUsernameTruncateLength(16)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,10 +170,11 @@ class ExternalServiceCredentialsGeneratorTest {
|
||||||
public void testTruncateLength() throws Exception {
|
public void testTruncateLength() throws Exception {
|
||||||
final ExternalServiceCredentialsGenerator generator = ExternalServiceCredentialsGenerator.builder(new byte[32])
|
final ExternalServiceCredentialsGenerator generator = ExternalServiceCredentialsGenerator.builder(new byte[32])
|
||||||
.withUserDerivationKey(new byte[32])
|
.withUserDerivationKey(new byte[32])
|
||||||
.withTruncateLength(14)
|
.withDerivedUsernameTruncateLength(14)
|
||||||
.build();
|
.build();
|
||||||
final ExternalServiceCredentials creds = generator.generateFor(E164);
|
final ExternalServiceCredentials creds = generator.generateFor(E164);
|
||||||
assertEquals(14*2 /* 2 chars per byte, because hex */, creds.username().length());
|
assertEquals(14*2 /* 2 chars per byte, because hex */, creds.username().length());
|
||||||
assertEquals("805b84df7eff1e8fe1baf0c6e838", creds.username());
|
assertEquals("805b84df7eff1e8fe1baf0c6e838", creds.username());
|
||||||
|
generator.validateAndGetTimestamp(creds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue