Derive username from ACI for CDS{H,I} (#989)

* Derive username from ACI for CDS{H,I}

* Update sample YAML.
This commit is contained in:
gram-signal 2022-05-02 08:41:38 -06:00 committed by GitHub
parent 058caadf4f
commit 06dd4c5026
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 17 additions and 19 deletions

View File

@ -134,6 +134,7 @@ directory:
directoryV2: directoryV2:
client: # Configuration for interfacing with Contact Discovery Service v2 cluster client: # Configuration for interfacing with Contact Discovery Service v2 cluster
userAuthenticationTokenSharedSecret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG= # base64-encoded secret shared with CDS to generate auth tokens for Signal users userAuthenticationTokenSharedSecret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG= # base64-encoded secret shared with CDS to generate auth tokens for Signal users
userIdTokenSharedSecret: bbcdefghijklmnopqrstuvwxyz0123456789ABCDEFG= # base64-encoded secret shared with CDS to generate auth identity tokens for Signal users
messageCache: # Redis server configuration for message store cache messageCache: # Redis server configuration for message store cache
persistDelayMinutes: 1 persistDelayMinutes: 1

View File

@ -420,8 +420,9 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenSharedSecret(), config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenSharedSecret(),
config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenUserIdSecret()); config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenUserIdSecret());
ExternalServiceCredentialGenerator directoryV2CredentialsGenerator = new ExternalServiceCredentialGenerator( ExternalServiceCredentialGenerator directoryV2CredentialsGenerator = new ExternalServiceCredentialGenerator(
config.getDirectoryV2Configuration().getDirectoryV2ClientConfiguration() config.getDirectoryV2Configuration().getDirectoryV2ClientConfiguration().getUserAuthenticationTokenSharedSecret(),
.getUserAuthenticationTokenSharedSecret(), false); config.getDirectoryV2Configuration().getDirectoryV2ClientConfiguration().getUserIdTokenSharedSecret(),
true, false);
dynamicConfigurationManager.start(); dynamicConfigurationManager.start();

View File

@ -35,7 +35,7 @@ public class ExternalServiceCredentialGenerator {
this(key, userIdKey, usernameDerivation, true); this(key, userIdKey, usernameDerivation, true);
} }
private ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation, public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation,
boolean prependUsername) { boolean prependUsername) {
this(key, userIdKey, usernameDerivation, prependUsername, Clock.systemUTC()); this(key, userIdKey, usernameDerivation, prependUsername, Clock.systemUTC());
} }

View File

@ -11,11 +11,14 @@ import org.whispersystems.textsecuregcm.util.ExactlySize;
public class DirectoryV2ClientConfiguration { public class DirectoryV2ClientConfiguration {
private final byte[] userAuthenticationTokenSharedSecret; private final byte[] userAuthenticationTokenSharedSecret;
private final byte[] userIdTokenSharedSecret;
@JsonCreator @JsonCreator
public DirectoryV2ClientConfiguration( public DirectoryV2ClientConfiguration(
@JsonProperty("userAuthenticationTokenSharedSecret") final byte[] userAuthenticationTokenSharedSecret) { @JsonProperty("userAuthenticationTokenSharedSecret") final byte[] userAuthenticationTokenSharedSecret,
@JsonProperty("userIdTokenSharedSecret") final byte[] userIdTokenSharedSecret) {
this.userAuthenticationTokenSharedSecret = userAuthenticationTokenSharedSecret; this.userAuthenticationTokenSharedSecret = userAuthenticationTokenSharedSecret;
this.userIdTokenSharedSecret = userIdTokenSharedSecret;
} }
@ExactlySize({32}) @ExactlySize({32})
@ -23,4 +26,8 @@ public class DirectoryV2ClientConfiguration {
return userAuthenticationTokenSharedSecret; return userAuthenticationTokenSharedSecret;
} }
@ExactlySize({32})
public byte[] getUserIdTokenSharedSecret() {
return userIdTokenSharedSecret;
}
} }

View File

@ -34,16 +34,8 @@ public class DirectoryV2Controller {
@Path("/auth") @Path("/auth")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response getAuthToken(@Auth AuthenticatedAccount auth) { public Response getAuthToken(@Auth AuthenticatedAccount auth) {
final UUID uuid = auth.getAccount().getUuid(); final UUID uuid = auth.getAccount().getUuid();
final String e164 = auth.getAccount().getNumber(); final ExternalServiceCredentials credentials = directoryServiceTokenGenerator.generateFor(uuid.toString());
final long e164AsLong = Long.parseLong(e164, e164.indexOf('+'), e164.length() - 1, 10);
final byte[] uuidAndNumber = ByteUtil.combine(UUIDUtil.toBytes(uuid), Util.longToByteArray(e164AsLong));
final String username = Base64.getEncoder().encodeToString(uuidAndNumber);
final ExternalServiceCredentials credentials = directoryServiceTokenGenerator.generateFor(username);
return Response.ok().entity(credentials).build(); return Response.ok().entity(credentials).build();
} }
} }

View File

@ -27,7 +27,7 @@ class DirectoryControllerV2Test {
@Test @Test
void testAuthToken() { void testAuthToken() {
final ExternalServiceCredentialGenerator credentialGenerator = new ExternalServiceCredentialGenerator( final ExternalServiceCredentialGenerator credentialGenerator = new ExternalServiceCredentialGenerator(
new byte[]{0x1}, new byte[0], false, false, new byte[]{0x1}, new byte[]{0x2}, true, false,
Clock.fixed(Instant.ofEpochSecond(1633738643L), ZoneId.of("Etc/UTC"))); Clock.fixed(Instant.ofEpochSecond(1633738643L), ZoneId.of("Etc/UTC")));
final DirectoryV2Controller controller = new DirectoryV2Controller(credentialGenerator); final DirectoryV2Controller controller = new DirectoryV2Controller(credentialGenerator);
@ -35,15 +35,12 @@ class DirectoryControllerV2Test {
final Account account = mock(Account.class); final Account account = mock(Account.class);
final UUID uuid = UUID.fromString("11111111-1111-1111-1111-111111111111"); final UUID uuid = UUID.fromString("11111111-1111-1111-1111-111111111111");
when(account.getUuid()).thenReturn(uuid); when(account.getUuid()).thenReturn(uuid);
when(account.getNumber()).thenReturn("+15055551111");
final ExternalServiceCredentials credentials = (ExternalServiceCredentials) controller.getAuthToken( final ExternalServiceCredentials credentials = (ExternalServiceCredentials) controller.getAuthToken(
new AuthenticatedAccount(() -> new Pair<>(account, mock(Device.class)))).getEntity(); new AuthenticatedAccount(() -> new Pair<>(account, mock(Device.class)))).getEntity();
assertEquals(credentials.getUsername(), "EREREREREREREREREREREQAAAABZvPKn"); assertEquals(credentials.getUsername(), "d369bc712e2e0dd36258");
assertEquals(credentials.getPassword(), "1633738643:ff03669c64f3f938a279"); assertEquals(credentials.getPassword(), "1633738643:4433b0fab41f25f79dd4");
assertEquals(32, credentials.getUsername().length());
assertEquals(31, credentials.getPassword().length());
} }
} }