5

I have defined a https stub in wiremock as follows:-

public class HttpsMockMain {
    public static void main(String[] args) {
        WireMockServer mockServer = new WireMockServer(56789, 8443);
            addStub(mockServer);
            mockServer.start();
    }
    private static void addStub(WireMockServer mockServer) {
        ResponseDefinitionBuilder responseBuilder = aResponse().withStatus(200).withBody(
        "{\"message\":null,\"httpStatus\":0,\"status\":{\"httpStatusCode\":200,\"success\":true,\"errors\":[]},\"_metaData\":{\"urlParams\":{}},\"debugData\":null,\"data\":[\"01125851014\",\"01125851014\",\"debraj.manna@jabong.com\",\"03325853088\",\"03325853088\",\"debraj.manna@rediffmail.com\"],\"httpStatusToBeReturned\":200}");
        mockServer.stubFor(post(urlPathEqualTo("/oms-api/")).willReturn(responseBuilder));
    }
}

Whenever I am sending a POST request to https://localhost:8443/oms-api/ I am getting the below exception:-

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

Is it possible to tell WireMock to accept any certificate? I am on wiremock 1.58 and java 1.8.

tuk
  • 5,941
  • 14
  • 79
  • 162

4 Answers4

3

As discussed here, the issue was not on Wiremock side it is the client code rejecting WireMock's self-signed certificate (which was right, as the client was not configured to use wiremock certificate.).

tuk
  • 5,941
  • 14
  • 79
  • 162
2

I see you cross-posted in WireMock github page and here.. OK let me just put it here.

I see this in the documentation of WireMock: http://wiremock.org/docs/https/

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

You are using WireMock’s default (self-signed) TLS certificate or another certificate that isn’t signed by a CA. In this case you need to specifically configure your HTTP client to trust the certificate being presented, or to trust all certificates. Here is an example of how to do this with the Apache HTTP client.

Example in the link:

/*
 * Copyright (C) 2011 Thomas Akehurst
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.tomakehurst.wiremock.http;

import com.github.tomakehurst.wiremock.common.KeyStoreSettings;
import com.github.tomakehurst.wiremock.common.ProxySettings;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;

import javax.net.ssl.SSLContext;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import static com.github.tomakehurst.wiremock.common.Exceptions.throwUnchecked;
import static com.github.tomakehurst.wiremock.common.KeyStoreSettings.NO_STORE;
import static com.github.tomakehurst.wiremock.common.LocalNotifier.notifier;
import static com.github.tomakehurst.wiremock.common.ProxySettings.NO_PROXY;
import static com.github.tomakehurst.wiremock.http.RequestMethod.*;
import static org.apache.commons.lang3.StringUtils.isEmpty;

public class HttpClientFactory {

    public static final int DEFAULT_MAX_CONNECTIONS = 50;
    public static final int DEFAULT_TIMEOUT = 30000;

    public static CloseableHttpClient createClient(
            int maxConnections,
            int timeoutMilliseconds,
            ProxySettings proxySettings,
            KeyStoreSettings trustStoreSettings) {

        HttpClientBuilder builder = HttpClientBuilder.create()
                .disableAuthCaching()
                .disableAutomaticRetries()
                .disableCookieManagement()
                .disableRedirectHandling()
                .disableContentCompression()
                .setMaxConnTotal(maxConnections)
                .setDefaultRequestConfig(RequestConfig.custom().setStaleConnectionCheckEnabled(true).build())
                .setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(timeoutMilliseconds).build())
                .useSystemProperties()
                .setHostnameVerifier(new AllowAllHostnameVerifier());

        if (proxySettings != NO_PROXY) {
            HttpHost proxyHost = new HttpHost(proxySettings.host(), proxySettings.port());
            builder.setProxy(proxyHost);
            if(!isEmpty(proxySettings.getUsername()) && !isEmpty(proxySettings.getPassword())) {
                builder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
                BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                credentialsProvider.setCredentials(
                        new AuthScope(proxySettings.host(), proxySettings.port()),
                        new UsernamePasswordCredentials(proxySettings.getUsername(), proxySettings.getPassword()));
                builder.setDefaultCredentialsProvider(credentialsProvider);
            }
        }

        if (trustStoreSettings != NO_STORE) {
            builder.setSslcontext(buildSSLContextWithTrustStore(trustStoreSettings));
        } else {
            builder.setSslcontext(buildAllowAnythingSSLContext());
        }

        return builder.build();
    }

    private static SSLContext buildSSLContextWithTrustStore(KeyStoreSettings trustStoreSettings) {
        try {
            KeyStore trustStore = trustStoreSettings.loadStore();
            return SSLContexts.custom()
                    .loadTrustMaterial(null, new TrustSelfSignedStrategy())
                    .loadKeyMaterial(trustStore, trustStoreSettings.password().toCharArray())
                    .useTLS()
                    .build();
        } catch (Exception e) {
            return throwUnchecked(e, SSLContext.class);
        }
    }

    private static SSLContext buildAllowAnythingSSLContext() {
        try {
            return SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
        } catch (Exception e) {
            return throwUnchecked(e, SSLContext.class);
        }
    }

    public static CloseableHttpClient createClient(int maxConnections, int timeoutMilliseconds) {
        return createClient(maxConnections, timeoutMilliseconds, NO_PROXY, NO_STORE);
    }

    public static CloseableHttpClient createClient(int timeoutMilliseconds) {
        return createClient(DEFAULT_MAX_CONNECTIONS, timeoutMilliseconds);
    }

    public static CloseableHttpClient createClient(ProxySettings proxySettings) {
        return createClient(DEFAULT_MAX_CONNECTIONS, DEFAULT_TIMEOUT, proxySettings, NO_STORE);
    }

    public static CloseableHttpClient createClient() {
      return createClient(DEFAULT_TIMEOUT);
    }

    public static HttpUriRequest getHttpRequestFor(RequestMethod method, String url) {
        notifier().info("Proxying: " + method + " " + url);

        if (method.equals(GET))
            return new HttpGet(url);
        else if (method.equals(POST))
            return new HttpPost(url);
        else if (method.equals(PUT))
            return new HttpPut(url);
        else if (method.equals(DELETE))
            return new HttpDelete(url);
        else if (method.equals(HEAD))
            return new HttpHead(url);
        else if (method.equals(OPTIONS))
            return new HttpOptions(url);
        else if (method.equals(TRACE))
            return new HttpTrace(url);
        else if (method.equals(PATCH))
            return new HttpPatch(url);
        else
            return new GenericHttpUriRequest(method.toString(), url);
    }
}
WesternGun
  • 11,303
  • 6
  • 88
  • 157
0

Fegin client for integration tests should be made in additional to :

wireMockConfig()
    .httpsPort(8443)
    .keystorePath("/path/to/keystore.jks") 
    .keystorePassword("verysecret") 

Example of Client code:

public Client client() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, new TrustManager[] {new NoopTrustManager()}, new SecureRandom());
        return new Default(context.getSocketFactory(), NoopHostnameVerifier.INSTANCE);
    }


static final NoopHostnameVerifier INSTANCE = new NoopHostnameVerifier();
LvDevR1
  • 59
  • 3
0

When you run WireMock server, pause the program before it ends, and download the WireMock self signed certificate from the browser. Or, you can find a post in GitHub for Java Tool installcert.java which has more details to extract the certificate.

Then, use keytool to apply the certificate to your environment. You can create a trust store using this certificate or add it to cacerts or jssecacerts file in the designated Java JDK/JRE folder. If you create a trust store, make sure your program is using this trust store when creating SSLContext object. If you add it to the files under JRE mentioned above, I think it will work by default.

Then, you have to add this code block below to the test class to disable matching the CN of the certificate with the host name:

    static {
        //for localhost testing only
        javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(newJavaKeyword javax.net.ssl.HostnameVerifier() {
            public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
                if (hostname.equals("localhost")) {
                    return true;
                }
                return false;
            }
        });
    }

Note: replace the keyword above newJavaKeyword with new as it won't let me post it using new for some reason.

The self signed certificate of WireMock is marked with CN=Tom Akehurst and this will throw an exception ... unless ... you have added the code block above.

The following code can be used to start WireMock and put a breakpoint before it shuts down the server:

    private final static int WIREMOCK_PORT = 8089;
    private final static int WIREMOCK_PORT_SSL = 8443;
    private final static String BASE_URL = "http://localhost:" + WIREMOCK_PORT + "/";
    private final static String BASE_URL_SSL = "https://localhost:" + WIREMOCK_PORT_SSL + "/";

    @BeforeClass
    public static void setup() {
        System.out.println("This is the Setup Method");
        wireMockServer = new WireMockServer(options().port(WIREMOCK_PORT).httpsPort(WIREMOCK_PORT_SSL).notifier(new ConsoleNotifier(false)));
        wireMockServer.start();
    }
    
tarekahf
  • 738
  • 1
  • 16
  • 42