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.secret: AAAAAAAAAAA= | ||||||
| currentReportingKey.salt: AAAAAAAAAAA= | currentReportingKey.salt: AAAAAAAAAAA= | ||||||
|  | 
 | ||||||
|  | turn.secret: AAAAAAAAAAA= | ||||||
|  |  | ||||||
|  | @ -419,3 +419,6 @@ registrationService: | ||||||
|     ABCDEFGHIJKLMNOPQRSTUVWXYZ/0123456789+abcdefghijklmnopqrstuvwxyz |     ABCDEFGHIJKLMNOPQRSTUVWXYZ/0123456789+abcdefghijklmnopqrstuvwxyz | ||||||
|     AAAAAAAAAAAAAAAAAAAA |     AAAAAAAAAAAAAAAAAAAA | ||||||
|     -----END CERTIFICATE----- |     -----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.SpamFilterConfiguration; | ||||||
| import org.whispersystems.textsecuregcm.configuration.StripeConfiguration; | import org.whispersystems.textsecuregcm.configuration.StripeConfiguration; | ||||||
| import org.whispersystems.textsecuregcm.configuration.SubscriptionConfiguration; | import org.whispersystems.textsecuregcm.configuration.SubscriptionConfiguration; | ||||||
|  | import org.whispersystems.textsecuregcm.configuration.TurnSecretConfiguration; | ||||||
| import org.whispersystems.textsecuregcm.configuration.UnidentifiedDeliveryConfiguration; | import org.whispersystems.textsecuregcm.configuration.UnidentifiedDeliveryConfiguration; | ||||||
| import org.whispersystems.textsecuregcm.configuration.ZkConfig; | import org.whispersystems.textsecuregcm.configuration.ZkConfig; | ||||||
| import org.whispersystems.textsecuregcm.limits.RateLimiterConfig; | import org.whispersystems.textsecuregcm.limits.RateLimiterConfig; | ||||||
|  | @ -264,6 +265,11 @@ public class WhisperServerConfiguration extends Configuration { | ||||||
|   @JsonProperty |   @JsonProperty | ||||||
|   private RegistrationServiceConfiguration registrationService; |   private RegistrationServiceConfiguration registrationService; | ||||||
| 
 | 
 | ||||||
|  |   @Valid | ||||||
|  |   @NotNull | ||||||
|  |   @JsonProperty | ||||||
|  |   private TurnSecretConfiguration turn; | ||||||
|  | 
 | ||||||
|   public AdminEventLoggingConfiguration getAdminEventLoggingConfiguration() { |   public AdminEventLoggingConfiguration getAdminEventLoggingConfiguration() { | ||||||
|     return adminEventLoggingConfiguration; |     return adminEventLoggingConfiguration; | ||||||
|   } |   } | ||||||
|  | @ -438,4 +444,8 @@ public class WhisperServerConfiguration extends Configuration { | ||||||
|   public RegistrationServiceConfiguration getRegistrationServiceConfiguration() { |   public RegistrationServiceConfiguration getRegistrationServiceConfiguration() { | ||||||
|     return registrationService; |     return registrationService; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   public TurnSecretConfiguration getTurnSecretConfiguration() { | ||||||
|  |     return turn; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -554,7 +554,8 @@ public class WhisperServerService extends Application<WhisperServerConfiguration | ||||||
|         pushNotificationManager, |         pushNotificationManager, | ||||||
|         pushLatencyManager); |         pushLatencyManager); | ||||||
|     final ReceiptSender receiptSender = new ReceiptSender(accountsManager, messageSender, receiptSenderExecutor); |     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( |     RecaptchaClient recaptchaClient = new RecaptchaClient( | ||||||
|         config.getRecaptchaConfiguration().projectPath(), |         config.getRecaptchaConfiguration().projectPath(), | ||||||
|  |  | ||||||
|  | @ -26,39 +26,44 @@ import java.util.Optional; | ||||||
| 
 | 
 | ||||||
| public class TurnTokenGenerator { | public class TurnTokenGenerator { | ||||||
| 
 | 
 | ||||||
|   private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfiguration; |   private final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager; | ||||||
|  | 
 | ||||||
|  |   private final byte[] turnSecret; | ||||||
| 
 | 
 | ||||||
|   private static final String ALGORITHM = "HmacSHA1"; |   private static final String ALGORITHM = "HmacSHA1"; | ||||||
| 
 | 
 | ||||||
|   public TurnTokenGenerator(final DynamicConfigurationManager<DynamicConfiguration> config) { |   public TurnTokenGenerator(final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager, | ||||||
|     this.dynamicConfiguration = config; |       final byte[] turnSecret) { | ||||||
|  | 
 | ||||||
|  |     this.dynamicConfigurationManager = dynamicConfigurationManager; | ||||||
|  |     this.turnSecret = turnSecret; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public TurnToken generate(final String e164) { |   public TurnToken generate(final String e164) { | ||||||
|     try { |     try { | ||||||
|       final byte[] key = dynamicConfiguration.getConfiguration().getTurnConfiguration().getSecret().getBytes(); |  | ||||||
|       final List<String> urls = urls(e164); |       final List<String> urls = urls(e164); | ||||||
|       final Mac mac = Mac.getInstance(ALGORITHM); |       final Mac mac = Mac.getInstance(ALGORITHM); | ||||||
|       final long validUntilSeconds = Instant.now().plus(Duration.ofDays(1)).getEpochSecond(); |       final long validUntilSeconds = Instant.now().plus(Duration.ofDays(1)).getEpochSecond(); | ||||||
|       final long user = Util.ensureNonNegativeInt(new SecureRandom().nextInt()); |       final long user = Util.ensureNonNegativeInt(new SecureRandom().nextInt()); | ||||||
|       final String userTime = validUntilSeconds + ":" + user; |       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())); |       final String password = Base64.getEncoder().encodeToString(mac.doFinal(userTime.getBytes())); | ||||||
| 
 | 
 | ||||||
|       return new TurnToken(userTime, password, urls); |       return new TurnToken(userTime, password, urls); | ||||||
|     } catch (NoSuchAlgorithmException | InvalidKeyException e) { |     } catch (final NoSuchAlgorithmException | InvalidKeyException e) { | ||||||
|       throw new AssertionError(e); |       throw new AssertionError(e); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private List<String> urls(final String e164) { |   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 |     // Check if number is enrolled to test out specific turn servers | ||||||
|     final Optional<TurnUriConfiguration> enrolled = turnConfig.getUriConfigs().stream() |     final Optional<TurnUriConfiguration> enrolled = turnConfig.getUriConfigs().stream() | ||||||
|         .filter(config -> config.getEnrolledNumbers().contains(e164)) |         .filter(config -> config.getEnrolledNumbers().contains(e164)) | ||||||
|         .findFirst(); |         .findFirst(); | ||||||
|  | 
 | ||||||
|     if (enrolled.isPresent()) { |     if (enrolled.isPresent()) { | ||||||
|       return enrolled.get().getUris(); |       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 { | public class DynamicTurnConfiguration { | ||||||
| 
 | 
 | ||||||
|   @JsonProperty |  | ||||||
|   private String secret; |  | ||||||
| 
 |  | ||||||
|   @JsonProperty |   @JsonProperty | ||||||
|   private List<@Valid TurnUriConfiguration> uriConfigs = Collections.emptyList(); |   private List<@Valid TurnUriConfiguration> uriConfigs = Collections.emptyList(); | ||||||
| 
 | 
 | ||||||
|   public List<TurnUriConfiguration> getUriConfigs() { |   public List<TurnUriConfiguration> getUriConfigs() { | ||||||
|     return uriConfigs; |     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.configuration.dynamic.DynamicConfiguration; | ||||||
| import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; | ||||||
| 
 | 
 | ||||||
|  | import java.nio.charset.StandardCharsets; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| import java.util.stream.Stream; | import java.util.stream.Stream; | ||||||
|  | @ -21,7 +22,6 @@ public class TurnTokenGeneratorTest { | ||||||
|         captcha: |         captcha: | ||||||
|           scoreFloor: 1.0 |           scoreFloor: 1.0 | ||||||
|         turn: |         turn: | ||||||
|           secret: bloop |  | ||||||
|           uriConfigs: |           uriConfigs: | ||||||
|             - uris: |             - uris: | ||||||
|                 - always1.org |                 - always1.org | ||||||
|  | @ -39,7 +39,9 @@ public class TurnTokenGeneratorTest { | ||||||
|         DynamicConfigurationManager.class); |         DynamicConfigurationManager.class); | ||||||
| 
 | 
 | ||||||
|     when(mockDynamicConfigManager.getConfiguration()).thenReturn(config); |     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; |     final long COUNT = 1000; | ||||||
| 
 | 
 | ||||||
|  | @ -60,7 +62,6 @@ public class TurnTokenGeneratorTest { | ||||||
|         captcha: |         captcha: | ||||||
|           scoreFloor: 1.0 |           scoreFloor: 1.0 | ||||||
|         turn: |         turn: | ||||||
|           secret: bloop |  | ||||||
|           uriConfigs: |           uriConfigs: | ||||||
|             - uris: |             - uris: | ||||||
|                 - always.org |                 - always.org | ||||||
|  | @ -80,7 +81,8 @@ public class TurnTokenGeneratorTest { | ||||||
|         DynamicConfigurationManager.class); |         DynamicConfigurationManager.class); | ||||||
| 
 | 
 | ||||||
|     when(mockDynamicConfigManager.getConfiguration()).thenReturn(config); |     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; |     final long COUNT = 1000; | ||||||
| 
 | 
 | ||||||
|  | @ -122,7 +124,9 @@ public class TurnTokenGeneratorTest { | ||||||
| 
 | 
 | ||||||
|     when(mockDynamicConfigManager.getConfiguration()).thenReturn(config); |     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"); |     TurnToken token = turnTokenGenerator.generate("+15555555555"); | ||||||
|     assertThat(token.getUrls().get(0)).isEqualTo("enrolled.org"); |     assertThat(token.getUrls().get(0)).isEqualTo("enrolled.org"); | ||||||
|     token = turnTokenGenerator.generate("+15555555556"); |     token = turnTokenGenerator.generate("+15555555556"); | ||||||
|  |  | ||||||
|  | @ -329,7 +329,6 @@ class DynamicConfigurationTest { | ||||||
|     { |     { | ||||||
|       final String config = REQUIRED_CONFIG.concat(""" |       final String config = REQUIRED_CONFIG.concat(""" | ||||||
|           turn: |           turn: | ||||||
|             secret: bloop |  | ||||||
|             uriConfigs: |             uriConfigs: | ||||||
|                 - uris: |                 - uris: | ||||||
|                     - turn:test0.org |                     - turn:test0.org | ||||||
|  | @ -344,7 +343,6 @@ class DynamicConfigurationTest { | ||||||
|           .parseConfiguration(config, DynamicConfiguration.class) |           .parseConfiguration(config, DynamicConfiguration.class) | ||||||
|           .orElseThrow() |           .orElseThrow() | ||||||
|           .getTurnConfiguration(); |           .getTurnConfiguration(); | ||||||
|       assertThat(turnConfiguration.getSecret()).isEqualTo("bloop"); |  | ||||||
|       assertThat(turnConfiguration.getUriConfigs().get(0).getUris()).hasSize(2); |       assertThat(turnConfiguration.getUriConfigs().get(0).getUris()).hasSize(2); | ||||||
|       assertThat(turnConfiguration.getUriConfigs().get(1).getUris()).hasSize(1); |       assertThat(turnConfiguration.getUriConfigs().get(1).getUris()).hasSize(1); | ||||||
|       assertThat(turnConfiguration.getUriConfigs().get(0).getWeight()).isEqualTo(1); |       assertThat(turnConfiguration.getUriConfigs().get(0).getWeight()).isEqualTo(1); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Jon Chambers
						Jon Chambers