Last active
July 7, 2023 08:37
-
-
Save ex0b1t/563bd016805fb3862565fa94014d0afb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.railway.security; | |
import com.google.common.collect.ImmutableList; | |
import com.google.common.collect.Iterables; | |
import lombok.extern.slf4j.Slf4j; | |
import javax.net.ssl.TrustManager; | |
import javax.net.ssl.TrustManagerFactory; | |
import javax.net.ssl.X509TrustManager; | |
import java.security.KeyStore; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.cert.CertificateException; | |
import java.security.cert.X509Certificate; | |
import java.util.Arrays; | |
import java.util.List; | |
/** | |
* CompositeX509TrustManager | |
* <p> | |
* Only needed as our trust store only ships with with 6 custom trusted certs, java default ships with 95, we need more! | |
* <br> | |
* <code>com.railway.security.CompositeX509TrustManager</code> | |
* <br> | |
* | |
* @since 03 July 2020 | |
*/ | |
@Slf4j | |
public class CompositeX509TrustManager implements X509TrustManager { | |
private final List<X509TrustManager> trustManagers; | |
public CompositeX509TrustManager(List<X509TrustManager> trustManagers) { | |
this.trustManagers = ImmutableList.copyOf(trustManagers); | |
} | |
public CompositeX509TrustManager(KeyStore keystore) { | |
this.trustManagers = ImmutableList.of(getDefaultTrustManager(), getTrustManager(keystore)); | |
} | |
@Override | |
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |
for (X509TrustManager trustManager : trustManagers) { | |
try { | |
trustManager.checkClientTrusted(chain, authType); | |
return; // someone trusts them. success! | |
} catch (CertificateException e) { | |
// maybe someone else will trust them | |
} | |
} | |
throw new CertificateException("None of the TrustManagers trust this certificate chain"); | |
} | |
@Override | |
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { | |
for (X509TrustManager trustManager : trustManagers) { | |
try { | |
trustManager.checkServerTrusted(chain, authType); | |
return; // someone trusts them. success! | |
} catch (CertificateException e) { | |
// maybe someone else will trust them | |
} | |
} | |
throw new CertificateException("None of the TrustManagers trust this certificate chain"); | |
} | |
@Override | |
public X509Certificate[] getAcceptedIssuers() { | |
ImmutableList.Builder<X509Certificate> certificates = ImmutableList.builder(); | |
for (X509TrustManager trustManager : trustManagers) { | |
for (X509Certificate cert : trustManager.getAcceptedIssuers()) { | |
certificates.add(cert); | |
} | |
} | |
return Iterables.toArray(certificates.build(), X509Certificate.class); | |
} | |
public static TrustManager[] getTrustManagers(KeyStore keyStore) { | |
return new TrustManager[]{new CompositeX509TrustManager(keyStore)}; | |
} | |
public static X509TrustManager getDefaultTrustManager() { | |
return getTrustManager(null); | |
} | |
public static X509TrustManager getTrustManager(KeyStore keystore) { | |
return getTrustManager(TrustManagerFactory.getDefaultAlgorithm(), keystore); | |
} | |
public static X509TrustManager getTrustManager(String algorithm, KeyStore keystore) { | |
TrustManagerFactory factory; | |
try { | |
factory = TrustManagerFactory.getInstance(algorithm); | |
factory.init(keystore); | |
return Iterables.getFirst(Iterables.filter( | |
Arrays.asList(factory.getTrustManagers()), X509TrustManager.class), null); | |
} catch (NoSuchAlgorithmException | KeyStoreException e) { | |
log.error("Failed to get trust manager", e); | |
} | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Bean("trustManager") | |
Supplier<CompositeX509TrustManager> trustManagerSupplier(ServerProperties serverProperties) { | |
return () -> { | |
log.info("Autoconfigure: trustManagerSupplier"); | |
CompositeX509TrustManager compositeX509TrustManager; | |
Ssl ssl = serverProperties.getSsl(); | |
if (ssl != null && ssl.isEnabled() && ssl.getTrustStore() != null) { | |
log.info("Creating CompositeX509TrustManager"); | |
char[] trustStorePassword = Optional.ofNullable(ssl.getTrustStorePassword()) | |
.orElse("") | |
.toCharArray(); | |
try { | |
File truststoreFile = ResourceUtils.getFile(ssl.getTrustStore()); | |
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); | |
FileInputStream myKeys = new FileInputStream(truststoreFile); | |
keyStore.load(myKeys, trustStorePassword); | |
myKeys.close(); | |
compositeX509TrustManager = new CompositeX509TrustManager(keyStore); | |
} catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException e) { | |
log.error("Failed to create CompositeX509TrustManager", e); | |
compositeX509TrustManager = null; | |
} | |
} else { | |
log.debug("No SSL CompositeX509TrustManager, returning null"); | |
compositeX509TrustManager = null; | |
} | |
return compositeX509TrustManager; | |
}; | |
} | |
@Bean("sslContextSupplier") | |
Supplier<SSLContext> sslContextSupplier(Supplier<CompositeX509TrustManager> trustManagerSupplier) { | |
return () -> { | |
log.info("Autoconfigure: sslContextSupplier"); | |
SSLContext sslContext; | |
if (trustManagerSupplier.get() != null) { | |
try { | |
log.info("Creating creating ssl context"); | |
sslContext = SSLContext.getInstance("TLS"); | |
TrustManager[] tm = {trustManagerSupplier.get()}; | |
sslContext.init(null, tm, null); | |
} catch (NoSuchAlgorithmException | KeyManagementException e) { | |
log.error("Failed to create ssl context", e); | |
sslContext = null; | |
} | |
} else { | |
log.debug("No SSL context setup, returning null"); | |
sslContext = null; | |
} | |
return sslContext; | |
}; | |
} | |
@Bean("restTemplate") | |
RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) { | |
log.info("Autoconfigure: restTemplate"); | |
return new RestTemplate(clientHttpRequestFactory); | |
} | |
@Bean("clientHttpRequestFactory") | |
ClientHttpRequestFactory clientHttpRequestFactory(Supplier<SSLContext> sslContextSupplier) { | |
log.info("Autoconfigure: ClientHttpRequestFactory"); | |
return Optional.ofNullable(sslContextSupplier.get()) | |
.map(sslContext -> { | |
log.info("Enabling SSL ClientHttpRequestFactory"); | |
final CloseableHttpClient httpClient = HttpClientBuilder.create() | |
.setSSLContext(sslContext) | |
.build(); | |
return new HttpComponentsClientHttpRequestFactory(httpClient); | |
}) | |
.orElseGet(() -> { | |
log.warn("Enabling ClientHttpRequestFactory with No SSL"); | |
return new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build()); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment