问题
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 ofjava.security.cert.X509Certificate
objects.javax.servlet.request.cipher_suite
holds your negotiated cipher suite as aString
object.javax.servlet.request.key_size
holds your keysize as anInteger
object.javax.servlet.request.ssl_session_id
holds your SSL Session ID as aString
object.
These are the Jetty custom attributes that SecureRequestCustomizer
adds to your incoming HttpServletRequests.
org.eclipse.jetty.servlet.request.ssl_session
holds the activejava.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