How to retrieve client certificate from rest request in Java

为君一笑 提交于 2021-02-11 14:44:14

问题


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?


回答1:


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);
}


来源:https://stackoverflow.com/questions/54907233/how-to-retrieve-client-certificate-from-rest-request-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!