spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.19k stars 40.69k forks source link

Make it easier to provide custom TrustManagers in SslManagerBundle #43064

Open ttddyy opened 4 days ago

ttddyy commented 4 days ago

I would like to use a custom TrustManager, such as one that only accepts certain issuers, accept-all, etc.

With current SslManagerBundle, I need to write something like this to use a custom TrustManager:


TrustManager myTrustManager = ...

// Cannot use DefaultSslManagerBundle as it's package private
KeyManagerFactory keyManagerFactory = getDefaultKeyManagerFactory();
// using netty impl
TrustManagerFactory trustManagerFactory = new TrustManagerFactoryWrapper(myTrustManager);

SslManagerBundle sslManagerBundle = SslManagerBundle.of(keyManagerFactory, trustManagerFactory);
SslBundle sslBundle = SslBundle.of(SslStoreBundle.NONE, SslBundleKey.NONE, SslOptions.NONE,
        SslBundle.DEFAULT_PROTOCOL, sslManagerBundle);
...

private KeyManagerFactory getDefaultKeyManagerFactory() {
    String algorithm = KeyManagerFactory.getDefaultAlgorithm();
    try {
        return KeyManagerFactory.getInstance(algorithm);
    }
    catch (NoSuchAlgorithmException ex) {
        throw new IllegalStateException("Could not load key manager factory: " + ex.getMessage(), ex);
    }
}

This is a lot of boilerplate code just to use a custom TrustManager.

It would be great if the SslManagerBundle API could be improved to support custom TrustManager usage without requiring a KeyManagerFactory. This would simplify configuring SSL/TLS settings when custom TrustManager configurations are needed.

mhalbritter commented 4 days ago

So, something like this on SslManagerBundle?

    /**
     * Factory method to create a new {@link SslManagerBundle} using the given
     * {@link TrustManagerFactory} and the default {@link KeyManagerFactory}.
     * @param trustManagerFactory the trust manager factory
     * @return a new {@link SslManagerBundle} instance
     * @since 3.5.0
     */
    static SslManagerBundle from(TrustManagerFactory trustManagerFactory) {
        Assert.notNull(trustManagerFactory, "TrustManagerFactory must not be null");
        KeyManagerFactory defaultKeyManagerFactory = createDefaultKeyManagerFactory();
        return of(defaultKeyManagerFactory, trustManagerFactory);
    }

    /**
     * Factory method to create a new {@link SslManagerBundle} using the given
     * {@link TrustManager TrustManagers} and the default {@link KeyManagerFactory}.
     * @param trustManagers the trust managers to use
     * @return a new {@link SslManagerBundle} instance
     * @since 3.5.0
     */
    static SslManagerBundle from(TrustManager... trustManagers) {
        Assert.notNull(trustManagers, "TrustManagers must not be null");
        KeyManagerFactory defaultKeyManagerFactory = createDefaultKeyManagerFactory();
        TrustManagerFactory defaultTrustManagerFactory = createDefaultTrustManagerFactory();
        return of(defaultKeyManagerFactory, FixedTrustManagerFactory.of(defaultTrustManagerFactory, trustManagers));
    }

The FixedTrustManagerFactory just returns the given TrustManagers on the getTrustManagers call.

You can then invoke it like this:

SslBundle bundle = SslBundle.of(SslStoreBundle.NONE, SslBundleKey.NONE, SslOptions.NONE, SslBundle.DEFAULT_PROTOCOL, SslManagerBundle.from(myTrustManager));

You can play around with it here: https://github.com/mhalbritter/spring-boot/tree/mh/43064-provide-user-friendly-api-to-use-custom-trustmanager-in-ssl-manager-bundle

ttddyy commented 3 days ago

Thanks @mhalbritter It looks great and makes it easy to set up a SslBundle with custom TrustManagers.