cheb1k4
cheb1k4

Reputation: 2464

How can I access to certificate information

I have a Java EE server/client architecture which communicate with each other by using SSL connection. When the connection is made, the client can interrogate the server web services. My question is how can I access to client certificate information in the server web service ? My server controller below :

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

    }

}

Upvotes: 2

Views: 1984

Answers (2)

cheb1k4
cheb1k4

Reputation: 2464

I found a way to do what I wanted.

First, the server has to be configurated to require client certificate authentication. In my case I use a JBoss server and had to add this in the standalone.xml file :

...
<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>
...

And then in my controller I had to inject HttpServletRequest and finally I could obtain an instance of X509Certificate which contains the certificate information :

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

    }

}

Upvotes: 4

Chris
Chris

Reputation: 389

If you are looking for the standard certificate information that would be found in the HTTP Headers and the HTTP Servlet Reqeust object, such as Client certificate information from Apache HTTP reverse proxy. You can inject these

For Example:

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

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

If you wish to access the keystore file and load the private key of the certificate, then file access should be done through a JNDI file resource or a JCA adaptor.

But i would advise caution, the application server should handle all the SSL/TLS connection security your WAR component just declares that it wants the connection to be "confidential" in the web.xml file. Mixing the message level security and authentication with the applicaition or transport protocol security can break separation of concerns. i.e. keeping authentication attached to the message in a bus or hub scenario.

Upvotes: 0

Related Questions