3

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.

siaodi
  • 33
  • 5

1 Answers1

3

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)

Joakim Erdfelt
  • 46,896
  • 7
  • 86
  • 136
  • Thanks so much, this is what i want. – siaodi Aug 20 '20 at 09:10
  • Hi @Joakim, I have tried, but when ssl handshake failed, I cannot get any information from SSLEngine. I get the SSLSession, `SSLSession session = event.getSSLEngine().getSession();`, but when i get other information with `session.getPeerCertificates()`, `session.getPeerCertificateChain()`, it all throws `javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated`. When ssl handshake is ok, I can get the certificates information with above two methods. Do you know anything about it. Thanks a lot – siaodi Sep 11 '20 at 09:25
  • Be aware that `session.getPeerCertificateChain()` is deprecated, use the recommended alternatives indicated in javadoc, and pay attention to the javadoc on the recommended paths about what SSLPeerUnverifiedException means, especially around specific cipher suites features. – Joakim Erdfelt Sep 11 '20 at 17:06
  • I checked, I used the right cipher, and try with `getPeerCertificates()` but still no certificates found. The javadoc of this method said `SSLPeerUnverifiedException` will be thrown `if the peer's identity has not been verified`. So i am afraid i cannot get peer identity when authentication failed. – siaodi Sep 16 '20 at 02:34
  • I tried with initiating an `SslContextFactory` setting with an `SSLContex` initialized myself with `X509TrustManager` and `X509TrustManager.checkServerTrusted(X509Certificate[] var1, String var2)` override, in this methd i can directly printout the certificates information no matter peer is authencated or not. Luckly, this works. But do you foresee any risk with homemade SSLContext in Jetty – siaodi Sep 16 '20 at 02:35