Skip to content

Commit

Permalink
Move turn secret to static configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
jon-signal committed Jun 14, 2023
1 parent 13456ba commit 9cfd88a
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 22 deletions.
2 changes: 2 additions & 0 deletions service/config/sample-secrets-bundle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,5 @@ artService.userAuthenticationTokenUserIdSecret: AAAAAAAAAAA= # base64-encoded se

currentReportingKey.secret: AAAAAAAAAAA=
currentReportingKey.salt: AAAAAAAAAAA=

turn.secret: AAAAAAAAAAA=
3 changes: 3 additions & 0 deletions service/config/sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,6 @@ registrationService:
ABCDEFGHIJKLMNOPQRSTUVWXYZ/0123456789+abcdefghijklmnopqrstuvwxyz
AAAAAAAAAAAAAAAAAAAA
-----END CERTIFICATE-----
turn:
secret: secret://turn.secret
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.whispersystems.textsecuregcm.configuration.SpamFilterConfiguration;
import org.whispersystems.textsecuregcm.configuration.StripeConfiguration;
import org.whispersystems.textsecuregcm.configuration.SubscriptionConfiguration;
import org.whispersystems.textsecuregcm.configuration.TurnSecretConfiguration;
import org.whispersystems.textsecuregcm.configuration.UnidentifiedDeliveryConfiguration;
import org.whispersystems.textsecuregcm.configuration.ZkConfig;
import org.whispersystems.textsecuregcm.limits.RateLimiterConfig;
Expand Down Expand Up @@ -264,6 +265,11 @@ public class WhisperServerConfiguration extends Configuration {
@JsonProperty
private RegistrationServiceConfiguration registrationService;

@Valid
@NotNull
@JsonProperty
private TurnSecretConfiguration turn;

public AdminEventLoggingConfiguration getAdminEventLoggingConfiguration() {
return adminEventLoggingConfiguration;
}
Expand Down Expand Up @@ -438,4 +444,8 @@ public SpamFilterConfiguration getSpamFilterConfiguration() {
public RegistrationServiceConfiguration getRegistrationServiceConfiguration() {
return registrationService;
}

public TurnSecretConfiguration getTurnSecretConfiguration() {
return turn;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,8 @@ public void run(WhisperServerConfiguration config, Environment environment) thro
pushNotificationManager,
pushLatencyManager);
final ReceiptSender receiptSender = new ReceiptSender(accountsManager, messageSender, receiptSenderExecutor);
final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(dynamicConfigurationManager);
final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(dynamicConfigurationManager,
config.getTurnSecretConfiguration().secret().value());

RecaptchaClient recaptchaClient = new RecaptchaClient(
config.getRecaptchaConfiguration().projectPath(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,44 @@

public class TurnTokenGenerator {

private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfiguration;
private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager;

private final byte[] turnSecret;

private static final String ALGORITHM = "HmacSHA1";

public TurnTokenGenerator(final DynamicConfigurationManager<DynamicConfiguration> config) {
this.dynamicConfiguration = config;
public TurnTokenGenerator(final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager,
final byte[] turnSecret) {

this.dynamicConfigurationManager = dynamicConfigurationManager;
this.turnSecret = turnSecret;
}

public TurnToken generate(final String e164) {
try {
final byte[] key = dynamicConfiguration.getConfiguration().getTurnConfiguration().getSecret().getBytes();
final List<String> urls = urls(e164);
final Mac mac = Mac.getInstance(ALGORITHM);
final long validUntilSeconds = Instant.now().plus(Duration.ofDays(1)).getEpochSecond();
final long user = Util.ensureNonNegativeInt(new SecureRandom().nextInt());
final String userTime = validUntilSeconds + ":" + user;

mac.init(new SecretKeySpec(key, ALGORITHM));
mac.init(new SecretKeySpec(turnSecret, ALGORITHM));
final String password = Base64.getEncoder().encodeToString(mac.doFinal(userTime.getBytes()));

return new TurnToken(userTime, password, urls);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
} catch (final NoSuchAlgorithmException | InvalidKeyException e) {
throw new AssertionError(e);
}
}

private List<String> urls(final String e164) {
final DynamicTurnConfiguration turnConfig = dynamicConfiguration.getConfiguration().getTurnConfiguration();
final DynamicTurnConfiguration turnConfig = dynamicConfigurationManager.getConfiguration().getTurnConfiguration();

// Check if number is enrolled to test out specific turn servers
final Optional<TurnUriConfiguration> enrolled = turnConfig.getUriConfigs().stream()
.filter(config -> config.getEnrolledNumbers().contains(e164))
.findFirst();

if (enrolled.isPresent()) {
return enrolled.get().getUris();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/

package org.whispersystems.textsecuregcm.configuration;

import org.whispersystems.textsecuregcm.configuration.secrets.SecretBytes;

public record TurnSecretConfiguration(SecretBytes secret) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,10 @@

public class DynamicTurnConfiguration {

@JsonProperty
private String secret;

@JsonProperty
private List<@Valid TurnUriConfiguration> uriConfigs = Collections.emptyList();

public List<TurnUriConfiguration> getUriConfigs() {
return uriConfigs;
}

public String getSecret() {
return secret;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -21,7 +22,6 @@ public void testAlwaysSelectFirst() throws JsonProcessingException {
captcha:
scoreFloor: 1.0
turn:
secret: bloop
uriConfigs:
- uris:
- always1.org
Expand All @@ -39,7 +39,9 @@ public void testAlwaysSelectFirst() throws JsonProcessingException {
DynamicConfigurationManager.class);

when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(mockDynamicConfigManager);

final TurnTokenGenerator turnTokenGenerator =
new TurnTokenGenerator(mockDynamicConfigManager, "bloop".getBytes(StandardCharsets.UTF_8));

final long COUNT = 1000;

Expand All @@ -60,7 +62,6 @@ public void testProbabilisticUrls() throws JsonProcessingException {
captcha:
scoreFloor: 1.0
turn:
secret: bloop
uriConfigs:
- uris:
- always.org
Expand All @@ -80,7 +81,8 @@ public void testProbabilisticUrls() throws JsonProcessingException {
DynamicConfigurationManager.class);

when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(mockDynamicConfigManager);
final TurnTokenGenerator turnTokenGenerator =
new TurnTokenGenerator(mockDynamicConfigManager, "bloop".getBytes(StandardCharsets.UTF_8));

final long COUNT = 1000;

Expand Down Expand Up @@ -122,7 +124,9 @@ public void testExplicitEnrollment() throws JsonProcessingException {

when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);

final TurnTokenGenerator turnTokenGenerator = new TurnTokenGenerator(mockDynamicConfigManager);
final TurnTokenGenerator turnTokenGenerator =
new TurnTokenGenerator(mockDynamicConfigManager, "bloop".getBytes(StandardCharsets.UTF_8));

TurnToken token = turnTokenGenerator.generate("+15555555555");
assertThat(token.getUrls().get(0)).isEqualTo("enrolled.org");
token = turnTokenGenerator.generate("+15555555556");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,6 @@ void testParseTurnConfig() throws JsonProcessingException {
{
final String config = REQUIRED_CONFIG.concat("""
turn:
secret: bloop
uriConfigs:
- uris:
- turn:test0.org
Expand All @@ -344,7 +343,6 @@ void testParseTurnConfig() throws JsonProcessingException {
.parseConfiguration(config, DynamicConfiguration.class)
.orElseThrow()
.getTurnConfiguration();
assertThat(turnConfiguration.getSecret()).isEqualTo("bloop");
assertThat(turnConfiguration.getUriConfigs().get(0).getUris()).hasSize(2);
assertThat(turnConfiguration.getUriConfigs().get(1).getUris()).hasSize(1);
assertThat(turnConfiguration.getUriConfigs().get(0).getWeight()).isEqualTo(1);
Expand Down

0 comments on commit 9cfd88a

Please sign in to comment.