问题
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.X509Certificateholds an array ofjava.security.cert.X509Certificateobjects.javax.servlet.request.cipher_suiteholds your negotiated cipher suite as aStringobject.javax.servlet.request.key_sizeholds your keysize as anIntegerobject.javax.servlet.request.ssl_session_idholds your SSL Session ID as aStringobject.
These are the Jetty custom attributes that SecureRequestCustomizer adds to your incoming HttpServletRequests.
org.eclipse.jetty.servlet.request.ssl_sessionholds the activejava.net.ssl.SSLSessionobject 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