Certificate authentication over REST

A little bit of background

Amongst the various different authentication mechanisms that OpenAM supports, there is one particular module that always proves to be difficult to get correctly working: Client certificate authentication, or Certificate authentication module as defined in OpenAM. The setup is mainly complex due to the technology (SSL/TLS) itself, and quite frankly in most of the cases the plain concept of SSL is just simply not well understood by users.

Disclaimer: I have to admit I’m certainly not an expert on SSL, so I’m not going to deep dive into the details of how client certificate authentication itself works, instead, I’m just going to try to highlight the important bits that everyone should know who wants to set up a simple certificate based authentication.

The main thing to understand is that client cert authentication happens as part of the SSL handshake. That is it… It will NOT work if you access your site over HTTP. The authentication MUST happen at the network component that provides HTTPS for the end users.
Again, due to SSL’s complexity there are several possibilities: it could be that SSL is provided by the web container itself, but it is also possible that there is a network component (like a load balancer or a reverse proxy) where SSL is terminated. In the latter case it is quite a common thing for these components to embed the authenticated certificate in a request header for the underlying application (remember: the client cert authentication is part of the SSL handshake, so by the time OpenAM is hit, authentication WAS already performed by the container).

Now this is all nice, but how do you actually authenticate using your client certificate over REST?

Setting it all up

Now some of this stuff may look a bit familiar to you, but for the sake of simplicity let me repeat the exact steps of setting this up:

  • Go to Access Control – realm – Authentication page and Add a new Module Instance called cert with type Certificate
  • Open the Certificate module configuration, and make sure the LDAP Server Authentication User/Password settings are correct.
  • Generate a new self signed certificate by following this guide, but make sure that in the CSR you set the CN to “demo”. The resulting certificate and private key for me was client.crt and client.key respectively.
  • Create PKCS#12 keystore for the freshly generated private key and certificate:
    openssl pkcs12 -export -inkey client.key.org -in client.crt -out client.p12
  • Install the PKCS#12 keystore in your browser (Guide for Firefox)
  • Enable Client Authentication on the container. For example on Tomcat 7.0.53 you would have to edit conf/server.xml and set up the SSL connector like this:
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
     maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
     keystoreFile="/Users/aldaris/server.jks" keystorePass="changeit"
     truststoreFile="/Users/aldaris/trust.jks" truststorePass="changeit"
     clientAuth="true" sslProtocol="TLS" />
    
  • Add your user’s public certificate into the truststore (since the container performs the authentication, it needs to trust the client):
    keytool -import -keystore /Users/aldaris/trust.jks -file client.crt -alias demo

    In cases when the truststoreFile attribute is missing from the Connector settings, Tomcat by default falls back to the JVM’s truststore, so make sure you update the correct truststore.

  • Restart the container

Now if you did everything correctly, you should be able to go to /openam/UI/Login?module=cert and the browser should ask for the client certificate. After selecting the correct certificate you should get access to OpenAM right away.

It’s time to test it via REST

For my tests I’m going to use curl, I must say though that curl on OSX Mavericks (7.30) isn’t really capable to do client authentication, hence I would suggest installing curl from MacPorts (7.36) instead.
To perform the login via REST one would:

$ curl -X POST -v -k --cert-type pem --cert client.crt --key client.key.org "https://openam.example.com:8443/openam/json/authenticate?authIndexType=module&authIndexValue=cert"

And if you want to authenticate into a subrealm:

$ curl -X POST -v -k --cert-type pem --cert client.crt --key client.key.org "https://openam.example.com:8443/openam/json/subrealm/authenticate?authIndexType=module&authIndexValue=cert"

Simple as that. ;)

How to use Certificate module with DAS

Previously I have described how to install the DAS properly. Today’s entry is all about using the Certificate authentication module in a deployment where you have a DAS instance. So here are the steps required to make this work:

  • Follow the DAS install guide, but with the only difference being that you install the DAS on a HTTPS URL (OpenAM can keep running on HTTP). Since you are now using HTTPS, you need to make sure that the OpenAM server trusts the DAS’s certificate, otherwise OpenAM won’t be able to send notifications to the DAS, which could result in strange situations when a given session remains valid for a short period of time even though the user has logged out on a different DAS instance.
  • Go to Access Control – realm – Authentication page and Add a new Module Instance called cert with type Certificate
  • Open the Certificate module configuration, and change the followings:
    • Set the LDAP Server Authentication User/Password to correct values
    • For evaluation purposes set the Trusted Remote Hosts to “all”
  • Generate a new self signed certificate by following this guide, but make sure that in the CSR you set the CN to “demo”.
  • Create PKCS#12 keystore for the freshly generated private key and certificate:
    openssl pkcs12 -export -inkey server.key.org -in server.crt -out server.p12
  • Install the PKCS#12 keystore in your browser (Guide for Firefox)
  • Enable Client Authentication on the DAS’s container. For example on GlassFish 3.1.2 Admin Console you would have to go to Configurationsserver-configHTTP serviceHttp Listenershttp-listener-2 then open the SSL tab and check the Client Authentication option.
  • Install the public certificate into the container’s truststore, so the container will actually trust your certificate:
    keytool -import -keystore glassfish3/glassfish/domains/domain2/config/cacerts.jks -file server.crt -alias mycert

    You need to make sure that you install the certificate to the actually used truststore, some containers may use the JVM’s truststore instead having one on their own.

  • On the DAS enable the Request/Response serialization by setting the following property in the ~/FAMDistAuth/*.properties file:
    openam.remoteauth.include.reqres=true
  • Restart the DAS’s container
  • Open /auth/UI/Login?module=cert and choose your certificate
  • Profit