Question

What is common way of client certificate validation against CRL in Tomcat?

A) One possible solution: Update server.xml, set up connector, set up key and trust store, and there is crlList parameter.

There are 2 issues with that approach:

1) Maintenance of the list - have to be done outside of Tomcat, Tomcat needs restart in order to pick up latest one

2) There is no (or at least the one I could find) way to support crl lists for multiple CA bodies, or just say - multiple CR Lists at the same time.

I was not able to find "good" solution back few years ago with Tomcat 5. Any news on this with 7?

B) Is there common/elegant way to override connector handler and current functionality and provide custom certificate validation?

In a way that JBoss AS let you do it, by just extending existing class and giving you possibility to define own login-module and own verifier.

Was it helpful?

Solution

There is now a way to pick the latest CRL file without restarting the server.

They introduced 2 methods named:

  1. reloadSslHostConfig(String hostName) - to reload a specific host
  2. reloadSslHostConfigs() - reload all

They can be called in various ways:

  1. Using jmx
  2. Using manager service
  3. By making custom protocol - I found this way during my research

Details of way 1 and way 2 are easily available online.

Details of how to go about using way 3:

  1. Make a class extending the protocol of your choice for eg. Http11NioProtocol
  2. Override the required methods and just call super in them to keep default behavior
  3. Make a thread in this class to call reloadSslHostConfigs method time to time
  4. Package this class in a jar and put that jar in tomcat's lib folder
  5. Edit protocol in connector in server.xml to use this custom defined protocol

Find sample code below:

Main protocol class:

    package com.myown.connector;

    import java.io.File;
    import java.io.InputStream;
    import java.lang.reflect.Field;
    import java.net.URL;
    import java.net.URLConnection;
    import java.nio.file.StandardCopyOption;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ConcurrentMap;

    import javax.management.MalformedObjectNameException;
    import javax.management.ObjectName;
    import javax.net.ssl.SSLSessionContext;

    import org.apache.coyote.http11.Http11NioProtocol;
    import org.apache.juli.logging.Log;
    import org.apache.juli.logging.LogFactory;
    import org.apache.tomcat.util.modeler.Registry;
    import org.apache.tomcat.util.net.AbstractEndpoint;
    import org.apache.tomcat.util.net.AbstractJsseEndpoint;
    import org.apache.tomcat.util.net.GetSslConfig;
    import org.apache.tomcat.util.net.SSLContext;
    import org.apache.tomcat.util.net.SSLHostConfig;
    import org.apache.tomcat.util.net.SSLHostConfigCertificate;
    import org.apache.tomcat.util.net.SSLImplementation;
    import org.apache.tomcat.util.net.SSLUtil;

    public class ReloadProtocol extends Http11NioProtocol {

        private static final Log log = LogFactory.getLog(Http12ProtocolSSL.class);

        public ReloadProtocol() {
            super();
            RefreshSslConfigThread refresher = new 
                  RefreshSslConfigThread(this.getEndpoint(), this);
            refresher.start();
        }

        @Override
        public void setKeystorePass(String s) {
            super.setKeystorePass(s);
        }

        @Override
        public void setKeyPass(String s) {
            super.setKeyPass(s);
        }

        @Override
        public void setTruststorePass(String p) {
            super.setTruststorePass(p);
        }

        class RefreshSslConfigThread extends Thread {

            AbstractJsseEndpoint<?> abstractJsseEndpoint = null;
            Http11NioProtocol protocol = null;

            public RefreshSslConfigThread(AbstractJsseEndpoint<?> abstractJsseEndpoint, Http11NioProtocol protocol) {
                this.abstractJsseEndpoint = abstractJsseEndpoint;
                this.protocol = protocol;
            }

            public void run() {
                int timeBetweenRefreshesInt = 1000000; // time in milli-seconds
                while (true) {
                    try {
                            abstractJsseEndpoint.reloadSslHostConfigs();
                            System.out.println("Config Updated");
                    } catch (Exception e) {
                        System.out.println("Problem while reloading.");
                    }
                    try {
                        Thread.sleep(timeBetweenRefreshesInt);
                    } catch (InterruptedException e) {
                        System.out.println("Error while sleeping");
                    }
                }
            }
       }
}

Connector in server.xml should mention this as the protocol:

<Connector protocol="com.myown.connector.ReloadProtocol"
 ..........

Hope this helps.

OTHER TIPS

You can do this by implementing your own TrustManager. See the trustManagerClassName attribute in the HTTP connector docs(http://tomcat.apache.org/tomcat-8.0-doc/config/http.html#SSL_Support)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top