I am trying to send a request to following address. The certificate is not valid and I would like to ignore it. I wrote following code based on my research on 1, 2 but I am not able to complete it. I am using Java 1.7,
https://api.stubhubsandbox.com/search/catalog/events/v3
Code
private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = 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 ){}
public void checkClientTrusted(
java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
}
};
public static void main(String[] args) {
TrustStrategy acceptingTrustStrategy =
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
String url = "https://api.stubhubsandbox.com/search/catalog/events/v3";
RestTemplate rest = new RestTemplate();
Map<String, String> mvm = new HashMap<String, String>();
mvm.put("Authorization", "Bearer TOKEEEEEEEN");
Object object = rest.postForObject(url, null, Object.class, mvm);
System.err.println("done");
}
As you may have noticed, Spring's RestTemplate delegates all the HTTP(S) related stuff to the underlying implementation of ClientHttpRequestFactory. Since you're using the HttpClient-based implementation, here are a couple of useful SO links on how to achieve this for the internal HttpClient:
Ignoring SSL certificate in Apache HttpClient 4.3
How to ignore SSL certificate errors in Apache HttpClient 4.0
Apparently, since version 4.4, this can be done as:
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
To bypass SSL checks in several spring projects I always re-use a SSLUtils class I wrote (or found) some time ago in conjunction with spring's RestTemplate. Using the class provided below you just need to call the static SSLUtil.turnOffSslChecking() method before you send your request.
import javax.net.ssl.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public final class SSLUtil{
static {
//for localhost testing only
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
if (hostname.equals("localhost")) {
return true;
}
return false;
}
});
}
private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = 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 ){}
}
};
public static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
// Install the all-trusting trust manager
final SSLContext sc = SSLContext.getInstance("SSL");
sc.init( null, UNQUESTIONING_TRUST_MANAGER, null );
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
// Return it to the initial state (discovered by reflection, now hardcoded)
SSLContext.getInstance("SSL").init( null, null, null );
}
private SSLUtil(){
throw new UnsupportedOperationException( "Do not instantiate libraries.");
}
}
Give it a try. Hope this works and turns out as an easy solution for you.
Add the SSLContext and X509TrustManager and the HostnameVerifier instances to the http ClientBuilders.
They can be for instance (given my example)
HttpClientBuilder with HttpComponentsClientHttpRequestFactory
OkHttpClient.Builder with OkHttp3ClientHttpRequestFactory
Here's the sample code for Apache HttpClient & OkHttpClient. Its for demo purpose but you can use it
Apache HttpClient
RestTemplate restTemplate = new RestTemplate(SSLClientFactory.getClientHttpRequestFactory(HttpClientType.HttpClient));
and OkHttpClient
RestTemplate restTemplate = new RestTemplate(SSLClientFactory.getClientHttpRequestFactory(HttpClientType.OkHttpClient));
The SSLClientFactory is custom class here
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
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.impl.client.HttpClientBuilder;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import okhttp3.OkHttpClient;
public abstract class SSLClientFactory {
private static boolean allowUntrusted = false;
private static final long LOGIN_TIMEOUT_SEC = 10;
private static HttpClientBuilder closeableClientBuilder = null;
private static OkHttpClient.Builder okHttpClientBuilder = null;
public enum HttpClientType{
HttpClient,
OkHttpClient
}
public static synchronized ClientHttpRequestFactory getClientHttpRequestFactory(HttpClientType httpClientType){
ClientHttpRequestFactory requestFactory = null;
SSLContext sslContext = SSLClientFactory.getSSlContext();
if(null == sslContext){
return requestFactory;
}
switch (httpClientType) {
case HttpClient:
closeableClientBuilder = HttpClientBuilder.create();
//Add the SSLContext and trustmanager
closeableClientBuilder.setSSLContext(getSSlContext());
//add the hostname verifier
closeableClientBuilder.setSSLHostnameVerifier(gethostnameVerifier());
requestFactory = new HttpComponentsClientHttpRequestFactory(closeableClientBuilder.build());
break;
case OkHttpClient:
okHttpClientBuilder = new OkHttpClient().newBuilder().readTimeout(LOGIN_TIMEOUT_SEC, TimeUnit.SECONDS);
//Add the SSLContext and trustmanager
okHttpClientBuilder.sslSocketFactory(getSSlContext().getSocketFactory(), getTrustManager());
//add the hostname verifier
okHttpClientBuilder.hostnameVerifier( gethostnameVerifier());
requestFactory = new OkHttp3ClientHttpRequestFactory(okHttpClientBuilder.build());
break;
default:
break;
}
return requestFactory;
}
private static SSLContext getSSlContext(){
final TrustManager[] trustAllCerts = new TrustManager[]{getTrustManager()};
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
return sslContext;
}
private static X509TrustManager getTrustManager(){
final X509TrustManager trustManager = new X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] cArrr = new X509Certificate[0];
return cArrr;
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// TODO Auto-generated method stub
}
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// TODO Auto-generated method stub
}
};
return trustManager;
}
private static HostnameVerifier gethostnameVerifier(){
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
};
return hostnameVerifier;
}
}
Not sure if things have changed after jdk6, but last time I was trying to do this we needed to import the SSL certificate to the keystore of the JAVA_HOME used to run the programs utilizing the trusted ssl.
First, you will need to export the certificate to a file. In windows, you can use any browser to save the SSL certificate to your personal certificates store and then run mmc, add certificates snapin (File/Add Remove Snapin) and save the certificate to disk.
Then you need to import the certificate to trusted domain cacerts using the keytool. But you need to import it to the keystore that your java_home uses when running your programs above.
The command below will add certificate file "mycertificate.cer" to keystore in file "cacerts.jks". The alias is "webservice" :
"%JAVA_HOME%\bin\keytool" -import -trustcacerts -alias webservice -file mycertificate.cer -keystore cacerts.jks
Usually, the Keystore password is "changeit", no quotes. Change it for production use
If you are using Apache httpClient 4.5 following:
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();
}
#Bean
public RestTemplate getRestTemplate() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
This code bypasses the certificate validation and you can connect with an insecure way by accepting all hosts and certificates. This code works for me
You can use this code:
#Bean
public RestTemplate restTemplate()
throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
return restTemplate;
}
in java 7 replace lambda expression with:
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
#Override public boolean isTrusted(X509Certificate[] x509Certificates, String s)
throws CertificateException {
return true;
}
};
SSLUtils solution posted by #Sebastián Ezquerro is spot on. I tested this both with RestTemplate and FeignClient - works like a champ. Many thanks to all contributors. In case, you are wondering Feign client solution, here it is:
#Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
BasicAuthRequestInterceptor auth = new BasicAuthRequestInterceptor(username, password);
RequestTemplate template = new RequestTemplate();
template.header(HttpHeaders.ACCEPT, "application/json");
template.header(HttpHeaders.CONTENT_TYPE, "application/json");
auth.apply(template);
// disable SSL self signed certificate check
try {
SSLUtil.turnOffSslChecking();
} catch (NoSuchAlgorithmException e) {
log.error("Error disabling SSL check", e);
} catch (KeyManagementException e) {
log.error("Error disabling SSL check", e);
}
return auth;
}
I have a scenario in which I must pass a certficate to my server, then the server sends me his certificate, which I must accept to access the server. I was using HttpURLConnection for this, with no problems.
However, I recently had a problem with HttpURLConnection. The code I was using retrieved an image from a HTTPS server. If the image was small (< 500kb), no problem whatsoever occured. However, with larger images I got this:
javax.net.ssl.SSLProtocolException: Read error: ssl=0x3c97e8: Failure in SSL library, usually a protocol error
I was reading about it on the Internet, and many people said that using HttpClient instead of HttpURLConnection was the way to go (an example is this site http://soan.tistory.com/62 , think that is written in korean, I can't read it but that's what I think it says).
This is my old code, using URLConnection:
public static URLConnection CreateFromP12(String uri, String keyFilePath,
String keyPass, TrustManager[] trustPolicy, HostnameVerifier hv) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyStore keyStore = KeyStore.getInstance("PKCS12");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
keyStore.load(new FileInputStream(keyFilePath),
keyPass.toCharArray());
kmf.init(keyStore, keyPass.toCharArray());
sslContext.init(kmf.getKeyManagers(), trustPolicy, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext
.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
} catch (Exception ex) {
return null;
}
URL url;
URLConnection conn;
try {
url = new URL(uri);
conn = url.openConnection();
} catch (MalformedURLException e) {
return null;
} catch (IOException e) {
return null;
}
return conn;
}
And this is the new one, using HttpClient:
public class HttpC2Connection {
public static HttpEntity CreateHttpEntityFromP12(String uri,
String keyFilePath, String keyPass) throws Exception {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream(keyFilePath), keyPass.toCharArray());
SSLSocketFactory sf = new MySSLSocketFactory(keyStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params,
registry);
HttpClient httpclient = new DefaultHttpClient(ccm, params);
HttpGet httpget = new HttpGet(uri);
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
return entity;
}
But now, using HttpClient, my server returns me an error saying that I must pass a certificate, so I guess that
SSLSocketFactory sf = new MySSLSocketFactory(keyStore);
isn't loading my certificate.
So, how can I do the following two things at the same time:
1.) Pass a certificate to my server;
2.) Accept any certificate from my server
Using the HttpClient class?
PS: I'm using Android 3.0
Thanks
The following code disables SSL certificate checking for any new instances of HttpsUrlConnection:
https://gist.github.com/aembleton/889392
/**
* Disables the SSL certificate checking for new instances of {#link HttpsURLConnection} This has been created to
* aid testing on a local box, not for use on production.
*/
private static void disableSSLCertificateChecking() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
#Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
} };
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
Don't just accept any certificates. Don't use home-made SSLSocketFactory's that compromise security. Use the SSLSocketFactory from the SDK, and pass both a trust store (containing the server certificate or the CA certificate that issued it) and a keystore (containing your client certificate and private key). You can use this constructor to achieve this, the JavaDoc has details on how to create the key stores.
How do I bypass invalid SSL certificate errors with Apache HttpClient 4.0?
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();
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);
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;
}
}
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();
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;
}
});
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();
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!
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());
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
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) {
}
This is how I did it -
Create my own MockSSLSocketFactory (Class attached below)
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));
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 {
}
});
// ...
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();
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);
}
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();
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
Output on browser is
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>
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();
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!
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
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;
}
}
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
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>
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();
}