Securing APIs using Mutual SSL with WSO2 API Manager.

WSO2 API Manager is using OAuth2 for securing the APIs which are exposed by it.  Currently API Manager implementation is tightly bound with the OAuth2. However, there is some way in APIM that we can write our own authentication mechanism for APIs instead of using OAuth2. But it is normally not recommended as some other functions such as throttling, application subscriptions, scopes and so on can be broken due to it.

Writing custom authentication may be needed in some scenarios. Following would be sample use case,

You may have several APIs that are exposed by WSO2 APIM (API Gateway). All of them are secured with OAuth2 by default. But there may be a requirement for one API, that it must be secured with mutual SSL authentication. It means that if client can send a valid certificate, client must be able to access the API.

Lets see how you can implement a Mutual SSL (Certificate base) authentication for given API.

Step 1. Let create API using API publisher and publish it to store. Please verify whether it can be accessed with given access token successfully. So, it means that API has been secured with OAuth2.

Step 2. Enable Mutual SSL in API Gateway. You can able it using /repository/conf/axis2/axis2.xml of the API Gateway.

Please configure following property under HTTPS transport receiver configuration..

<parameter name="SSLVerifyClient">optional</parameter>

Complete configuration would look like following

<transportReceiver name="https" class="org.apache.synapse.transport.passthru.PassThroughHttpSSLListener">
<parameter name="port" locked="false">8243</parameter>
<parameter name="non-blocking" locked="false">true</parameter>
<parameter name="httpGetProcessor" locked="false">org.wso2.carbon.transport.nhttp.api.PassThroughNHttpGetProcessor</parameter>
<parameter name="keystore" locked="false">
<KeyStore>
<Location>repository/resources/security/wso2carbon.jks</Location>
<Type>JKS</Type>
<Password>wso2carbon</Password>
<KeyPassword>wso2carbon</KeyPassword>
</KeyStore>
</parameter>
<parameter name="truststore" locked="false">
<TrustStore>
<Location>repository/resources/security/client-truststore.jks</Location>
<Type>JKS</Type>
<Password>wso2carbon</Password>
</TrustStore>
</parameter>
<parameter name="SSLVerifyClient">optional</parameter>
</transportReceiver

Step 3. Import client’s certificate in to the truststore file of the API Gateway. By default, truststore file is client-truststore.jks which can be found at /repository/resources/security directory. It is defined under HTTPS transport receiver configuration of the axis2.xml file as mentioned in above

You can import client’s certificate using following keytool command.

>keytool -import -file {PATH_TO_CLIENT_CERTIFICATE} -keystore [PATH TO client-truststore.jks] -storepass wso2carbon -alias clientCert

Step 4. You can find the Mutual SSL authentication handler from here and add it to /repository/components/lib directory in API Gateway instance.

You can find the complete source from here and you can modify the authentication handler as you like. It is a maven project and you need maven 3 to build the project.

Step 5. Configure your handler for give API. You can find the API definition from /repository/deployment/server/synapse-configs/default/api directory. You can open the related find for given API and edit it.

Remove all the handlers that are configured by default.  Then we can add our new authentication handler which is org.soasecurity.apim.authentication.handler.MutualSSLAuthenticationHandler.

So finally handler configuration look like following.

<handlers>
<handler class="org.soasecurity.apim.authentication.handler.MutualSSLAuthenticationHandler"/>
</handlers>

Note1 : If you like to keep existing authentication handler.  You can keep all the handlers & configure this handler as an additional authentication mechanism 

Note2: If your API is in tenant,  then you can find the API definition from tenant’s directory /repository/tenants/

Step 6. Restart the API Gateway server.

Step 7. Invoke the our API using mutual SSL. You can find sample mutual SSL client code from here, which i used to test. When client sends a proper certificate, you can access the API and if it is not client would be hit with 401.

 

Also, Inside the authentication handler, you can retrieve the client certificate and do what ever you want. As an example, i am adding certificate in to HTTP header block which would be sent to backend service as well.

Thanks for reading…!!!