ssljettyembedded-jettysslcontext

How to get the client's certificate in jetty server when doing authentication


After set an embedded Jetty server that requests client authentication by setting SslContextFactory.setNeedClientAuth(true), how can I get the client's certificate information when a client connect to jetty server for both cases, the authentication successful and failed?

I have read this reference but I think this is only applicable for the authentication successful. SecureRequestCustomizer.customize(...) seems only executed after client's certificate information is authenticated successfully.

But what i am wondering is there any approach to get the client's certificate information when jetty server is doing authentication, no matter it is successful or failed. Then I can get the client's certificate information even this client is not trusted by jetty sever.


Solution

  • Welcome to stackoverflow.

    When you have SslContextFactory.setNeedClientAuth(true) set, that means you are setting the Java level javax.net.ssl.SSLParameters.setNeedClientAuth(true).

    This impacts the Java level TLS/SSL negotiation of new connections, and forces them to require a valid Client Certificate.

    If that fails, the connection is terminated by Java itself at the TLS/SSL handshake level, and no HTTP request is even sent by the client, and Jetty has not been involved in this determination.

    As you have no-doubt already noticed, a connection that has failed the TLS/SSL level Client Authentication is not processed in the SecureRequestCustomizer.

    If you want to see successful and failed clients get past the TLS/SSL handshake level and reach your various HTTP handlers then you'll have to turn off the SslContextFactory.setNeedClientAuth(true) setting. But that means there is no client certificate authentication performed by the Java JVM's TLS/SSL layers, and you are now on the hook to perform these same checks in your own code. This wont work very well.

    So you have a choice of ...

    1. setNeedClientAuth(true) - Connection is authenticated, terminated if client certificate failed. No HTTP request is created by client.
    2. setNeedClientAuth(false) - All connections succeed with no authentication being performed, resulting in HTTP requests that you can then process.

    If you need point 1, but point 2 is no-go, consider using the org.eclipse.jetty.io.ssl.SslHandshakeListener and just paying attention to the results of success/failure.

    Create your own implementation of this listener, and add it as a bean to your server Connectors. You'll get passed the active javax.net.ssl.SSLEngine for that event source, where you can interrogate the various details you are after for a failed connection (you can even get the IP information of the client that attempted the connection)