Add `enabled` to SVR2 configuration
This commit is contained in:
		
							parent
							
								
									4fa08fb189
								
							
						
					
					
						commit
						0cc84131de
					
				|  | @ -146,6 +146,7 @@ directoryV2: | |||
|     userIdTokenSharedSecret: bbcdefghijklmnopqrstuvwxyz0123456789ABCDEFG= # base64-encoded secret shared with CDS to generate auth identity tokens for Signal users | ||||
| 
 | ||||
| svr2: | ||||
|   enabled: false | ||||
|   uri: svr2.example.com | ||||
|   userAuthenticationTokenSharedSecret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG= # base64-encoded secret shared with SVR2 to generate auth tokens for Signal users | ||||
|   userIdTokenSharedSecret: bbcdefghijklmnopqrstuvwxyz0123456789ABCDEFG= # base64-encoded secret shared with SVR2 to generate auth identity tokens for Signal users | ||||
|  |  | |||
|  | @ -796,7 +796,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration | |||
|             config.getRemoteConfigConfiguration().getGlobalConfig()), | ||||
|         new SecureBackupController(backupCredentialsGenerator, accountsManager), | ||||
|         new SecureStorageController(storageCredentialsGenerator), | ||||
|         new SecureValueRecovery2Controller(svr2CredentialsGenerator), | ||||
|         new SecureValueRecovery2Controller(svr2CredentialsGenerator, config.getSvr2Configuration()), | ||||
|         new StickerController(rateLimiters, config.getCdnConfiguration().getAccessKey(), | ||||
|             config.getCdnConfiguration().getAccessSecret(), config.getCdnConfiguration().getRegion(), | ||||
|             config.getCdnConfiguration().getBucket()), | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| /* | ||||
|  * Copyright 2013-2020 Signal Messenger, LLC | ||||
|  * Copyright 2023 Signal Messenger, LLC | ||||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
| package org.whispersystems.textsecuregcm.configuration; | ||||
|  | @ -12,9 +12,10 @@ import javax.validation.constraints.NotNull; | |||
| import org.whispersystems.textsecuregcm.util.ExactlySize; | ||||
| 
 | ||||
| public record SecureValueRecovery2Configuration( | ||||
|     boolean enabled, | ||||
|     @NotBlank String uri, | ||||
|     @ExactlySize({32}) byte[] userAuthenticationTokenSharedSecret, | ||||
|     @ExactlySize({32}) byte[] userIdTokenSharedSecret, | ||||
|     @NotBlank String uri, | ||||
|     @NotEmpty List<@NotBlank String> svrCaCertificates, | ||||
|     @NotNull @Valid CircuitBreakerConfiguration circuitBreaker, | ||||
|     @NotNull @Valid RetryConfiguration retry) { | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.Operation; | |||
| import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||||
| import javax.ws.rs.GET; | ||||
| import javax.ws.rs.NotFoundException; | ||||
| import javax.ws.rs.Path; | ||||
| import javax.ws.rs.Produces; | ||||
| import javax.ws.rs.core.MediaType; | ||||
|  | @ -32,9 +33,12 @@ public class SecureValueRecovery2Controller { | |||
|   } | ||||
| 
 | ||||
|   private final ExternalServiceCredentialsGenerator backupServiceCredentialGenerator; | ||||
|   private final boolean enabled; | ||||
| 
 | ||||
|   public SecureValueRecovery2Controller(final ExternalServiceCredentialsGenerator backupServiceCredentialGenerator) { | ||||
|   public SecureValueRecovery2Controller(final ExternalServiceCredentialsGenerator backupServiceCredentialGenerator, | ||||
|       final SecureValueRecovery2Configuration cfg) { | ||||
|     this.backupServiceCredentialGenerator = backupServiceCredentialGenerator; | ||||
|     this.enabled = cfg.enabled(); | ||||
|   } | ||||
| 
 | ||||
|   @Timed | ||||
|  | @ -51,6 +55,9 @@ public class SecureValueRecovery2Controller { | |||
|   @ApiResponse(responseCode = "200", description = "`JSON` with generated credentials.", useReturnTypeSchema = true) | ||||
|   @ApiResponse(responseCode = "401", description = "Account authentication check failed.") | ||||
|   public ExternalServiceCredentials getAuth(@Auth final AuthenticatedAccount auth) { | ||||
|     if (!enabled) { | ||||
|       throw new NotFoundException(); | ||||
|     } | ||||
|     return backupServiceCredentialGenerator.generateFor(auth.getAccount().getUuid().toString()); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ public class SecureValueRecovery2Client { | |||
|   private final ExternalServiceCredentialsGenerator secureValueRecoveryCredentialsGenerator; | ||||
|   private final URI deleteUri; | ||||
|   private final FaultTolerantHttpClient httpClient; | ||||
|   private final boolean enabled; | ||||
| 
 | ||||
|   @VisibleForTesting | ||||
|   static final String DELETE_PATH = "/v1/delete"; | ||||
|  | @ -52,9 +53,15 @@ public class SecureValueRecovery2Client { | |||
|         .withSecurityProtocol(FaultTolerantHttpClient.SECURITY_PROTOCOL_TLS_1_2) | ||||
|         .withTrustedServerCertificates(configuration.svrCaCertificates().toArray(new String[0])) | ||||
|         .build(); | ||||
|     this.enabled = configuration.enabled(); | ||||
|   } | ||||
| 
 | ||||
|   public CompletableFuture<Void> deleteBackups(final UUID accountUuid) { | ||||
| 
 | ||||
|     if (!enabled) { | ||||
|       return CompletableFuture.completedFuture(null); | ||||
|     } | ||||
| 
 | ||||
|     final ExternalServiceCredentials credentials = secureValueRecoveryCredentialsGenerator.generateForUuid(accountUuid); | ||||
| 
 | ||||
|     final HttpRequest request = HttpRequest.newBuilder() | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| /* | ||||
|  * Copyright 2021 Signal Messenger, LLC | ||||
|  * Copyright 2023 Signal Messenger, LLC | ||||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; | |||
| import static com.github.tomakehurst.wiremock.client.WireMock.delete; | ||||
| import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; | ||||
| import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; | ||||
| import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; | ||||
| import static org.junit.jupiter.api.Assertions.assertThrows; | ||||
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
| import static org.mockito.Mockito.mock; | ||||
|  | @ -50,8 +51,11 @@ class SecureValueRecovery2ClientTest { | |||
|     credentialsGenerator = mock(ExternalServiceCredentialsGenerator.class); | ||||
|     httpExecutor = Executors.newSingleThreadExecutor(); | ||||
| 
 | ||||
|     final SecureValueRecovery2Configuration config = new SecureValueRecovery2Configuration(new byte[0], new byte[0], | ||||
|         "http://localhost:" + wireMock.getPort(), List.of(""" | ||||
|     final SecureValueRecovery2Configuration config = new SecureValueRecovery2Configuration(true, | ||||
|         "http://localhost:" + wireMock.getPort(), | ||||
|         new byte[0], new byte[0], | ||||
|         // This is a randomly-generated, throwaway certificate that's not actually connected to anything | ||||
|         List.of(""" | ||||
|             -----BEGIN CERTIFICATE----- | ||||
|             MIICZDCCAc2gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBPMQswCQYDVQQGEwJ1czEL | ||||
|             MAkGA1UECAwCVVMxHjAcBgNVBAoMFVNpZ25hbCBNZXNzZW5nZXIsIExMQzETMBEG | ||||
|  | @ -67,8 +71,7 @@ class SecureValueRecovery2ClientTest { | |||
|             y7MTM4NoBV1k0zb5LAk89SIDPr/maW5AsLtEomzjnEiomjoMBUdNe3YCgQReoLnr | ||||
|             R/QaUNbrCjTGYfBsjGbIzmkWPUyTec2ZdRyJ8JiVl386+6CZkxnndQ== | ||||
|             -----END CERTIFICATE----- | ||||
|             """, | ||||
|         """ | ||||
|             """, """ | ||||
|             -----BEGIN CERTIFICATE----- | ||||
|             MIIEpDCCAowCCQC43PUTWSADVjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls | ||||
|             b2NhbGhvc3QwHhcNMjIxMDE3MjA0NTM0WhcNMjMxMDE3MjA0NTM0WjAUMRIwEAYD | ||||
|  | @ -96,7 +99,8 @@ class SecureValueRecovery2ClientTest { | |||
|             WIOjZOKGW690ESKCKOnFjUHVO0HpuWnT81URTuY62FXsYdVc2wE4v0E04mEbqQ0P | ||||
|             lY6ZKNA81Lm3YADYtObmK1IUrOPo9BeIaPy0UM08SmN880Vunqa91Q== | ||||
|             -----END CERTIFICATE----- | ||||
|             """), null, null); | ||||
|             """), | ||||
|         null, null); | ||||
| 
 | ||||
|     secureValueRecovery2Client = new SecureValueRecovery2Client(credentialsGenerator, httpExecutor, config); | ||||
|   } | ||||
|  | @ -119,8 +123,7 @@ class SecureValueRecovery2ClientTest { | |||
|         .withBasicAuth(username, password) | ||||
|         .willReturn(aResponse().withStatus(202))); | ||||
| 
 | ||||
|     // We're happy as long as this doesn't throw an exception | ||||
|     secureValueRecovery2Client.deleteBackups(accountUuid).join(); | ||||
|     assertDoesNotThrow(() -> secureValueRecovery2Client.deleteBackups(accountUuid).join()); | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Chris Eager
						Chris Eager