Allow HTTP clients to trust multiple certificates to support certificate rollover

This commit is contained in:
Jon Chambers
2022-10-17 14:47:39 -04:00
committed by Jon Chambers
parent a41d047f58
commit 0120a85c39
9 changed files with 154 additions and 86 deletions

View File

@@ -13,6 +13,7 @@ import javax.validation.constraints.NotNull;
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import java.util.List;
public class SecureBackupServiceConfiguration {
@@ -24,9 +25,9 @@ public class SecureBackupServiceConfiguration {
@JsonProperty
private String uri;
@NotBlank
@NotEmpty
@JsonProperty
private String backupCaCertificate;
private List<@NotBlank String> backupCaCertificates;
@NotNull
@Valid
@@ -52,12 +53,12 @@ public class SecureBackupServiceConfiguration {
}
@VisibleForTesting
public void setBackupCaCertificate(final String backupCaCertificate) {
this.backupCaCertificate = backupCaCertificate;
public void setBackupCaCertificates(final List<String> backupCaCertificates) {
this.backupCaCertificates = backupCaCertificates;
}
public String getBackupCaCertificate() {
return backupCaCertificate;
public List<String> getBackupCaCertificates() {
return backupCaCertificates;
}
public CircuitBreakerConfiguration getCircuitBreakerConfiguration() {

View File

@@ -13,6 +13,7 @@ import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import java.util.List;
public class SecureStorageServiceConfiguration {
@@ -24,9 +25,9 @@ public class SecureStorageServiceConfiguration {
@JsonProperty
private String uri;
@NotBlank
@NotEmpty
@JsonProperty
private String storageCaCertificate;
private List<@NotBlank String> storageCaCertificates;
@NotNull
@Valid
@@ -52,12 +53,12 @@ public class SecureStorageServiceConfiguration {
}
@VisibleForTesting
public void setStorageCaCertificate(final String certificatePem) {
this.storageCaCertificate = certificatePem;
public void setStorageCaCertificates(final List<String> certificatePem) {
this.storageCaCertificates = certificatePem;
}
public String getStorageCaCertificate() {
return storageCaCertificate;
public List<String> getStorageCaCertificates() {
return storageCaCertificates;
}
public CircuitBreakerConfiguration getCircuitBreakerConfiguration() {

View File

@@ -135,7 +135,7 @@ public class FaultTolerantHttpClient {
return this;
}
public Builder withTrustedServerCertificate(final String certificatePem) throws CertificateException {
public Builder withTrustedServerCertificates(final String... certificatePem) throws CertificateException {
this.trustStore = CertificateUtil.buildKeyStoreForPem(certificatePem);
return this;
}

View File

@@ -46,7 +46,7 @@ public class SecureBackupClient {
.withExecutor(executor)
.withName("secure-backup")
.withSecurityProtocol(FaultTolerantHttpClient.SECURITY_PROTOCOL_TLS_1_2)
.withTrustedServerCertificate(configuration.getBackupCaCertificate())
.withTrustedServerCertificates(configuration.getBackupCaCertificates().toArray(new String[0]))
.build();
}

View File

@@ -47,7 +47,7 @@ public class SecureStorageClient {
.withExecutor(executor)
.withName("secure-storage")
.withSecurityProtocol(FaultTolerantHttpClient.SECURITY_PROTOCOL_TLS_1_3)
.withTrustedServerCertificate(configuration.getStorageCaCertificate())
.withTrustedServerCertificates(configuration.getStorageCaCertificates().toArray(new String[0]))
.build();
}

View File

@@ -15,33 +15,37 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class CertificateUtil {
public static KeyStore buildKeyStoreForPem(final String caCertificatePem) throws CertificateException
{
try {
X509Certificate certificate = getCertificate(caCertificatePem);
if (certificate == null) {
throw new CertificateException("No certificate found in parsing!");
}
public static KeyStore buildKeyStoreForPem(final String... caCertificatePems) throws CertificateException {
try {
final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
keyStore.setCertificateEntry("ca", certificate);
return keyStore;
} catch (IOException | KeyStoreException ex) {
throw new CertificateException(ex);
} catch (NoSuchAlgorithmException ex) {
throw new AssertionError(ex);
for (int i = 0; i < caCertificatePems.length; i++) {
final X509Certificate certificate = getCertificate(caCertificatePems[i]);
if (certificate == null) {
throw new CertificateException("No certificate found in parsing!");
}
}
public static X509Certificate getCertificate(final String certificatePem) throws CertificateException {
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
keyStore.setCertificateEntry("ca-" + i, certificate);
}
try (final ByteArrayInputStream pemInputStream = new ByteArrayInputStream(certificatePem.getBytes())) {
return (X509Certificate) certificateFactory.generateCertificate(pemInputStream);
} catch (IOException e) {
throw new CertificateException(e);
}
return keyStore;
} catch (IOException | KeyStoreException ex) {
throw new CertificateException(ex);
} catch (NoSuchAlgorithmException ex) {
throw new AssertionError(ex);
}
}
public static X509Certificate getCertificate(final String certificatePem) throws CertificateException {
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
try (final ByteArrayInputStream pemInputStream = new ByteArrayInputStream(certificatePem.getBytes())) {
return (X509Certificate) certificateFactory.generateCertificate(pemInputStream);
} catch (IOException e) {
throw new CertificateException(e);
}
}
}