Open syedyusufh opened 6 months ago
If you need to work with self-signed certificates or for testing purposes, consider using an InsecureTrustManagerFactory. This involves creating a custom SSLContext with an InsecureTrustManager and setting it as the default for your HTTPS connections.
For the Custom manager Factory you have the scenarios where you have specific truststore requirements, create a custom SSLContext with a TrustManagerFactory initialized with your custom truststore. Ensure that you load your truststore appropriately and initialize the SSLContext with the custom trust manager.
@Nikunj2788 ask is how to do the same via Ssl Bundles. Thanks
@syedyusufh if you're interacting with a server that uses a self-signed certificate, have you considered trusting that certificate alone on the client-side? That, I think, would be the SSL bundle way of doing things. If you want the client to trust all self-signed certificates or to skip hostname verification, that should be done with client-specific configuration and not through SSL bundles.
@wilkinsona thanks for your comments.
My understanding is that Ssl Bundle manages the trustStore, trustStrategy, etc as part of the Ssl Bundle configuration via application.properties
. How do we alter the trust strategy of the Ssl Bundle managed TrustStore still benefiting from the Ssl Bundle benefits?
In other words, how can I construct a full beneficial Ssl Bundle of my underlying JKS with trustStore, trustStrategy programmatically?
Thanks
I don't think I understand why you need both. You can configure an SSL bundle that trusts the server's unsigned certificates or you can configure whatever HTTP client you're using to use an insecure trust manager. Doing one of these negates the need for the other, does it not?
Let us please consider the below sample from Spring.io Blog on how to setup SSL for WebClient
via Ssl Bundle,
@Service
public class MyService {
private final WebClient webClient;
public MyService(WebClient.Builder webClientBuilder, WebClientSsl ssl) {
this.webClient = webClientBuilder.baseUrl("https://example.org").apply(ssl.fromBundle("mybundle")).build();
}
}
How do we now configure the underlying (WebClientSsl
) TrustStore to ignore hostNameVerification
? We were able to do the same without Ssl Bundle by configuring SslContext, TrustManagerFactory, KeyManagerFactory like below.
// Create an SSL context that uses that certificate
return SslContextBuilder.forClient()
.keyManager(keyManagerFactory)
.build();
I agree with Andy's statement above:
If you want the client to trust all self-signed certificates or to skip hostname verification, that should be done with client-specific configuration and not through SSL bundles.
Disabling hostname verification is a very dangerous thing to do. It might be useful for testing sometimes, but I don't think Spring Boot should do anything more to make this easy to do so that user's don't mistakenly disable verification in production applications.
We were able to do the same without Ssl Bundle by configuring SslContext, TrustManagerFactory, KeyManagerFactory like below.
One option would be to keep your code that sets up the SSLContext
manually, but retrieve the trust material from a configured SSL bundle. To do this, you'd need to auto-wire an instance of SslBundles
into your code, retrieve the bundle you want using SslBundles.getBundle(String name)
. Once you get an SslBundle
from SslBundles
, you can use SslBundle.getManagers()
to get any KeyManagerFactory
and TrustManagerFactory
instances you need to configure the SSLContext
.
Hi @scottfrederick thanks for your inputs.
Like any enterprise we have both modern and legacy systems, so the custom TrustStrategy
is a much needed one. The default SSL behavior out-of-box does NOT fit every system :(
Ssl Bundles
solve the problem of application restart to update the application's Ssl Context
due to the underlying certificate change and this is an awesome feature in a Microservices environment where multiple applications are run.
but I don't think Spring Boot should do anything more to make this easy to do so that user's don't mistakenly disable verification in production applications.
Spring Boot framework today provides options to configure your own TrustStrategy
when setting up the SSL either via Apache Http
or Netty
implementations. For instance, we have out of framework implementations like InSecureTrustManagerFactory
though with a warning and a disclaimer.
Once you get an SslBundle from SslBundles, you can use SslBundle.getManagers() to get any KeyManagerFactory and TrustManagerFactory instances you need to configure the SSLContext
Can we get the Ssl Bundle benefit of dynamic reloading of Ssl Context if the framework managed KeyManagerFactory
and TrustManagerFactory
are overridden?
Thanks
@syedyusufh I'm afraid it's still not completely clear what you're trying to accomplish. It seems that you are mostly concerned with configuring SSL for client connections. Reloading of SSL material with SSL bundles is only supported for server-side connections when using Tomcat or Netty as an embedded web server, so your questions about reloading the SSL context would not apply to your client connections.
I think we would make more progress on this discussion if we had a small code sample of what you are doing now. Can you provide a complete minimal application that demonstrates your use case, and share it with us by pushing it to a separate repository on GitHub or by zipping it and attaching it to this issue? That would make it much easier for us to see if there's anything we can add to our APIs for custom configuration of client connections.
Reloading of SSL material with SSL bundles is only supported for server-side connections when using Tomcat or Netty as an embedded web server, so your questions about reloading the SSL context would not apply to your client connections
I got it now. Sorry, I was with the impression Ssl Bundle
applicable components are all reloadable by default.
Kindly consider allowing an option to customize the TrustStrategy
for client connections when we use Ssl Bundles
Thanks
@syedyusufh i'm a bit late to the party, but i had a similar situation i think where i needed to connect to a https server. I needed to provide client cert to connect to the server and needed to accept the server's self signed cert.
It wasn't possible to customize the SSLBundle trustmanagers / trustmanagerfactory so i ended up using the SSLBundle only to load the keys from the files. I didn't use it to build my RestTemplate and initialized the SSLContext with the SSLBundle's KeyManager[].
So, instead of:
SslBundle sslBundle = sslBundles.getBundle("rest");
return builder
.setSslBundle(sslBundle)
.messageConverters(converters)
.build();
i did:
SslBundle sslBundle = sslBundles.getBundle("rest");
KeyManager[] keyManagers = sslBundle.getManagers().getKeyManagers();
SslUtils.configureDefaultSslSockerFactory(keyManagers);
return builder
.messageConverters(converters)
.build();
with SSLUtils:
public class SslUtils {
public static TrustManager[] trustAllCerts() {
return new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs,
String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs,
String authType) {
}
}
};
}
public static void configureDefaultSslSockerFactory(KeyManager[] keyManagers) {
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(keyManagers, trustAllCerts(), new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
}
How do we configure the Ssl Bundle to use InsecureTrustManagerFactory or custom TrustManagerFactory or skip hostname verification? Couldn't find these details in the documentation. Thanks