如何从Java中的剩余请求中检索客户端证书 [英] How to retrieve client certificate from rest request in Java
问题描述
我正在将Jersey
用于Java
和Jetty
中的REST
服务器作为Web服务器.我有self signed
证书.我想从收到的HTTP请求中获取客户端证书详细信息.如何从HttpServletRequest
获取信息?
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
?
一种方法:
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
我应该包括其他任何JAR
吗?还是有什么方法可以获取客户端证书的详细信息?
Should I include any additional JAR
? Or is there any way to obtain client certificate details?
我也遇到过
httpRequest.getHeader("ssl_client_cert");
这两种方式似乎都不适合我.如何获取详细信息?
Both ways not seems to work for me. How to get the details?
推荐答案
首先,确保您的处理SSL/TLS的ServerConnector. 接下来,该ServerConnector应该具有一个SslConnectionFactory,其中带有配置的HttpConfiguration对象. 该HttpConfiguration对象应该添加了SecureRequestCustomizer.
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);
如果在独立Jetty上使用${jetty.home}
和${jetty.base}
拆分,则需要检查配置中是否存在jetty-ssl.xml
...
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.
接下来,当您向该安全连接器发出请求时,各种过滤器和servlet将有权访问许多可能对您有用的请求属性.
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.
这些是Servlet规范定义的属性,已被SecureRequestCustomizer
添加到传入的HttpServletRequest中.
These are the Servlet spec defined attributes that SecureRequestCustomizer
adds to your incoming HttpServletRequest.
-
javax.servlet.request.X509Certificate
保存一个由java.security.cert.X509Certificate
个对象组成的数组. -
javax.servlet.request.cipher_suite
将协商的密码套件保存为String
对象. -
javax.servlet.request.key_size
将密钥大小保存为Integer
对象. -
javax.servlet.request.ssl_session_id
将SSL会话ID保留为String
对象.
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.
这些是SecureRequestCustomizer
添加到传入的HttpServletRequest中的Jetty定制属性.
These are the Jetty custom attributes that SecureRequestCustomizer
adds to your incoming HttpServletRequests.
-
org.eclipse.jetty.servlet.request.ssl_session
保持该连接的活动java.net.ssl.SSLSession
对象.
org.eclipse.jetty.servlet.request.ssl_session
holds the activejava.net.ssl.SSLSession
object for this connection.
由于尝试使用该属性时看到的是通用Object[]
,因此也许应该调试并查看这些对象的实际含义.
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.
请考虑一下,在尝试访问它们之前,Jetty无法控制的某些东西可能已替换了它们,或者使它们无法在Servlet规格表中显示给Jetty.
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.
- 过去已知一些第三方安全性库会更改这些属性.
- 或者您不是要在Jetty终止TLS/SSL连接,例如在防火墙/路由器/负载平衡器(haproxy,nginx,apache httpd或各种硬件)处终止(这意味着Jetty无法看到证书).
- 您没有使用普通的ServerConnector(例如UnixSocketConnector,LocalConnector或自定义连接器)
- 或者您在Java实现中有一个第三方安全层.
Object certs[] = httpRequest.getAttribute("javax.servlet.request.X509Certificate");
for(Object cert: certs) {
System.out.printf("DEBUG: Cert[%s] = %s%n", cert.getClass().getName(), cert);
}
这篇关于如何从Java中的剩余请求中检索客户端证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!