Two-way SSL (client certificates) with Scalatest
At work we recently added the option to authenticate machine to machine communication using client certificates (two-way ssl). While this was relatively easy to set up and access programatically from different programming languages, we ran into some difficulties getting our integration test up and running. We wanted to have a couple of tests to make sure the information from the certificate was correctly parsed and mapped to an internal client id, and how the system reacts to invalid certificates and a couple of other edge cases.
Since we use Scalatest for all our integration testing we just wanted to add the private keystore and the trust store to scalatest and be done with it. However, the standard fluent API provided by Scalatest doesn’t offer it (or we couldn’t find it). After some looking around we came to the following setup which works for us in our integration test suite:
import java.io.{File, FileInputStream} import java.security.KeyStore import com.jayway.restassured.RestAssured import com.jayway.restassured.config.SSLConfig import com.jayway.restassured.http.ContentType import com.jayway.restassured.response.Response import org.apache.http.conn.ssl.{SSLConnectionSocketFactory, SSLSocketFactory} import org.scalatest._ object SSLTest { def doSSLTest() = { // load the corresponding keystores val privateKeyStoreLocation = new FileInputStream(new File("src/test/resources/keystores/testing-client.p12")); val keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(privateKeyStoreLocation, "secret".toCharArray()); val certKeyStoreLocation = new FileInputStream(new File("src/test/resources/keystores/ca-chain.cert.jks")); val trustStore = KeyStore.getInstance("jks"); trustStore.load(certKeyStoreLocation, "secret".toCharArray()); // manually create a new sockerfactory and pass in the required values val clientAuthFactory = new org.apache.http.conn.ssl.SSLSocketFactory(keyStore, "secret", trustStore); // don't check on hostname clientAuthFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); // set the config in rest assured val config = new SSLConfig().`with`().sslSocketFactory(clientAuthFactory).and().allowAllHostnames(); RestAssured.config = RestAssured.config().sslConfig(config); RestAssured .given.contentType(ContentType.JSON) .when .request .post("https://theurl") } }
Note that some of these classes are actually deprecated, and could be replaced with other relevant classes from the apache commons library used here.
Reference: | Two-way SSL (client certificates) with Scalatest from our JCG partner Jos Dirksen at the Smart Java blog. |