diff --git a/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/SSLITest.java b/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/SSLITest.java index 9285aac29..bb3a17888 100644 --- a/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/SSLITest.java +++ b/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/SSLITest.java @@ -25,10 +25,13 @@ import io.restassured.itest.java.support.WithJetty; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; @@ -39,10 +42,8 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; -public class SSLITest extends WithJetty { - - @Rule - public ExpectedException exception = ExpectedException.none(); +@RunWith(Enclosed.class) +public class SSLITest { public static ResponseSpecification helloWorldSpec() { return new ResponseSpecBuilder(). @@ -50,215 +51,260 @@ public static ResponseSpecification helloWorldSpec() { expectStatusCode(200).build(); } - @Test(expected = SSLException.class) - public void throwsSSLExceptionWhenHostnameInCertDoesntMatch() throws Exception { - RestAssured.get("https://localhost:8443/hello"); - } + public static class OneWaySSLTest extends WithJetty { - @Test - public void givenTrustStoreDefinedStaticallyWhenSpecifyingJksKeyStoreFileWithCorrectPasswordAllowsToUseSSL() throws Exception { - RestAssured.trustStore("jetty_localhost_client.jks", "test1234"); - try { - RestAssured.expect().spec(helloWorldSpec()).when().get("https://localhost:8443/hello"); - } finally { - RestAssured.reset(); - } - } + @Rule + public ExpectedException exception = ExpectedException.none(); - @Test(expected = SSLHandshakeException.class) - public void whenEnablingAllowAllHostNamesVerifierWithoutActivatingAKeyStore() throws Exception { - RestAssured.config = RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().allowAllHostnames()); - try { - RestAssured.get("https://localhost:8443/hello").then().spec(helloWorldSpec()); - } finally { - RestAssured.reset(); + @Test(expected = SSLException.class) + public void throwsSSLExceptionWhenHostnameInCertDoesntMatch() throws Exception { + RestAssured.get("https://localhost:8443/hello"); } - } - @Test - public void usingStaticallyConfiguredCertificateAuthenticationWorks() throws Exception { - RestAssured.authentication = RestAssured.certificate("jetty_localhost_client.jks", "test1234", CertificateAuthSettings.certAuthSettings().allowAllHostnames()); - try { - RestAssured.get("https://localhost:8443/hello").then().spec(helloWorldSpec()); - } finally { - RestAssured.reset(); + @Test + public void givenTrustStoreDefinedStaticallyWhenSpecifyingJksKeyStoreFileWithCorrectPasswordAllowsToUseSSL() throws Exception { + RestAssured.trustStore("jetty_localhost_client.jks", "test1234"); + try { + RestAssured.expect().spec(helloWorldSpec()).when().get("https://localhost:8443/hello"); + } finally { + RestAssured.reset(); + } } - } - @Test(expected = SSLException.class) - public void usingStaticallyConfiguredCertificateAuthenticationWithIllegalHostNameInCertDoesntWork() throws Exception { - RestAssured.authentication = RestAssured.certificate("truststore_mjvmobile.jks", "test4321"); - try { - RestAssured.get("https://localhost:8443/hello").then().body(containsString("eurosport")); - } finally { - RestAssured.reset(); + @Test(expected = SSLHandshakeException.class) + public void whenEnablingAllowAllHostNamesVerifierWithoutActivatingAKeyStore() throws Exception { + RestAssured.config = RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().allowAllHostnames()); + try { + RestAssured.get("https://localhost:8443/hello").then().spec(helloWorldSpec()); + } finally { + RestAssured.reset(); + } } - } - @Test - public void usingStaticallyConfiguredCertificateAuthenticationWithIllegalHostNameInCertWorksWhenSSLConfigIsConfiguredToAllowAllHostNames() throws Exception { - RestAssured.config = RestAssuredConfig.newConfig().sslConfig(SSLConfig.sslConfig().allowAllHostnames()); - RestAssured.authentication = RestAssured.certificate("jetty_localhost_client.jks", "test1234"); - try { - RestAssured.get("https://localhost:8443/hello").then().spec(helloWorldSpec()); - } finally { - RestAssured.reset(); + @Test + public void usingStaticallyConfiguredCertificateAuthenticationWorks() throws Exception { + RestAssured.authentication = RestAssured.certificate("jetty_localhost_client.jks", "test1234", CertificateAuthSettings.certAuthSettings().allowAllHostnames()); + try { + RestAssured.get("https://localhost:8443/hello").then().spec(helloWorldSpec()); + } finally { + RestAssured.reset(); + } } - } - @Test - public void givenKeystoreDefinedUsingGivenWhenSpecifyingJksKeyStoreFileWithCorrectPasswordAllowsToUseSSL() throws Exception { - RestAssured.given().trustStore("/jetty_localhost_client.jks", "test1234").then().expect().spec(helloWorldSpec()).when().get("https://localhost:8443/hello"); - } + @Test(expected = SSLException.class) + public void usingStaticallyConfiguredCertificateAuthenticationWithIllegalHostNameInCertDoesntWork() throws Exception { + RestAssured.authentication = RestAssured.certificate("truststore_mjvmobile.jks", "test4321"); + try { + RestAssured.get("https://localhost:8443/hello").then().body(containsString("eurosport")); + } finally { + RestAssured.reset(); + } + } - @Test - public void throwsIOExceptionWhenPasswordIsIncorrect() throws Exception { - exception.expect(IOException.class); - exception.expectMessage("Keystore was tampered with, or password was incorrect"); - - RestAssured.given(). - auth().certificate("jetty_localhost_client.jks", "test4333"). - when(). - get("https://localhost:8443/hello"). - then(). - body(containsString("eurosport")); - } + @Test + public void usingStaticallyConfiguredCertificateAuthenticationWithIllegalHostNameInCertWorksWhenSSLConfigIsConfiguredToAllowAllHostNames() throws Exception { + RestAssured.config = RestAssuredConfig.newConfig().sslConfig(SSLConfig.sslConfig().allowAllHostnames()); + RestAssured.authentication = RestAssured.certificate("jetty_localhost_client.jks", "test1234"); + try { + RestAssured.get("https://localhost:8443/hello").then().spec(helloWorldSpec()); + } finally { + RestAssured.reset(); + } + } - @Test - public void certificateAuthenticationWorks() throws Exception { - RestAssured.given(). - auth().certificate("jetty_localhost_client.jks", "test1234", CertificateAuthSettings.certAuthSettings().allowAllHostnames()). - when(). - get("https://localhost:8443/hello"). - then(). - spec(helloWorldSpec()); - } + @Test + public void givenKeystoreDefinedUsingGivenWhenSpecifyingJksKeyStoreFileWithCorrectPasswordAllowsToUseSSL() throws Exception { + RestAssured.given().trustStore("/jetty_localhost_client.jks", "test1234").then().expect().spec(helloWorldSpec()).when().get("https://localhost:8443/hello"); + } - @Test public void - allows_specifying_trust_store_in_dsl() throws Exception { - InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jetty_localhost_client.jks"); - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(keyStoreStream, "test1234".toCharArray()); + @Test + public void throwsIOExceptionWhenPasswordIsIncorrect() throws Exception { + exception.expect(IOException.class); + exception.expectMessage("Keystore was tampered with, or password was incorrect"); + + RestAssured.given(). + auth().certificate("jetty_localhost_client.jks", "test4333"). + when(). + get("https://localhost:8443/hello"). + then(). + body(containsString("eurosport")); + } - RestAssured.given().config(RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().allowAllHostnames())).trustStore(keyStore).when().get("https://localhost:8443/hello").then().statusCode(200); - } + @Test + public void certificateAuthenticationWorks() throws Exception { + RestAssured.given(). + auth().certificate("jetty_localhost_client.jks", "test1234", CertificateAuthSettings.certAuthSettings().allowAllHostnames()). + when(). + get("https://localhost:8443/hello"). + then(). + spec(helloWorldSpec()); + } - @Ignore("Temporary ignored but I think this ought to work. Perhaps some issues with config merging?") - @Test public void - allows_specifying_trust_store_statically() throws Exception { - InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jetty_localhost_client.jks"); - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(keyStoreStream, "test1234".toCharArray()); + @Test + public void + allows_specifying_trust_store_in_dsl() throws Exception { + InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jetty_localhost_client.jks"); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(keyStoreStream, "test1234".toCharArray()); - RestAssured.trustStore(keyStore); + RestAssured.given().config(RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().allowAllHostnames())).trustStore(keyStore).when().get("https://localhost:8443/hello").then().statusCode(200); + } - try { - RestAssured.given().config(RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().allowAllHostnames())).when().get("https://localhost:8443/hello").then().statusCode(200); - } finally { - RestAssured.reset(); + @Ignore("Temporary ignored but I think this ought to work. Perhaps some issues with config merging?") + @Test + public void + allows_specifying_trust_store_statically() throws Exception { + InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jetty_localhost_client.jks"); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(keyStoreStream, "test1234".toCharArray()); + + RestAssured.trustStore(keyStore); + + try { + RestAssured.given().config(RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().allowAllHostnames())).when().get("https://localhost:8443/hello").then().statusCode(200); + } finally { + RestAssured.reset(); + } } - } - @Test public void - allows_specifying_trust_store_and_allow_all_host_names_in_config_using_dsl() throws Exception { - InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jetty_localhost_client.jks"); - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(keyStoreStream, "test1234".toCharArray()); + @Test + public void + allows_specifying_trust_store_and_allow_all_host_names_in_config_using_dsl() throws Exception { + InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jetty_localhost_client.jks"); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(keyStoreStream, "test1234".toCharArray()); - RestAssured.given().config(RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().trustStore(keyStore).and().allowAllHostnames())).when().get("https://localhost:8443/hello").then().spec(helloWorldSpec()); - } + RestAssured.given().config(RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().trustStore(keyStore).and().allowAllHostnames())).when().get("https://localhost:8443/hello").then().spec(helloWorldSpec()); + } - @Test public void - relaxed_https_validation_works_using_instance_config() { - RestAssured.given().config(RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().relaxedHTTPSValidation())).when().get("https://localhost:8443/hello").then().spec(helloWorldSpec()); - } + @Test + public void + relaxed_https_validation_works_using_instance_config() { + RestAssured.given().config(RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().relaxedHTTPSValidation())).when().get("https://localhost:8443/hello").then().spec(helloWorldSpec()); + } - @Ignore("Site is not working anymore") - @Test public void - relaxed_https_validation_works_using_instance_dsl() { - RestAssured.given().relaxedHTTPSValidation().when().get("https://bunny.cloudamqp.com/api/").then().statusCode(200); - } + @Ignore("Site is not working anymore") + @Test + public void + relaxed_https_validation_works_using_instance_dsl() { + RestAssured.given().relaxedHTTPSValidation().when().get("https://bunny.cloudamqp.com/api/").then().statusCode(200); + } - @Ignore("Site is not working anymore") - @Test public void - relaxed_https_validation_works_when_defined_statically() { - RestAssured.useRelaxedHTTPSValidation(); + @Ignore("Site is not working anymore") + @Test + public void + relaxed_https_validation_works_when_defined_statically() { + RestAssured.useRelaxedHTTPSValidation(); + + try { + RestAssured.get("https://bunny.cloudamqp.com/api/").then().statusCode(200); + } finally { + RestAssured.reset(); + } + } - try { - RestAssured.get("https://bunny.cloudamqp.com/api/").then().statusCode(200); - } finally { - RestAssured.reset(); + @Ignore("Site is not working anymore") + @Test + public void + relaxed_https_validation_works_when_defined_statically_with_base_uri() { + RestAssured.useRelaxedHTTPSValidation(); + RestAssured.baseURI = "https://bunny.cloudamqp.com"; + + try { + RestAssured.get("/api/").then().statusCode(200); + } finally { + RestAssured.reset(); + } } - } - @Ignore("Site is not working anymore") - @Test public void - relaxed_https_validation_works_when_defined_statically_with_base_uri() { - RestAssured.useRelaxedHTTPSValidation(); - RestAssured.baseURI = "https://bunny.cloudamqp.com"; + @Test + public void + truststore_works_with_static_base_uri() { + RestAssured.baseURI = "https://localhost:8443/hello"; - try { - RestAssured.get("/api/").then().statusCode(200); - } finally { - RestAssured.reset(); + try { + RestAssured.given().trustStore("/jetty_localhost_client.jks", "test1234").when().get().then().spec(helloWorldSpec()); + } finally { + RestAssured.reset(); + } + } + + @Ignore("Temporary ignored since site has changed") + @Test + public void + truststrore_works_with_static_base_uri() throws Exception { + RestAssured.baseURI = "https://bunny.cloudamqp.com/"; + + InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("truststore_cloudamqp.jks"); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(keyStoreStream, "cloud1234".toCharArray()); + + try { + RestAssured.given().trustStore(keyStore).when().get("/api/").then().statusCode(200); + } finally { + RestAssured.reset(); + } } - } - @Test public void - truststore_works_with_static_base_uri() { - RestAssured.baseURI = "https://localhost:8443/hello"; - try { - RestAssured.given().trustStore("/jetty_localhost_client.jks", "test1234").when().get().then().spec(helloWorldSpec()); - } finally { - RestAssured.reset(); + @Test + public void + can_make_request_to_sites_that_with_valid_ssl_cert() { + RestAssured.get("https://duckduckgo.com/").then().statusCode(200); } - } - @Ignore("Temporary ignored since site has changed") @Test public void - truststrore_works_with_static_base_uri() throws Exception{ - RestAssured.baseURI = "https://bunny.cloudamqp.com/"; + @Test + public void + allows_specifying_trust_store_statically_with_request_builder() throws Exception { + // Load the trust store + InputStream trustStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jetty_localhost_client.jks"); + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(trustStoreStream, "test1234".toCharArray()); - InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("truststore_cloudamqp.jks"); - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(keyStoreStream, "cloud1234".toCharArray()); + // Set the truststore on the global config + RestAssured.config = RestAssured.config().sslConfig(SSLConfig.sslConfig().trustStore(trustStore).and().allowAllHostnames()); - try { - RestAssured.given().trustStore(keyStore).when().get("/api/").then().statusCode(200); - } finally { - RestAssured.reset(); + final RequestSpecification spec = new RequestSpecBuilder().build(); + RestAssured.given().spec(spec).get("https://localhost:8443/hello").then().spec(helloWorldSpec()); } - } + @Test + public void + supports_setting_truststore_in_request_specification() { + final RequestSpecification spec = new RequestSpecBuilder().setTrustStore("/jetty_localhost_client.jks", "test1234").build(); + RestAssured.given().spec(spec).expect().spec(helloWorldSpec()).when().get("https://localhost:8443/hello"); + } - @Test public void - can_make_request_to_sites_that_with_valid_ssl_cert() { - RestAssured.get("https://duckduckgo.com/").then().statusCode(200); + @Test + public void + supports_overriding_truststore_in_request_specification() { + final RequestSpecification spec = new RequestSpecBuilder().setTrustStore("/jetty_localhost_client.jks", "wrong pw").build(); + RestAssured.given().spec(spec).trustStore("/jetty_localhost_client.jks", "test1234").expect().spec(helloWorldSpec()).when().get("https://localhost:8443/hello"); + } } - @Test public void - allows_specifying_trust_store_statically_with_request_builder() throws Exception { - // Load the trust store - InputStream trustStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jetty_localhost_client.jks"); - KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - trustStore.load(trustStoreStream, "test1234".toCharArray()); - - // Set the truststore on the global config - RestAssured.config = RestAssured.config().sslConfig(SSLConfig.sslConfig().trustStore(trustStore).and().allowAllHostnames()); + public static class TwoWaySSLTest extends WithJetty { - final RequestSpecification spec = new RequestSpecBuilder().build(); - RestAssured.given().spec(spec).get("https://localhost:8443/hello").then().spec(helloWorldSpec()); - } + @BeforeClass + public static void startJetty() throws Exception { + startJettyTwoWaySSL(); + } - @Test public void - supports_setting_truststore_in_request_specification() { - final RequestSpecification spec = new RequestSpecBuilder().setTrustStore("/jetty_localhost_client.jks", "test1234").build(); - RestAssured.given().spec(spec).expect().spec(helloWorldSpec()).when().get("https://localhost:8443/hello"); - } + @Test(expected = SSLException.class) + public void relaxed_https_validation_throws_exception_without_keystore() { + RestAssuredConfig sslConfig = RestAssuredConfig.config().sslConfig(SSLConfig.sslConfig().relaxedHTTPSValidation()); + RestAssured.given().config(sslConfig).when().get("https://localhost:8443/hello").then().spec(helloWorldSpec()); + } - @Test public void - supports_overriding_truststore_in_request_specification() { - final RequestSpecification spec = new RequestSpecBuilder().setTrustStore("/jetty_localhost_client.jks", "wrong pw").build(); - RestAssured.given().spec(spec).trustStore("/jetty_localhost_client.jks", "test1234").expect().spec(helloWorldSpec()).when().get("https://localhost:8443/hello"); + @Test + public void relaxed_https_validation_works_using_instance_config() { + RestAssuredConfig sslConfig = RestAssuredConfig.config().sslConfig( + SSLConfig.sslConfig() + .keyStore("keystore.p12", "test1234") + .keystoreType("PKCS12") + .relaxedHTTPSValidation() + ); + RestAssured.given().config(sslConfig).when().get("https://localhost:8443/hello").then().spec(helloWorldSpec()); + } } } diff --git a/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/support/WithJetty.java b/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/support/WithJetty.java index 34cbf3314..ca27e385b 100644 --- a/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/support/WithJetty.java +++ b/examples/rest-assured-itest-java/src/test/java/io/restassured/itest/java/support/WithJetty.java @@ -23,7 +23,17 @@ import org.eclipse.jetty.security.HashLoginService; import org.eclipse.jetty.security.LoginService; import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.server.*; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.HandlerList; +import org.eclipse.jetty.server.handler.SecuredRedirectHandler; import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.webapp.WebAppContext; @@ -33,7 +43,11 @@ import org.junit.Rule; import org.junit.rules.ExpectedException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.File; +import java.io.IOException; import java.util.Collections; import static io.restassured.itest.java.support.WithJetty.JettyOption.RESET_REST_ASSURED_BEFORE_TEST; @@ -61,6 +75,10 @@ protected WithJetty(JettyOption jettyOption) { @BeforeClass public static void startJetty() throws Exception { + startJettyOneWaySSL(); + } + + protected static void startJettyOneWaySSL() throws Exception { server = new Server(); HttpConfiguration httpConfig = new HttpConfiguration(); @@ -129,6 +147,46 @@ public static void startJetty() throws Exception { server.start(); } + protected static void startJettyTwoWaySSL() throws Exception { + server = new Server(); + int httpsPort = 8443; + + // Setup HTTP Connector + HttpConfiguration httpConf = new HttpConfiguration(); + httpConf.setSecurePort(httpsPort); + httpConf.setSecureScheme("https"); + + // Setup SSL + String keystore = WithJetty.class.getClassLoader().getResource("keystore.p12").getFile(); + SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setKeyStorePath(keystore); + sslContextFactory.setKeyStorePassword("test1234"); + sslContextFactory.setTrustAll(true); + sslContextFactory.setNeedClientAuth(true); + + // Setup HTTPS Configuration + HttpConfiguration httpsConf = new HttpConfiguration(); + httpsConf.setSecureScheme("https"); + httpsConf.setSecurePort(httpsPort); + httpsConf.addCustomizer(new SecureRequestCustomizer()); + + // Establish the HTTPS ServerConnector + ServerConnector httpsConnector = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConf)); + httpsConnector.setPort(httpsPort); + + server.addConnector(httpsConnector); + + // Add a Handlers for requests + HandlerList handlers = new HandlerList(); + handlers.addHandler(new SecuredRedirectHandler()); + handlers.addHandler(new HelloHandler()); + server.setHandler(handlers); + + server.start(); + } + private static void dontSendDateHeader(Server server) { // Remove the sending of date header since it makes testing of logging much harder for (Connector y : server.getConnectors()) { @@ -167,4 +225,15 @@ public enum JettyOption { RESET_REST_ASSURED_BEFORE_TEST, DONT_RESET_REST_ASSURED_BEFORE_TEST } + + private static class HelloHandler extends AbstractHandler { + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + response.setContentType("text/json;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + baseRequest.setHandled(true); + response.getWriter().println("{\"hello\": \"Hello Scalatra\"}"); + } + } } diff --git a/examples/rest-assured-itest-java/src/test/resources/keystore.p12 b/examples/rest-assured-itest-java/src/test/resources/keystore.p12 new file mode 100644 index 000000000..d07388ef3 Binary files /dev/null and b/examples/rest-assured-itest-java/src/test/resources/keystore.p12 differ diff --git a/rest-assured/src/main/java/io/restassured/config/SSLConfig.java b/rest-assured/src/main/java/io/restassured/config/SSLConfig.java index 4540eff2a..e51b99330 100644 --- a/rest-assured/src/main/java/io/restassured/config/SSLConfig.java +++ b/rest-assured/src/main/java/io/restassured/config/SSLConfig.java @@ -22,14 +22,23 @@ import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.conn.ssl.X509HostnameVerifier; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.security.KeyManagementException; import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import static org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; @@ -246,8 +255,10 @@ public SSLConfig trustStore(KeyStore trustStore) { } /** - * Use relaxed HTTP validation. This means that you'll trust all hosts regardless if the SSL certificate is invalid. By using this - * method you don't need to specify a keystore (see {@link #keyStore(String, String)} or trust store (see {@link #trustStore(java.security.KeyStore)}. + * Use relaxed HTTP validation. This means that you'll trust all hosts regardless if the SSL certificate is invalid. + * By using this method you don't need to specify a trust store (see {@link #trustStore(java.security.KeyStore)}. + * If you need to send an SSL certificate, then you can specify a key store (see {@link #keyStore(File, String)} + * and a key store type (see {@link #keystoreType(String)} before calling this method. * This method assumes that the protocol for the {@link SSLContext} instance is {@value #SSL}. If this is not the case use {@link #relaxedHTTPSValidation(String)}. * * @return A new SSLConfig instance. @@ -257,8 +268,10 @@ public SSLConfig relaxedHTTPSValidation() { } /** - * Use relaxed HTTP validation. This means that you'll trust all hosts regardless if the SSL certificate is invalid. By using this - * method you don't need to specify a keystore (see {@link #keyStore(String, String)} or trust store (see {@link #trustStore(java.security.KeyStore)}. + * Use relaxed HTTP validation. This means that you'll trust all hosts regardless if the SSL certificate is invalid. + * By using this method you don't need to specify a trust store (see {@link #trustStore(java.security.KeyStore)}. + * If you need to send an SSL certificate, then you can specify a key store (see {@link #keyStore(File, String)} + * and a key store type (see {@link #keystoreType(String)} before calling this method * * @param protocol The standard name of the requested protocol. See the SSLContext section in the Java Cryptography Architecture Standard Algorithm Name Documentation for information about standard protocol names. * @return A new SSLConfig instance @@ -272,9 +285,18 @@ public SSLConfig relaxedHTTPSValidation(String protocol) { return SafeExceptionRethrower.safeRethrow(e); } - // Set up a TrustManager that trusts everything try { - sslContext.init(null, new TrustManager[]{new X509TrustManager() { + // Set up a KeyManager to use with relaxed HTTPS validation + KeyStore relaxedKeyStore = loadKeyStore(); + KeyManager[] keyManagers = null; + if (relaxedKeyStore != null) { + KeyManagerFactory kmf = + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(relaxedKeyStore, keyStorePassword.toCharArray()); + keyManagers = kmf.getKeyManagers(); + } + // Set up a TrustManager that trusts everything + sslContext.init(keyManagers, new TrustManager[]{new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } @@ -285,7 +307,7 @@ public void checkClientTrusted(X509Certificate[] certs, String authType) { public void checkServerTrusted(X509Certificate[] certs, String authType) { } }}, new SecureRandom()); - } catch (KeyManagementException e) { + } catch (KeyManagementException | UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) { return SafeExceptionRethrower.safeRethrow(e); } @@ -451,8 +473,49 @@ public X509HostnameVerifier getX509HostnameVerifier() { /** * @return true if user has configured this SSL Configuration instance, false otherwise. */ + @Override public boolean isUserConfigured() { return isUserConfigured; } + private KeyStore loadKeyStore() { + if (pathToKeyStore == null) { + return null; + } + + InputStream resource; + try { + if (pathToKeyStore instanceof String) { + String keyStorePath = (String) pathToKeyStore; + if (keyStorePath.trim().isEmpty()) { + return null; + } + resource = Thread.currentThread().getContextClassLoader().getResourceAsStream(keyStorePath); + if (resource == null) { // To allow for backward compatibility + resource = getClass().getResourceAsStream(keyStorePath); + } + if (resource == null) { // Fallback to load path as file if not found in classpath + resource = new FileInputStream(keyStorePath); + } + } else { + resource = new FileInputStream((File) pathToKeyStore); + } + } catch (FileNotFoundException e) { + return SafeExceptionRethrower.safeRethrow(e); + } + + try { + KeyStore relaxedKeyStore = KeyStore.getInstance(keyStoreType); + relaxedKeyStore.load(resource, keyStorePassword.toCharArray()); + return relaxedKeyStore; + } catch (IOException | KeyStoreException | CertificateException | NoSuchAlgorithmException e) { + return SafeExceptionRethrower.safeRethrow(e); + } finally { + try { + resource.close(); + } catch (IOException e) { + // Nothing to do + } + } + } }