package pl.touk.sputnik.connector.http; import com.github.tomakehurst.wiremock.junit.WireMockRule; import org.apache.http.HttpHost; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import pl.touk.sputnik.configuration.ConfigurationBuilder; import pl.touk.sputnik.configuration.GeneralOption; import pl.touk.sputnik.connector.ConnectorDetails; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLPeerUnverifiedException; import java.util.Properties; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static com.googlecode.catchexception.CatchException.caughtException; import static com.googlecode.catchexception.apis.CatchExceptionAssertJ.then; import static com.googlecode.catchexception.apis.CatchExceptionAssertJ.when; import static org.assertj.core.api.Assertions.assertThat; public class SslVerificationTest { @Rule public WireMockRule trustedService = new WireMockRule(wireMockConfig().dynamicPort().dynamicHttpsPort() .keystorePath(this.getClass().getResource("/ssl/trusted/keystore.jks").getPath()).keystorePassword("changeit")); @Rule public WireMockRule untrustedService = new WireMockRule(wireMockConfig().dynamicPort().dynamicHttpsPort() .keystorePath(this.getClass().getResource("/ssl/untrusted/keystore.jks").getPath()).keystorePassword("changeit")); @Before public void setUp() { untrustedService.stubFor(get(urlEqualTo("/hello")).willReturn(aResponse().withStatus(200))); trustedService.stubFor(get(urlEqualTo("/hello")).willReturn(aResponse().withStatus(200))); } @Test public void doNotVerifySslTrustWhenVerificationIsOff() throws Exception { // given ConnectorDetails connectorDetails = buildConnectorDetails("localhost", untrustedService.httpsPort(), "true", "false"); HttpHelper httpHelper = new HttpHelper(); HttpHost httpHost = httpHelper.buildHttpHost(connectorDetails); CloseableHttpClient closeableHttpClient = httpHelper.buildClient(httpHost, connectorDetails); // when CloseableHttpResponse response = closeableHttpClient.execute(httpHost, new HttpGet("/hello")); // then assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); } @Test public void doNotVerifyHostnameWhenVerificationIsOff() throws Exception { // given ConnectorDetails connectorDetails = buildConnectorDetails("127.0.0.1", trustedService.httpsPort(), "true", "false"); HttpHelper httpHelper = new HttpHelper(); HttpHost httpHost = httpHelper.buildHttpHost(connectorDetails); CloseableHttpClient closeableHttpClient = httpHelper.buildClient(httpHost, connectorDetails); // when CloseableHttpResponse response = closeableHttpClient.execute(httpHost, new HttpGet("/hello")); // then assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); } @Test public void verifySslTrust() throws Exception { // given setSystemTrustStore(); ConnectorDetails connectorDetails = buildConnectorDetails("localhost", trustedService.httpsPort(), "true", "true"); HttpHelper httpHelper = new HttpHelper(); HttpHost httpHost = httpHelper.buildHttpHost(connectorDetails); CloseableHttpClient closeableHttpClient = httpHelper.buildClient(httpHost, connectorDetails); // when CloseableHttpResponse response = closeableHttpClient.execute(httpHost, new HttpGet("/hello")); // then assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); } @Test public void verifySslTrustThrowsSSLHandshakeException() throws Exception { // given ConnectorDetails connectorDetails = buildConnectorDetails("localhost", untrustedService.httpsPort(), "true", "true"); HttpHelper httpHelper = new HttpHelper(); HttpHost httpHost = httpHelper.buildHttpHost(connectorDetails); CloseableHttpClient closeableHttpClient = httpHelper.buildClient(httpHost, connectorDetails); // when when(closeableHttpClient).execute(httpHost, new HttpGet("/hello")); // then then(caughtException()).isInstanceOf(SSLHandshakeException.class); } @Test public void useDefaultTrustStoreToVerifySslTrust() throws Exception { // given ConnectorDetails connectorDetails = buildConnectorDetails("localhost", untrustedService.httpsPort(), "true", "true"); HttpHelper httpHelper = new HttpHelper(); HttpHost httpHost = httpHelper.buildHttpHost(connectorDetails); CloseableHttpClient closeableHttpClient = httpHelper.buildClient(httpHost, connectorDetails); // when when(closeableHttpClient).execute(httpHost, new HttpGet("/hello")); // then then(caughtException()).isInstanceOf(SSLHandshakeException.class); } @Test public void verifyHostnameThrowsSSLPeerUnverifiedExceptionWhenHostDoesNotMatch() throws Exception { // given setSystemTrustStore(); ConnectorDetails connectorDetails = buildConnectorDetails("127.0.0.1", trustedService.httpsPort(), "true", "true"); HttpHelper httpHelper = new HttpHelper(); HttpHost httpHost = httpHelper.buildHttpHost(connectorDetails); CloseableHttpClient closeableHttpClient = httpHelper.buildClient(httpHost, connectorDetails); // when when(closeableHttpClient).execute(httpHost, new HttpGet("/hello")); // then then(caughtException()).isInstanceOf(SSLPeerUnverifiedException.class); } private void setSystemTrustStore() { System.setProperty("javax.net.ssl.trustStore", this.getClass().getResource("/ssl/trusted/cacerts.jks").getPath()); System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); } private ConnectorDetails buildConnectorDetails(String host, int port, String useHttps, String verifySsl) { Properties properties = new Properties(); properties.setProperty(GeneralOption.HOST.getKey(), host); properties.setProperty(GeneralOption.PORT.getKey(), Integer.toString(port)); properties.setProperty(GeneralOption.USE_HTTPS.getKey(), useHttps); properties.setProperty(GeneralOption.VERIFY_SSL.getKey(), verifySsl); return new ConnectorDetails(ConfigurationBuilder.initFromProperties(properties)); } }