Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify usage of custom ssl configuration #706

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Hakky54
Copy link

@Hakky54 Hakky54 commented Mar 12, 2024

This PR is a followup of the following earlier PR #673 Although that pull request didn't get merged, the code changes has been comitted to the main branch by the main developer, see here for the specific commit: b0df981

Context
With the earlier commit it is now possible to programatically configure the ssl configuration of tomcat instead of using properties and delegating to tomcat to construct the ssl configuration. This opens the possibility of reloading the ssl configuration or other customizations as shown also here: sslcontext-kickstart

I want to provide an example with my own code to give a better understanding, the project is also available here: Instant SSL Reloading with Tomcat

SSLContext wrapper

import nl.altindag.ssl.SSLFactory;
import org.apache.tomcat.util.net.SSLContext;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.TrustManager;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

public final class TomcatSSLContext implements SSLContext {

    private final SSLFactory sslFactory;

    public TomcatSSLContext(SSLFactory sslFactory) {
        this.sslFactory = sslFactory;
    }

    @Override
    public void init(KeyManager[] kms, TrustManager[] tms, SecureRandom sr) {
        // not needed to initialize as it is already initialized
    }

    @Override
    public void destroy() {

    }

    @Override
    public SSLSessionContext getServerSessionContext() {
        return sslFactory.getSslContext().getServerSessionContext();
    }

    @Override
    public SSLEngine createSSLEngine() {
        return sslFactory.getSSLEngine();
    }

    @Override
    public SSLServerSocketFactory getServerSocketFactory() {
        return sslFactory.getSslServerSocketFactory();
    }

    @Override
    public SSLParameters getSupportedSSLParameters() {
        return sslFactory.getSslParameters();
    }

    @Override
    public X509Certificate[] getCertificateChain(String alias) {
        return sslFactory.getKeyManager()
                .map(keyManager -> keyManager.getCertificateChain(alias))
                .orElseThrow();
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return sslFactory.getTrustedCertificates().toArray(new X509Certificate[0]);
    }

}
import nl.altindag.ssl.SSLFactory;
import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
import org.apache.tomcat.util.net.SSLUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SSLConnectorCustomizer implements TomcatConnectorCustomizer {

    private final SSLFactory sslFactory;
    private final int port;

    public SSLConnectorCustomizer(SSLFactory sslFactory, @Value("${server.port}") int port) {
        this.sslFactory = sslFactory;
        this.port = port;
    }

    @Override
    public void customize(Connector connector) {
        connector.setScheme("https");
        connector.setSecure(true);
        connector.setPort(port);

        AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) connector.getProtocolHandler();
        protocol.setSSLEnabled(true);

        SSLHostConfig sslHostConfig = new SSLHostConfig();
        SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, Type.UNDEFINED);
        certificate.setSslContext(new TomcatSSLContext(sslFactory));
        sslHostConfig.addCertificate(certificate);
        protocol.addSslHostConfig(sslHostConfig);
    }

}

Problem statement
Boilerplate code is needed by the end-user to provide a custom ssl configuration. Tomcat takes a custom SSLContext, the full name is org.apache.tomcat.util.net.SSLContext while the end-user has javax.net.ssl.SSLContext. So the end-user is required to create an implementation of org.apache.tomcat.util.net.SSLContext which acts as a wrapper. This sslcontext needs to be passed to SSLHostConfigCertificate to further configure the server.

Solution
Provide a helper class which acts as a wrapper to reduce the boilerplate code. The utility interface is able to provide a method to wrap the required objects, in this case javax.net.ssl.SSLContext, KeyManager, TrustManager in a org.apache.tomcat.util.net.SSLContext

What do you think, would it be a nice addition to the code changes we did previously? It will atleast make it more developer friendlier. Looking forward to your feedback.

…e as an easy way to create a custom tomcat sslcontext
@Hakky54
Copy link
Author

Hakky54 commented Apr 11, 2024

Hi @markt-asf

What do you think of this PR, would it make sense to have this kind of wrapper, or does it needs to be adjusted or would you like me to close it and disregard it? Looking forward to get your feedback on this

@rmaucher
Copy link
Contributor

Your previous PR, which was integrated, unfortunately caused a very high number of regressions that had to be fixed over multiple Tomcat releases. This PR similarly seems uninteresting to me, so as a result I will not integrate it.

@Hakky54
Copy link
Author

Hakky54 commented Apr 11, 2024

Ah so your feeling is that this also might cause some regression while this wrapper does not add that much value to the project itself. I can understand that. Okay, thank you for your time for reviewing this PR. Let's close it then.

@Hakky54 Hakky54 closed this Apr 11, 2024
@rmaucher
Copy link
Contributor

I had left the PR open since others could have been willing to go through with it (or not, I don't know).

@rmaucher rmaucher reopened this Apr 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants