Move turn secret to static configuration
This commit is contained in:
		
							parent
							
								
									13456bad3a
								
							
						
					
					
						commit
						9cfd88a23f
					
				|  | @ -84,3 +84,5 @@ artService.userAuthenticationTokenUserIdSecret: AAAAAAAAAAA= # base64-encoded se | |||
| 
 | ||||
| currentReportingKey.secret: AAAAAAAAAAA= | ||||
| currentReportingKey.salt: AAAAAAAAAAA= | ||||
| 
 | ||||
| turn.secret: AAAAAAAAAAA= | ||||
|  |  | |||
|  | @ -419,3 +419,6 @@ registrationService: | |||
|     ABCDEFGHIJKLMNOPQRSTUVWXYZ/0123456789+abcdefghijklmnopqrstuvwxyz | ||||
|     AAAAAAAAAAAAAAAAAAAA | ||||
|     -----END CERTIFICATE----- | ||||
| 
 | ||||
| turn: | ||||
|   secret: secret://turn.secret | ||||
|  |  | |||
|  | @ -47,6 +47,7 @@ import org.whispersystems.textsecuregcm.configuration.SecureValueRecovery2Config | |||
| 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; | ||||
|  | @ -264,6 +265,11 @@ public class WhisperServerConfiguration extends Configuration { | |||
|   @JsonProperty | ||||
|   private RegistrationServiceConfiguration registrationService; | ||||
| 
 | ||||
|   @Valid | ||||
|   @NotNull | ||||
|   @JsonProperty | ||||
|   private TurnSecretConfiguration turn; | ||||
| 
 | ||||
|   public AdminEventLoggingConfiguration getAdminEventLoggingConfiguration() { | ||||
|     return adminEventLoggingConfiguration; | ||||
|   } | ||||
|  | @ -438,4 +444,8 @@ public class WhisperServerConfiguration extends Configuration { | |||
|   public RegistrationServiceConfiguration getRegistrationServiceConfiguration() { | ||||
|     return registrationService; | ||||
|   } | ||||
| 
 | ||||
|   public TurnSecretConfiguration getTurnSecretConfiguration() { | ||||
|     return turn; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -554,7 +554,8 @@ public class WhisperServerService extends Application<WhisperServerConfiguration | |||
|         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(), | ||||
|  |  | |||
|  | @ -26,39 +26,44 @@ import java.util.Optional; | |||
| 
 | ||||
| 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(); | ||||
|     } | ||||
|  |  | |||
|  | @ -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) { | ||||
| } | ||||
|  | @ -13,17 +13,10 @@ import org.whispersystems.textsecuregcm.configuration.TurnUriConfiguration; | |||
| 
 | ||||
| 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; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; | |||
| 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; | ||||
|  | @ -21,7 +22,6 @@ public class TurnTokenGeneratorTest { | |||
|         captcha: | ||||
|           scoreFloor: 1.0 | ||||
|         turn: | ||||
|           secret: bloop | ||||
|           uriConfigs: | ||||
|             - uris: | ||||
|                 - always1.org | ||||
|  | @ -39,7 +39,9 @@ public class TurnTokenGeneratorTest { | |||
|         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; | ||||
| 
 | ||||
|  | @ -60,7 +62,6 @@ public class TurnTokenGeneratorTest { | |||
|         captcha: | ||||
|           scoreFloor: 1.0 | ||||
|         turn: | ||||
|           secret: bloop | ||||
|           uriConfigs: | ||||
|             - uris: | ||||
|                 - always.org | ||||
|  | @ -80,7 +81,8 @@ public class TurnTokenGeneratorTest { | |||
|         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; | ||||
| 
 | ||||
|  | @ -122,7 +124,9 @@ public class TurnTokenGeneratorTest { | |||
| 
 | ||||
|     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"); | ||||
|  |  | |||
|  | @ -329,7 +329,6 @@ class DynamicConfigurationTest { | |||
|     { | ||||
|       final String config = REQUIRED_CONFIG.concat(""" | ||||
|           turn: | ||||
|             secret: bloop | ||||
|             uriConfigs: | ||||
|                 - uris: | ||||
|                     - turn:test0.org | ||||
|  | @ -344,7 +343,6 @@ class DynamicConfigurationTest { | |||
|           .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); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Jon Chambers
						Jon Chambers