如何获取证书信息

How can I access to certificate information

我有一个 Java EE server/client 架构,它通过使用 SSL 连接相互通信。建立连接后,客户端可以查询服务器 Web 服务。我的问题是如何访问服务器 Web 服务中的客户端证书信息?我的服务器控制器如下:

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("mycontroller")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public class Controller {

    @GET
    @Path("dosomething")
    public Response doSomething() {

        // How can I have access to certificate information here ?

        return Response.ok().build();

    }

}

如果您要查找可在 HTTP Headers 和 HTTP Servlet Reqeust object 中找到的标准证书信息,例如来自 Apache HTTP 反向代理的客户端证书信息。你可以注入这些

例如:

@Context private HttpServletRequest servletRequest; @Context private HttpServletContext servletContext;

(见Get HttpServletRequest in Jax Rs / Appfuse application? or in the Java EE tutorial

如果您希望访问密钥库文件并加载证书的私钥,则应通过 JNDI 文件资源或 JCA 适配器来完成文件访问。

但我建议您谨慎,应用程序服务器应处理所有 SSL/TLS 连接安全,您的 WAR 组件只是声明它希望连接在 web.xml 文件。将消息级安全性和身份验证与应用程序或传输协议安全性混合在一起可以打破关注点分离。即在总线或集线器场景中将身份验证附加到消息。

我找到了一种方法来做我想做的事。

首先,必须将服务器配置为需要客户端证书身份验证。在我的例子中,我使用了一个 JBoss 服务器并且必须在 standalone.xml 文件中添加它:

...
<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="false">
    ...
    <connector name="https" protocol="HTTP/1.1" scheme="https" socket-binding="https" enable-lookups="false" secure="true">
        <ssl name="localhost" key-alias="localhost" password="server" certificate-file="${jboss.server.config.dir}/server.jks" certificate-key-file="${jboss.server.config.dir}/server.jks" ca-certificate-file="${jboss.server.config.dir}/truststore.jks" protocol="TLSv1" verify-client="true" />
    </connector>
    ...
</subsystem>
...

然后在我的控制器中,我不得不注入 HttpServletRequest,最后我可以获得一个包含证书信息的 X509Certificate 实例:

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.servlet.http.HttpServletRequest;
import java.security.cert.X509Certificate;

@Path("mycontroller")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public class Controller {

    @Context 
    private HttpServletRequest request;

    @GET
    @Path("dosomething")
    public Response doSomething() {

        X509Certificate[] certChain = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
        X509Certificate certificate = certChain[0];

        return Response.ok().build();

    }

}