citrusframework / citrus

Framework for automated integration tests with focus on messaging integration
https://citrusframework.org
Apache License 2.0
459 stars 136 forks source link

Disable Certificate and hostname validation #926

Closed rathnapandi closed 1 year ago

rathnapandi commented 1 year ago

Citrus Version 3.4.0

Question

How to disable certificate and hostname verification? What I've tried so far I tried to set a custom apache httpClient on RestTemplate, but it is not working.

Spring config -

<bean id="httpClientAllowAllHosts" class="test.HttpClientAllowAllHosts"/>
   <bean id="httpClient" factory-bean="httpClientAllowAllHosts" factory-method="httpClient"/>
   <citrus-http:client id="httpsServer"
                        request-url="https://localhost:8443/api/v1.4"
                        request-method="GET"
                        content-type="application/json"
                        charset="UTF-8"
                        timeout="60000"
                        interceptors="clientInterceptors"
                        rest-template="customizedRestTemplate"/>

  <bean id="basicAuthFactory" class="com.consol.citrus.http.client.BasicAuthClientHttpRequestFactory">
        <property name="authScope">
            <bean class="org.apache.http.auth.AuthScope">
                <constructor-arg value="localhost"/>
                <constructor-arg value="8443"/>
                <constructor-arg value=""/>
                <constructor-arg value="basic"/>
            </bean>
        </property>
        <property name="credentials">
            <bean class="org.apache.http.auth.UsernamePasswordCredentials">
                <constructor-arg value="${username}"/>
                <constructor-arg value="${password}"/>
            </bean>
        </property>
    </bean>
    <bean name="customizedRestTemplate" class="org.springframework.web.client.RestTemplate">
        <property name="requestFactory">
            <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
                <property name="readTimeout" value="9000"/>
                <property name="httpClient" ref="httpClient"/>
            </bean>
        </property>
    </bean>

Java code -

public class HttpClientAllowAllHosts {    
 public HttpClient httpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {

    CloseableHttpClient httpClient = HttpClients
                .custom()
                .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
       return httpClient;
    }
}

Additional information

christophd commented 1 year ago

What is the error message that you get if you run the test?

You could also have a look at this sample: https://github.com/citrusframework/citrus-samples/blob/main/samples-http/sample-https/src/test/java/com/consol/citrus/samples/todolist/EndpointConfig.java

rathnapandi commented 1 year ago

Find below the exception, it is not taking the custom http client injected in request factory.

java.lang.AssertionError: Before suite failed with errors

at com.consol.citrus.Citrus.beforeSuite(Citrus.java:85)
at com.consol.citrus.testng.AbstractTestNGCitrusTest.beforeSuite(AbstractTestNGCitrusTest.java:216)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.testng.internal.invokers.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:139)
at org.testng.internal.invokers.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:69)
at org.testng.internal.invokers.ConfigInvoker.invokeConfigurationMethod(ConfigInvoker.java:361)
at org.testng.internal.invokers.ConfigInvoker.invokeConfigurations(ConfigInvoker.java:296)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:376)
at org.testng.SuiteRunner.run(SuiteRunner.java:330)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:95)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1256)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1176)
at org.testng.TestNG.runSuites(TestNG.java:1099)
at org.testng.TestNG.run(TestNG.java:1067)
at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:109)

Caused by: com.consol.citrus.exceptions.CitrusRuntimeException: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://localhost:8443/api/v1.4": PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at com.consol.citrus.container.SequenceBeforeSuite.doExecute(SequenceBeforeSuite.java:54) at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:59) at com.consol.citrus.Citrus.beforeSuite(Citrus.java:79) ... 19 more Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for ""https://localhost:8443/api/v1.4": PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:791) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:757) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:627) at com.consol.citrus.http.client.HttpClient.send(HttpClient.java:131) at com.consol.citrus.actions.SendMessageAction.doExecute(SendMessageAction.java:165) at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:59) at com.consol.citrus.container.SequenceBeforeSuite.doExecute(SequenceBeforeSuite.java:51) ... 21 more Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:259) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1329) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1204) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1151) at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:450) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:427) at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:178) at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164) at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152) at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063) at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:87) at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:109) at com.consol.citrus.http.interceptor.LoggingClientInterceptor.intercept(LoggingClientInterceptor.java:63) at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:93) at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:77) at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:782) ... 27 more Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385) at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:290) at java.base/sun.security.validator.Validator.validate(Validator.java:264) at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313) at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:222) at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1313) ... 59 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380) ... 65 more

rathnapandi commented 1 year ago

@christophd Thanks for the example link. I could fix the ssl issue by adding the following.

 public HttpComponentsClientHttpRequestFactory sslRequestFactory() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        return new HttpComponentsClientHttpRequestFactory(httpClient());
    }

 public HttpClient httpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {

        CloseableHttpClient httpClient = HttpClientBuilder.create()
                .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
        return httpClient;
    }
  <bean id="httpClientAllowAllHosts" class="test.HttpClientAllowAllHosts"/>

    <citrus-http:client id="apiManager"
                        request-url="https://localhost:8443/api/v1.4"
                        request-method="GET"
                        content-type="application/json"
                        charset="UTF-8"
                        timeout="60000"
                        interceptors="clientInterceptors"
                        request-factory="sslRequestFactory"
                        />

    <bean id="httpClient" factory-bean="httpClientAllowAllHosts" factory-method="httpClient"/>

    <bean id="sslRequestFactory" factory-bean="httpClientAllowAllHosts" factory-method="sslRequestFactory"/>

    <util:list id="clientInterceptors">
        <bean class="com.consol.citrus.http.interceptor.LoggingClientInterceptor"/>
        <bean class="test.BasicAuthInterceptor"/>
    </util:list>

If I setup Basic auth via Apache HttpClient, it is not working. Hence i added RestTemplate interceptor to add basic auth header. Do i miss anything here?

 public HttpClient httpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        HttpHost targetHost = new HttpHost(host, port);
        AuthScope scope = new AuthScope(targetHost);
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
        CredentialsProvider provider = new BasicCredentialsProvider();
        provider.setCredentials(scope, credentials);
        CloseableHttpClient httpClient = HttpClientBuilder.create()
                .setDefaultCredentialsProvider(provider)
                .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
        return httpClient;
    }
christophd commented 1 year ago

I am glad that you have found a solution. Closing