6

I have to work with old version (1.8.1) of rest-assured framework. And all my post() or get() requests called from rest-assured fails, because server I am using for tests has self-signed SSL certificate.

I know that since version 2.2.0 this is quite easy to setup ssl connection to use relaxedHTTPSValidation, e.g.

given().relaxedHTTPSValidation().when().get("https://some_server.com")

I also found on rest-assured wiki how to deal with SSL config.

But my question is is it possible in older version of rest-assured (1.8.1).

Exception thrown is SSLHandshakeException.

And here is the trace I got:

   javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
       at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
       at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
       at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
       at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
       at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
       at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
       at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
       at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
       at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
       at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
       at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
       at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
       at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:543)
       at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:409)
       at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177)
       at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:304)
       at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:611)
       at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:446)
       at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:882)
       at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
       at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
       at org.apache.http.client.HttpClient$execute.call(Unknown Source)
       at com.jayway.restassured.internal.RequestSpecificationImpl$RestAssuredHttpBuilder.doRequest(RequestSpecificationImpl.groovy:1377)
       at com.jayway.restassured.internal.http.HTTPBuilder.post(HTTPBuilder.java:341)
       at com.jayway.restassured.internal.http.HTTPBuilder$post.call(Unknown Source)
       at com.jayway.restassured.internal.RequestSpecificationImpl.sendRequest(RequestSpecificationImpl.groovy:801)
       at com.jayway.restassured.internal.RequestSpecificationImpl.this$2$sendRequest(RequestSpecificationImpl.groovy)
       at com.jayway.restassured.internal.RequestSpecificationImpl$this$2$sendRequest.call(Unknown Source)
       at com.jayway.restassured.internal.filter.RootFilter.filter(RootFilter.groovy:30)
       at com.jayway.restassured.filter.Filter$filter.call(Unknown Source)
       at com.jayway.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:49)
       at com.jayway.restassured.filter.FilterContext$next.call(Unknown Source)
       at com.jayway.restassured.internal.RequestSpecificationImpl.invokeFilterChain(RequestSpecificationImpl.groovy:758)
       at com.jayway.restassured.internal.RequestSpecificationImpl$invokeFilterChain.callCurrent(Unknown Source)
       at com.jayway.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1142)
       at com.jayway.restassured.internal.RequestSpecificationImpl.this$2$applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy)
       at com.jayway.restassured.internal.RequestSpecificationImpl$this$2$applyPathParamsAndSendRequest.callCurrent(Unknown Source)
       at com.jayway.restassured.internal.RequestSpecificationImpl.post(RequestSpecificationImpl.groovy:135)
       at com.ibm.datatools.webauto.framework.common.BaseWebTest.login(BaseWebTest.java:53)
       at com.ibm.datatools.webauto.dynamite.svt.ui.testcases.UDXTest.idaLogin(UDXTest.java:47)
       at com.ibm.datatools.webauto.dynamite.svt.ui.testcases.UDXTest.beforeClass(UDXTest.java:62)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
       at java.lang.reflect.Method.invoke(Method.java:498)
       at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
       at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:510)
       at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:211)
       at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
       at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:170)
       at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:104)
       at org.testng.TestRunner.privateRun(TestRunner.java:774)
       at org.testng.TestRunner.run(TestRunner.java:624)
       at org.testng.SuiteRunner.runTest(SuiteRunner.java:359)
       at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:354)
       at org.testng.SuiteRunner.privateRun(SuiteRunner.java:312)
       at org.testng.SuiteRunner.run(SuiteRunner.java:261)
       at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
       at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
       at org.testng.TestNG.runSuitesSequentially(TestNG.java:1215)
       at org.testng.TestNG.runSuitesLocally(TestNG.java:1140)
       at org.testng.TestNG.run(TestNG.java:1048)
       at org.testng.TestNG.privateMain(TestNG.java:1355)
       at org.testng.TestNG.main(TestNG.java:1324)

Note: This is not duplicate of this or this question, because answers provided there regard newer version of rest-assured.

Community
  • 1
  • 1
running.t
  • 5,329
  • 3
  • 32
  • 50
  • 1
    What SSL error are you getting? I am guessing a handshake exception but can you post the stacktrace? Also, have you tried importing the certificate into your Java installation's trust store? – Adam Jan 27 '17 at 15:53
  • @Adam: regarding importing certificate into trust store. This seems not to be an option as our test environements are automatically created/spawned so I can assume certificate is generated once per test session. Is it possible to download such certificate before test, create *temporary* trust store that I could use during test session and add this certificate to that trust store? – running.t Jan 30 '17 at 10:11
  • Well based on the error, it looks like you need to upload the certificate into your trust store when your JVM is started. See http://stackoverflow.com/questions/373295/digital-certificate-how-to-import-cer-file-in-to-truststore-file-using. This should be part of your environment setup and if for some terrible bureaucratic reason it can't happen, I don't think there is much you can do other than get a real signed certificate or forcing it to be stored within your test (not recommended). – Adam Jan 30 '17 at 15:51
  • @Adam: yes, **but** in general every test session I have a new test server with new self-signed certificate is created. So I would have to add each such cert before test session and probably remove it after test session. So in fact it looks perfectly like part of `@BeforeSuite` and `@AfterSuite` methods (setup and teardown). I am now trying to do that automatically in Java without using external tools. Probably will paste code snippet with solution as an answer when it's done. – running.t Jan 31 '17 at 09:52

2 Answers2

4

It worked for me with below correction

@Test
public void testUserFetchesSuccess(){
   given().config(RestAssured.config().sslConfig(new SSLConfig().allowAllHostnames())).
    get(restUrl).
    then().body("id", equalTo("abc0"));
}
1

As I wrote in one of my comments I tried solution that:

  1. Download server certificates
  2. Creates temporary keystore to be used by rest-assured
  3. stores server certificates in temporary keystore
  4. Uses temporary keystore in rest-assured when connecting to server during tests

Here is important part of code:

protected Certificate[] getCertificates(String url) throws IOException, GeneralSecurityException
{
    URL urlConnection = new URL(url);
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(new KeyManager[0], new TrustManager[] {new DummyTrustManager()}, new SecureRandom());
    SSLContext.setDefault(context);

    HttpsURLConnection con = (HttpsURLConnection)urlConnection.openConnection();
    con.setHostnameVerifier(
            new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                    }
    });

    con.setSSLSocketFactory(context.getSocketFactory());
    con.connect();
    Certificate[] certificates = con.getServerCertificates();

    con.disconnect();
    return certificates;

}

protected void storeCertificates(Certificate[] certs, String keystorePath, String keystorePassword) throws GeneralSecurityException, IOException
{
    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    keystore.load(null, keystorePassword.toCharArray());
    for (Certificate c: certs)
    {
        keystore.setCertificateEntry(Integer.toHexString(c.hashCode()), c);
    }
    File f = new File(keystorePath);
    FileOutputStream out_stream = new FileOutputStream(f);
    keystore.store(out_stream, keystorePassword.toCharArray());
    out_stream.close();
}

After that the only thing I have to do is:

 RestAssured.keystore(keystorePath, keystorePassword);

Notes:

  • getCertificates method is based on piece of code I found under this question. DummyTrustManager is exactly the same as DefaultTrustManager there.
  • storeCertificates is based on this question and it's answer.
  • I am still not sure if SSLContext.setDefault(context) changes SSLContext only temporarly (during downloading certificates) or permanently
Community
  • 1
  • 1
running.t
  • 5,329
  • 3
  • 32
  • 50