简体   繁体   中英

How to retrieve client certificate from rest request in Java

I'm using Jersey for REST server in Java and Jetty as web server. I have self signed certificates. I want to fetch client certificate details from received HTTP Request. How to obtain the information from HttpServletRequest ?

One method:

X509Certificate certs[] = (X509Certificate[])httpRequest.getAttribute("javax.servlet.request.X509Certificate");

Is this right? This results in exception,

Error [Ljava.lang.Object; cannot be cast to [Ljava.security.cert.X509Certificate 

Should I include any additional JAR ? Or is there any way to obtain client certificate details?

I also came across,

httpRequest.getHeader("ssl_client_cert");

Both ways not seems to work for me. How to get the details?

First, ensure that your ServerConnector that handles SSL/TLS. Next, that ServerConnector should have a SslConnectionFactory with a configured HttpConfiguration object within it. That HttpConfiguration object should have the SecureRequestCustomizer added to it.

In embedded-jetty parlance, it looks like this ...

        // SSL Context Factory
        SslContextFactory sslContextFactory = new SslContextFactory();
        sslContextFactory.setKeyStorePath("/path/to/keystore");
        sslContextFactory.setKeyStorePassword("password");
        sslContextFactory.setKeyManagerPassword("secret");
        sslContextFactory.setTrustStorePath("/path/to/keystore");
        sslContextFactory.setTrustStorePassword("password");


        // SSL HTTP Configuration
        HttpConfiguration https_config = new HttpConfiguration(http_config);
        https_config.addCustomizer(new SecureRequestCustomizer()); // <-- THIS LINE

        // SSL Connector
        ServerConnector sslConnector = new ServerConnector(server,
            new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
            new HttpConnectionFactory(https_config));
        sslConnector.setPort(8443);
        server.addConnector(sslConnector);

If you are using a ${jetty.home} and ${jetty.base} split on standalone Jetty, then you'll want to check that the jetty-ssl.xml is present in your configuration ...

$ cd /path/to/my-jetty-base
$ java -jar /path/to/jetty-home/start.jar --list-config

Java Environment:
-----------------
 java.home = /Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre (null)
 java.vm.vendor = Oracle Corporation (null)
 java.vm.version = 25.202-b08 (null)
 java.vm.name = Java HotSpot(TM) 64-Bit Server VM (null)
 java.vm.info = mixed mode (null)
 java.runtime.name = Java(TM) SE Runtime Environment (null)
 java.runtime.version = 1.8.0_202-b08 (null)
 java.io.tmpdir = /var/folders/w5/mmnzpk0n369dntp4nszlc8h40000gn/T/ (null)
 user.dir = /path/to/my-jetty-base (null)
 user.language = en (null)
 user.country = US (null)

Jetty Environment:
-----------------
 jetty.version = 9.4.15.v20190215
 jetty.tag.version = master
 jetty.home = /path/to/jetty-home
 jetty.base = /path/to/my-jetty-base

...(snip lots of output)...

Jetty Active XMLs:
------------------
 ${jetty.home}/etc/jetty-threadpool.xml
 ${jetty.home}/etc/jetty.xml
 ${jetty.home}/etc/jetty-webapp.xml
 ${jetty.home}/etc/jetty-plus.xml
 ${jetty.home}/etc/jetty-annotations.xml
 ${jetty.home}/etc/jetty-deploy.xml
 ${jetty.home}/etc/jetty-http.xml
 ${jetty.home}/etc/jetty-ssl.xml      <-- THIS LINE
 ${jetty.home}/etc/jetty-ssl-context.xml
 ${jetty.home}/etc/jetty-https.xml
 ${jetty.home}/etc/jetty-jaas.xml
 ${jetty.home}/etc/jetty-rewrite.xml
 ${jetty.base}/etc/demo-rewrite-rules.xml
 ${jetty.base}/etc/test-realm.xml

Once you have verified this base level configuration you are good to go with even using those attributes.

Next, when you make a request to that secure connector, the various filters and servlets will have access to a number of request attributes that could prove useful to you.

These are the Servlet spec defined attributes that SecureRequestCustomizer adds to your incoming HttpServletRequest.

  • javax.servlet.request.X509Certificate holds an array of java.security.cert.X509Certificate objects.
  • javax.servlet.request.cipher_suite holds your negotiated cipher suite as a String object.
  • javax.servlet.request.key_size holds your keysize as an Integer object.
  • javax.servlet.request.ssl_session_id holds your SSL Session ID as a String object.

These are the Jetty custom attributes that SecureRequestCustomizer adds to your incoming HttpServletRequests.

  • org.eclipse.jetty.servlet.request.ssl_session holds the active java.net.ssl.SSLSession object for this connection.

Since you are seeing a generic Object[] from your attempt to use the attribute, perhaps you should debug and see what those objects actually are.

Consider that something outside of Jetty's control might have replaced them, or made them unavailable to Jetty in the Servlet spec form before you attempted to access them.

  • A few 3rd party security libraries have been known to alter these attribute in the past.
  • Or you are not terminating the TLS/SSL connection at Jetty, such as at a firewall/router/load balancer (haproxy, nginx, apache httpd, or various hardware) (which means Jetty cannot see the certificate).
  • You are not using a normal ServerConnector (such as UnixSocketConnector, LocalConnector, or a custom Connector)
  • Or you have a 3rd party security layer in your Java implementation.
Object certs[] = httpRequest.getAttribute("javax.servlet.request.X509Certificate");
for(Object cert: certs) {
  System.out.printf("DEBUG: Cert[%s] = %s%n", cert.getClass().getName(), cert);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM