165

How do I bypass invalid SSL certificate errors with Apache HttpClient 4.0?

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
Viet
  • 17,944
  • 33
  • 103
  • 135
  • 12
    It should be noted that the answers to this question don't do more than what's asked: they let you ignore the error but don't fix the underlying problem (a bit like removing the batteries from a smoke alarm instead of putting out the fire). Certificates have a purpose in ensuring the security of the SSL/TLS connection, ignoring those errors introduces a vulnerability to MITM attack. Use test certificates instead of ignoring the error. – Bruno May 13 '12 at 22:42
  • 1
    Related to http://stackoverflow.com/questions/1828775/how-to-handle-invalid-ssl-certificates-with-apache-httpclient – Gray May 17 '12 at 17:14
  • 58
    "like removing the batteries from a smoke alarm" You might give other developers the benefit of the doubt and assume they know what they're doing. Perhaps the motivation for this question is local testing and the OP wishes to run a quick test without going through the horrible amounts of Java boilerplate necessary to set up even a simple SSL environment. Maybe someone could just answer the question without going into a "holier than thou" lecture. – Mike Jan 16 '14 at 18:42
  • I.e in our company internal JIRA server has some "windows security policy based cert" which is valid on Windows machines included in domain and not valid on other. I can't control this policy and still want to call JIRA REST API. – odiszapc Apr 05 '16 at 13:08
  • 4
    @Bruno The inability to disable smoke detectors for a period of 30-60 minutes while dealing with a small kitchen fire shows an insane lack of insight into usage patterns by some legal official at some point that I feel borders on criminal. The fact that there is a concept of "removing batteries from a smoke alarm" proves this. I feel about the same level of anger about having to get certificates to work for a simple test that I know doesn't have security ramifications. The existence of this question proves this. – Bill K Mar 21 '17 at 18:54
  • @BillK Sure, don't get me wrong, I've disabled that sort of verification myself for simple tests once in a while. The real problem is that most people understand the why it's a problem with smoke alarms. That's not so much the case in software development: these lines of codes won't generate errors, and it's very easy for various project stakeholders (especially those who don't get near the code) to push for a product release without realising the consequences. Fixing things that don't cause errors is generally not a priority, especially when you have a deadline. – Bruno Mar 21 '17 at 20:26
  • @Bruno Sounds like I agree--My point would be that to not recognize that this is an issue is a design flaw. If the designers were more aware of this issue they might have given us a command line -Dignore_certs_unsafe=true to disable cert checking completely. This is a pretty exact match to the fire alarm analogy where they should just have a button to disable it for 30 minutes instead of a law that it can't be disabled. Sometimes what is perceived as more security is actually less security in practice :) – Bill K Mar 24 '17 at 21:11
  • Hmm, and actually that might be a good way to implement this hack--setting a -D variable that you enable in your dev launch environment but never prod which would eliminate your concern about forgetting it. – Bill K Mar 24 '17 at 21:12
  • If you don't want it secure why are you using SSL at all? – user207421 May 11 '17 at 12:20

25 Answers25

124

All of the other answers were either deprecated or didn't work for HttpClient 4.3.

Here is a way to allow all hostnames when building an http client.

CloseableHttpClient httpClient = HttpClients
    .custom()
    .setHostnameVerifier(new AllowAllHostnameVerifier())
    .build();

Or if you are using version 4.4 or later, the updated call looks like this:

CloseableHttpClient httpClient = HttpClients
    .custom()
    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
    .build();
kapex
  • 28,903
  • 6
  • 107
  • 121
Eric
  • 2,573
  • 1
  • 23
  • 19
  • Thanks for the answer, I would like to know from which package is HttpsClients as I'm using in Android compile("org.apache.httpcomponents:httpclient:4.3.4") but this class doesn't appear. – Juan Saravia Nov 15 '14 at 15:27
  • 1
    It's package is org.apache.http.impl.client.HttpClients . – Eric Nov 17 '14 at 15:11
  • 20
    This works around a host name mismatch (I assume), but it doesn't seem to work when the certificate isn't signed by a trusted authority. – twm Jan 25 '17 at 17:56
  • 1
    @twm that's why it says it "allows all hostnames", trust issues require different configuration. – eis Aug 30 '17 at 06:15
  • 1
    @eis, I was pointing out that this answer addresses the original question in certain cases but not others. – twm Aug 30 '17 at 15:18
98

You need to create a SSLContext with your own TrustManager and create HTTPS scheme using this context. Here is the code,

SSLContext sslContext = SSLContext.getInstance("SSL");

// set up a TrustManager that trusts everything
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                    System.out.println("getAcceptedIssuers =============");
                    return null;
            }

            public void checkClientTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkClientTrusted =============");
            }

            public void checkServerTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkServerTrusted =============");
            }
} }, new SecureRandom());

SSLSocketFactory sf = new SSLSocketFactory(sslContext);
Scheme httpsScheme = new Scheme("https", 443, sf);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);

// apache HttpClient version >4.2 should use BasicClientConnectionManager
ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
HttpClient httpClient = new DefaultHttpClient(cm);
Gray
  • 115,027
  • 24
  • 293
  • 354
ZZ Coder
  • 74,484
  • 29
  • 137
  • 169
  • 1
    Say I don't want to buy valid SSL certificate for my site and just want to use it, this piece of code can help? How come I don't see any part where a URL is needed or exception handling is needed? – Viet Apr 24 '10 at 10:56
  • 1
    As you can see the X509TrustManager doesn't check for anything and doesn't throw any exceptions so any cert is accepted. – ZZ Coder Apr 24 '10 at 13:19
  • 21
    Hmm, it's telling me that 'new SSLSocketFactory(ssslCont)' is expecting a KeyStore, not an SSLContext. Am I missing something? – MSpeed Apr 05 '12 at 15:20
  • For some reason the Jelatic and Heroku jetty and tomcat servers can't pick up on this code whereas AWS beanstalk's tomcat understands and runs it just fine ... strange. – pulkitsinghal Jan 03 '13 at 17:08
  • 3
    I get the error that an X509TrustManager can't be cast to a TrustManager. – MW. Jan 16 '13 at 19:36
  • 4
    Make sure that you import the correct packages, i.e. from org.apache.http. – rantoniuk Jun 21 '13 at 19:48
  • 1
    The way to create and configure an SSLContext is revised in 4.3: SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).useTLS().build(); – Jason Dec 17 '13 at 00:44
  • 3
    Anyone know how to throw all this together using `HttpClientBuilder`? – Ali Feb 13 '14 at 05:10
  • It works for me and SSLContext, TrustManager and X509TrustManager are all from package javax.net.ssl – alfonx Jun 02 '15 at 22:06
  • which version of HttpClient you're using ? –  Jan 07 '16 at 13:54
  • This technique is totally and utterly insecure. Do not use. Import the sever certificate into the client trust store, or gets the server certificate signed by a CA. – user207421 May 11 '17 at 12:17
  • Still getting Certificate for <....> doesn't match any of the.... – Nathan B Feb 01 '22 at 16:27
83

Apache HttpClient 4.5.5

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

No deprecated API has been used.

Simple verifiable test case:

package org.apache.http.client.test;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

public class ApacheHttpClientTest {

    private HttpClient httpClient;

    @Before
    public void initClient() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
        httpClient = HttpClients
                .custom()
                .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
    }

    @Test
    public void apacheHttpClient455Test() throws IOException {
        executeRequestAndVerifyStatusIsOk("https://expired.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://wrong.host.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://self-signed.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://untrusted-root.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://revoked.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://pinning-test.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://sha1-intermediate.badssl.com");
    }

    private void executeRequestAndVerifyStatusIsOk(String url) throws IOException {
        HttpUriRequest request = new HttpGet(url);

        HttpResponse response = httpClient.execute(request);
        int statusCode = response.getStatusLine().getStatusCode();

        assert statusCode == 200;
    }
}
Mikhail Kholodkov
  • 23,642
  • 17
  • 61
  • 78
  • 2
    Thank you! Just change `TrustAllStrategy.INSTANCE` with `TrustSelfSignedStrategy.INSTANCE` in this answer. – Percy Vega Sep 16 '19 at 16:18
  • This did not work for me. 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 – ggb667 Jun 22 '20 at 13:10
  • 2
    @ggb667 I don't find `TrustAllStrategy.INSTANCE`, but I try implement it by myself: `new SSLContextBuilder().loadTrustMaterial(null, (chain, authType) -> true).build()` and it has worked. – Svichkarev Anatoly Nov 18 '20 at 13:42
  • .setSSLContext() in the 4.5.6 apache dependency actually throws and error? Changing it to .setSslContext() made the error go away?? Unless they changed it in 4.5.6, it should be .setSslContext() with a lowercase "Ssl" – whyoz May 26 '21 at 00:00
  • 1
    This answer worked but not without @SvichkarevAnatoly 's comment. Thanks to both!! – WISERDIVISOR Mar 29 '23 at 11:06
62

Just had to do this with the newer HttpClient 4.5 and it seems like they've deprecated a few things since 4.4 so here's the snippet that works for me and uses the most recent API:

final SSLContext sslContext = new SSLContextBuilder()
        .loadTrustMaterial(null, (x509CertChain, authType) -> true)
        .build();

return HttpClientBuilder.create()
        .setSSLContext(sslContext)
        .setConnectionManager(
                new PoolingHttpClientConnectionManager(
                        RegistryBuilder.<ConnectionSocketFactory>create()
                                .register("http", PlainConnectionSocketFactory.INSTANCE)
                                .register("https", new SSLConnectionSocketFactory(sslContext,
                                        NoopHostnameVerifier.INSTANCE))
                                .build()
                ))
        .build();
rustyx
  • 80,671
  • 25
  • 200
  • 267
Z4-
  • 1,851
  • 14
  • 17
34

Just for the record, there is a much simpler way to accomplish the same with HttpClient 4.1

    SSLSocketFactory sslsf = new SSLSocketFactory(new TrustStrategy() {

        public boolean isTrusted(
                final X509Certificate[] chain, String authType) throws CertificateException {
            // Oh, I am easy...
            return true;
        }

    });
ok2c
  • 26,450
  • 5
  • 63
  • 71
29

For the record, tested with httpclient 4.3.6 and compatible with Executor of fluent api:

CloseableHttpClient httpClient = HttpClients.custom().
                    setHostnameVerifier(new AllowAllHostnameVerifier()).
                    setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy()
                    {
                        public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
                        {
                            return true;
                        }
                    }).build()).build();
STM
  • 954
  • 6
  • 16
  • 3
    For HttpClient 4.4 upwards, you have to do this -- and may also need to create an `SSLConnectionSocketFactory` using that `SSLContext`, and define this in a `Registry`, if you're going to create a `PoolingHttpClientConnectionManager`. The other answers are more popular, but don't work at HttpClient 4.4. – Thomas W Mar 04 '15 at 05:13
  • 1
    Works exactly like this with httpclient-4.3.5.jar. – Harald Jan 28 '16 at 13:07
  • works with httpclient 4.3.2 – Naveen Yalla Oct 06 '21 at 08:37
18

For Apache HttpClient 4.4:

HttpClientBuilder b = HttpClientBuilder.create();

SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
        return true;
    }
}).build();
b.setSslcontext( sslContext);

// or SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken
HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.getSocketFactory())
        .register("https", sslSocketFactory)
        .build();

// allows multi-threaded use
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry);
b.setConnectionManager( connMgr);

HttpClient client = b.build();

This is extracted from our actual working implementation.

The other answers are popular, but for HttpClient 4.4 they don't work. I spent hours trying & exhausting possibilities, but there seems to have been extremely major API change & relocation at 4.4.

See also a slightly fuller explanation at: http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/

Hope that helps!

Thomas W
  • 13,940
  • 4
  • 58
  • 76
14

If all you want to do is get rid of invalid hostname errors you can just do:

HttpClient httpClient = new DefaultHttpClient();
SSLSocketFactory sf = (SSLSocketFactory)httpClient.getConnectionManager()
    .getSchemeRegistry().getScheme("https").getSocketFactory();
sf.setHostnameVerifier(new AllowAllHostnameVerifier());
David Tinker
  • 9,383
  • 9
  • 66
  • 98
  • 8
    The sf.setHostnameVerifier method has been deprecated as of 4.1. The alternative is to use one of the constructors. For example: `SSLSocketFactory sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);` – kaliatech Jun 01 '11 at 21:04
9

We are using HTTPClient 4.3.5 and we tried almost all solutions exist on the stackoverflow but nothing, After thinking and figuring out the problem, we come to the following code which works perfectly, just add it before creating HttpClient instance.

some method to call when making post requests....

SSLContextBuilder builder = new SSLContextBuilder();
    builder.loadTrustMaterial(null, new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            return true;
        }
    });

    SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(builder.build(),
            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslSF).build();
    HttpPost postRequest = new HttpPost(url);

continue your request in the normal form

Hamed MP
  • 5,443
  • 3
  • 39
  • 37
7

With fluent 4.5.2 i had to make the following modification to make it work.

try {
    TrustManager[] trustAllCerts = new TrustManager[] {
       new X509TrustManager() {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
    }
    public void checkClientTrusted(X509Certificate[] certs, String authType) {  }

    public void checkServerTrusted(X509Certificate[] certs, String authType) {  }
    }
    };

    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new SecureRandom());
    CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setSslcontext(sc).build();

    String output = Executor.newInstance(httpClient).execute(Request.Get("https://127.0.0.1:3000/something")
                                      .connectTimeout(1000)
                                      .socketTimeout(1000)).returnContent().asString();
    } catch (Exception e) {
    }
Talespin_Kit
  • 20,830
  • 29
  • 89
  • 135
  • 1
    This is the only solution that worked for me. I tried the above solutions for 4.3 and 4.4 before upgrading to 4.5 and trying this. – YoungDinosaur Oct 28 '16 at 22:12
6

This is how I did it -

  1. Create my own MockSSLSocketFactory (Class attached below)
  2. Use it to initialise DefaultHttpClient. Proxy settings need to be provided if a proxy is used.

Initialising DefaultHTTPClient -

SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
    schemeRegistry.register(new Scheme("https", 443, new MockSSLSocketFactory()));
    ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);

    DefaultHttpClient httpclient = new DefaultHttpClient(cm);

Mock SSL Factory -

public class MockSSLSocketFactory extends SSLSocketFactory {

public MockSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
    super(trustStrategy, hostnameVerifier);
}

private static final X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
    @Override
    public void verify(String host, SSLSocket ssl) throws IOException {
        // Do nothing
    }

    @Override
    public void verify(String host, X509Certificate cert) throws SSLException {
        //Do nothing
    }

    @Override
    public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
        //Do nothing
    }

    @Override
    public boolean verify(String s, SSLSession sslSession) {
        return true; 
    }
};

private static final TrustStrategy trustStrategy = new TrustStrategy() {
    @Override
    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        return true;
    }
};
}

If behind a proxy, need to do this -

HttpParams params = new BasicHttpParams();
    params.setParameter(AuthPNames.PROXY_AUTH_PREF, getClientAuthPrefs());

DefaultHttpClient httpclient = new DefaultHttpClient(cm, params);

httpclient.getCredentialsProvider().setCredentials(
                        new AuthScope(proxyHost, proxyPort),
                        new UsernamePasswordCredentials(proxyUser, proxyPass));
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
Swaroop Rath
  • 141
  • 1
  • 4
  • 1
    It would help if you included the imports in the future. There are two different classes. – Johann Dec 06 '12 at 17:16
5

In extension to ZZ Coder's answer it will be nice to override the hostnameverifier.

// ...
SSLSocketFactory sf = new SSLSocketFactory (sslContext);
sf.setHostnameVerifier(new X509HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }

    public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
    }

    public void verify(String host, X509Certificate cert) throws SSLException {
    }

    public void verify(String host, SSLSocket ssl) throws IOException {
    }
});
// ...
Community
  • 1
  • 1
eldur
  • 256
  • 3
  • 4
  • 1
    You can achieve the same by just doing `sf.setHostnameVerifier(new AllowAllHostnameVerifier());` – Dan Dyer May 05 '11 at 19:57
  • 7
    The sf.setHostnameVerifier has been deprecated as of 4.1. The alternative is to use one of the constructors. For example: `SSLSocketFactory sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);` – kaliatech Jun 01 '11 at 21:03
5

Tested with HttpClient 4.5.5 with Fluent API

final SSLContext sslContext = new SSLContextBuilder()
    .loadTrustMaterial(null, (x509CertChain, authType) -> true).build();

CloseableHttpClient httpClient = HttpClients.custom()
    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
    .setSSLContext(sslContext).build();

String result = Executor.newInstance(httpClient)
    .execute(Request.Get("https://localhost:8080/someapi")
    .connectTimeout(1000).socketTimeout(1000))
    .returnContent().asString();
Lachesis
  • 51
  • 1
  • 2
4
        DefaultHttpClient httpclient = new DefaultHttpClient();

    SSLContext sslContext;
    try {
        sslContext = SSLContext.getInstance("SSL");

        // set up a TrustManager that trusts everything
        try {
            sslContext.init(null,
                    new TrustManager[] { new X509TrustManager() {
                        public X509Certificate[] getAcceptedIssuers() {
                            log.debug("getAcceptedIssuers =============");
                            return null;
                        }

                        public void checkClientTrusted(
                                X509Certificate[] certs, String authType) {
                            log.debug("checkClientTrusted =============");
                        }

                        public void checkServerTrusted(
                                X509Certificate[] certs, String authType) {
                            log.debug("checkServerTrusted =============");
                        }
                    } }, new SecureRandom());
        } catch (KeyManagementException e) {
        }
         SSLSocketFactory ssf = new SSLSocketFactory(sslContext,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
         ClientConnectionManager ccm = this.httpclient.getConnectionManager();
         SchemeRegistry sr = ccm.getSchemeRegistry();
         sr.register(new Scheme("https", 443, ssf));            
    } catch (Exception e) {
        log.error(e.getMessage(),e);
    }
littletiger
  • 651
  • 1
  • 8
  • 14
4

To accept all certificates in HttpClient 4.4.x you can use the following one liner when creating the httpClient:

httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, (x509Certificates, s) -> true).build()).build();
Chilly
  • 578
  • 4
  • 11
  • I am getting this: Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present? –  Jan 07 '16 at 10:33
  • How to allow connections to SSL sites without certs in HttpClient API or in RestClient API ? –  Jan 07 '16 at 10:35
3

Tested on 4.5.4:

            SSLContext sslContext = new SSLContextBuilder()
                    .loadTrustMaterial(null, (TrustStrategy) (arg0, arg1) -> true).build();

            CloseableHttpClient httpClient = HttpClients
                    .custom()
                    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    .setSSLContext(sslContext)
                    .build();
Jacky
  • 8,619
  • 7
  • 36
  • 40
3

Below code works with 4.5.5

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

class HttpsSSLClient {


    public static CloseableHttpClient createSSLInsecureClient() {
        SSLContext sslcontext = createSSLContext();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new HostnameVerifier() {

            @Override
            public boolean verify(String paramString, SSLSession paramSSLSession) {
                return true;
            }
        });
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        return httpclient;
    }


    private static SSLContext createSSLContext() {
        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContext.getInstance("TLS");
            sslcontext.init(null, new TrustManager[] {new TrustAnyTrustManager()}, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return sslcontext;
    }


    private static class TrustAnyTrustManager implements X509TrustManager {

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[] {};
        }
    }

}
public class TestMe {


    public static void main(String[] args) throws IOException {
        CloseableHttpClient client = HttpsSSLClient.createSSLInsecureClient();

        CloseableHttpResponse res = client.execute(new HttpGet("https://wrong.host.badssl.com/"));
        System.out.println(EntityUtils.toString(res.getEntity()));
    }
}

Output from code is

Code

Output on browser is

Bad SSL

The pom used is below

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tarun</groupId>
    <artifactId>testing</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
    <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.5</version>
    </dependency>

</dependencies>
</project>
Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
2

a full working version for Apache HttpClient 4.1.3 (based on oleg's code above, but it still needed an allow_all_hostname_verifier on my system):

private static HttpClient trustEveryoneSslHttpClient() {
    try {
        SchemeRegistry registry = new SchemeRegistry();

        SSLSocketFactory socketFactory = new SSLSocketFactory(new TrustStrategy() {

            public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
                // Oh, I am easy...
                return true;
            }

        }, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        registry.register(new Scheme("https", 443, socketFactory));
        ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(registry);
        DefaultHttpClient client = new DefaultHttpClient(mgr, new DefaultHttpClient().getParams());
        return client;
    } catch (GeneralSecurityException e) {
        throw new RuntimeException(e);
    }
}

Note I'm re-throwing all exceptions because really, there's not much I can do if any of this fails in a real system!

Korny
  • 1,988
  • 1
  • 18
  • 16
2

If you are using the fluent API, you need to set it up via the Executor:

Executor.unregisterScheme("https");
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslContext,
                                  SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Executor.registerScheme(new Scheme("https", 443, sslSocketFactory));

... where sslContext is the SSLContext created as shown in the ZZ Coder's answer.

After that, you can do your http requests as:

String responseAsString = Request.Get("https://192.168.1.0/whatever.json")
                         .execute().getContent().asString();

Note: tested with HttpClient 4.2

Elias Dorneles
  • 22,556
  • 11
  • 85
  • 107
2

Tested with 4.3.3

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class AccessProtectedResource {

public static void main(String[] args) throws Exception {

    // Trust all certs
    SSLContext sslcontext = buildSSLContext();

    // Allow TLSv1 protocol only
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslcontext,
            new String[] { "TLSv1" },
            null,
            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    CloseableHttpClient httpclient = HttpClients.custom()
            .setSSLSocketFactory(sslsf)
            .build();
    try {

        HttpGet httpget = new HttpGet("https://yoururl");

        System.out.println("executing request" + httpget.getRequestLine());

        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
            }
            for (Header header : response.getAllHeaders()) {
                System.out.println(header);
            }
            EntityUtils.consume(entity);
        } finally {
            response.close();
        }
    } finally {
        httpclient.close();
    }
}

private static SSLContext buildSSLContext()
        throws NoSuchAlgorithmException, KeyManagementException,
        KeyStoreException {
    SSLContext sslcontext = SSLContexts.custom()
            .setSecureRandom(new SecureRandom())
            .loadTrustMaterial(null, new TrustStrategy() {

                public boolean isTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                    return true;
                }
            })
            .build();
    return sslcontext;
}

}

craftsmannadeem
  • 2,665
  • 26
  • 22
0

If you encountered this problem when using AmazonS3Client, which embeds Apache HttpClient 4.1, you simply need to define a system property like this so that the SSL cert checker is relaxed:

-Dcom.amazonaws.sdk.disableCertChecking=true

Mischief managed

Mike Slinn
  • 7,705
  • 5
  • 51
  • 85
0

fwiw, an example using "RestEasy" implementation of JAX-RS 2.x to build a special "trust all" client...

    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.security.GeneralSecurityException;
    import java.security.KeyManagementException;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.util.ArrayList;
    import java.util.Arrays;
    import javax.ejb.Stateless;
    import javax.net.ssl.SSLContext;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import javax.ws.rs.client.Entity;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    import org.apache.http.config.Registry;
    import org.apache.http.config.RegistryBuilder;
    import org.apache.http.conn.HttpClientConnectionManager;
    import org.apache.http.conn.ssl.TrustStrategy;
    import org.jboss.resteasy.client.jaxrs.ResteasyClient;
    import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
    import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
    import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
    import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
    import org.apache.http.conn.socket.ConnectionSocketFactory;
    import org.apache.http.conn.ssl.NoopHostnameVerifier;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.ssl.SSLContexts;

    @Stateless
    @Path("/postservice")
    public class PostService {

        private static final Logger LOG = LogManager.getLogger("PostService");

        public PostService() {
        }

        @GET
        @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
        public PostRespDTO get() throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException, GeneralSecurityException {

            //...object passed to the POST method...
            PostDTO requestObject = new PostDTO();
            requestObject.setEntryAList(new ArrayList<>(Arrays.asList("ITEM0000A", "ITEM0000B", "ITEM0000C")));
            requestObject.setEntryBList(new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC")));

            //...build special "trust all" client to call POST method...
            ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(createTrustAllClient());

            ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
            ResteasyWebTarget target = client.target("https://localhost:7002/postRespWS").path("postrespservice");
            Response response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(requestObject, MediaType.APPLICATION_JSON));

            //...object returned from the POST method...
            PostRespDTO responseObject = response.readEntity(PostRespDTO.class);

            response.close();

            return responseObject;
        }


        //...get special "trust all" client...
        private static CloseableHttpClient createTrustAllClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {

            SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, TRUSTALLCERTS).useProtocol("TLS").build();
            HttpClientBuilder builder = HttpClientBuilder.create();
            NoopHostnameVerifier noop = new NoopHostnameVerifier();
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, noop);
            builder.setSSLSocketFactory(sslConnectionSocketFactory);
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionSocketFactory).build();
            HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager(registry);
            builder.setConnectionManager(ccm);

            return builder.build();
        }


        private static final TrustStrategy TRUSTALLCERTS = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
                return true;
            }
        };
    }

related Maven dependencies

    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-client</artifactId>
        <version>3.0.10.Final</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>jaxrs-api</artifactId>
        <version>3.0.10.Final</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson2-provider</artifactId>
        <version>3.0.10.Final</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5</version>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency> 
sairn
  • 461
  • 3
  • 24
  • 58
0

Careful with the use of SSLConnectionSocketFactory. This was noted with Apache HttpClient v4.5.x

Caused by: javax.net.ssl.SSLPeerUnverifiedException: Certificate for <somedomain.org> doesn't match any of the subject alternative names: [cert-used-in-2-way-tls.org, www.cert-used-in-2-way-tls.org]

The following code still yielded above exception:

        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        inputStream = new FileInputStream(certificatePath);

        keyStore.load(inputStream, certificatePassword.toCharArray());

        SSLContext sslContext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, certificatePassword.toCharArray())
                .build();

        SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext); //don't do this

        client = HttpClients.custom()
                    .setSSLSocketFactory(socketFactory) //don't do this
                    //.setSSLContext(sslContext) //do this instead
                    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    .build();

The following worked for me instead:

             //same code as above, but not using the SSLConnectionSocketFactory 
             client = HttpClients.custom()
                    .setSSLContext(sslContext) //do this instead
                    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    .build(); 
Tim Schumacher
  • 321
  • 3
  • 19
-1

If you are using Apache httpClient 4.5.x then try this:

public static void main(String... args)  {

    try (CloseableHttpClient httpclient = createAcceptSelfSignedCertificateClient()) {
        HttpGet httpget = new HttpGet("https://example.com");
        System.out.println("Executing request " + httpget.getRequestLine());

        httpclient.execute(httpget);
        System.out.println("----------------------------------------");
    } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) {
        throw new RuntimeException(e);
    }
}

private static CloseableHttpClient createAcceptSelfSignedCertificateClient()
        throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {

    // use the TrustSelfSignedStrategy to allow Self Signed Certificates
    SSLContext sslContext = SSLContextBuilder
            .create()
            .loadTrustMaterial(new TrustSelfSignedStrategy())
            .build();

    // we can optionally disable hostname verification. 
    // if you don't want to further weaken the security, you don't have to include this.
    HostnameVerifier allowAllHosts = new NoopHostnameVerifier();

    // create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
    // and allow all hosts verifier.
    SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);

    // finally create the HttpClient using HttpClient factory methods and assign the ssl socket factory
    return HttpClients
            .custom()
            .setSSLSocketFactory(connectionFactory)
            .build();
}
Brijesh Patel
  • 417
  • 5
  • 11
-1

For java.net.http.HttpClient


Imports

import java.net.http.HttpClient;
import org.apache.http.ssl.SSLContexts;
import javax.net.ssl.SSLContext;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

Usage

    try {
        sslContext = SSLContexts.custom()
                .loadTrustMaterial(null, (chain, authType) -> true)
                .build();
    } catch (KeyManagementException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (KeyStoreException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
        
    HttpClient httpClient = HttpClient.newBuilder().sslContext(sslContext).build();

Tested on Elasticsearch 8.1.3 as a Maven plugin

WISERDIVISOR
  • 154
  • 2
  • 12