in our project we switched from apache httpclient 4 to httpclient 5 now we have a ssl problem in one module. The code in httpclient 4 was
private void buildHttpClient() throws MalformedURLException {
try {
URL aURL = new URL(BASE_URL);
String host = aURL.getAuthority();
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
HostnameVerifier defaultHostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
SSLConnectionSocketFactory systemSocketFactory = new SSLConnectionSocketFactory(socketFactory, defaultHostnameVerifier);
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(
new AuthScope(new HttpHost(host)),
new UsernamePasswordCredentials(USER, PASSWORD));
httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(provider)
.setSSLSocketFactory(systemSocketFactory)
.build();
} catch (MalformedURLException e) {
throw new MalformedURLException(BASE_URL);
}
}
the new code is
private void buildClient() throws MalformedURLException {
URL aURL = new URL(BASE_URL);
String host = aURL.getAuthority();
final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(host, 443),
new UsernamePasswordCredentials(USER, PASSWORD.toCharArray()));
SSLContext ctx = SSLContexts.createDefault();
final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create()
.setSslContext(ctx)
.build();
final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(sslSocketFactory)
.build();
httpclient = HttpClients.custom()
.setConnectionManager(cm)
.setDefaultCredentialsProvider(credsProvider)
.build();
}
httpclient is CloseableHttpClient in both cases. Testin locally never got a problem but testing on the customer server shows now PKIX path building failed: com.ibm.security.cert.IBMCertPathBuilderException: unable to find valid certification path to requested target
When i roll back to an old deployment it works on the server but the new one doesn't work. The keystore deployed by the customer should be correct and I don't want to use an own keystore.
Can somebody describe where I should look, or what is the problem with the ssl?
You are getting a certification error. You can add following static block in order to close SSL verification.
static {
// this part is needed cause Lebocoin has invalid SSL certificate, that
// cannot be normally processed by Java
TrustManager[] trustAllCertificates = new TrustManager[] { new X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
return null; // Not relevant.
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
} };
HostnameVerifier trustAllHostnames = (String hostname, SSLSession session) -> true // Just
// allow
// them
// all.
;
try {
System.setProperty("jsse.enableSNIExtension", "false");
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCertificates, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames);
} catch (GeneralSecurityException e) {
throw new ExceptionInInitializerError(e);
}
}
How to ignore SSL certificate (trust all) for Apache HttpClient 4.3?
All the answers that I have found on SO treat previous versions, and the API changed.
Related:
How to ignore SSL certificate errors in Apache HttpClient 4.0
How to handle invalid SSL certificates with Apache HttpClient?
Need to trust all the certificates during the development using Spring
Ignore SSL Certificate Errors with Java
Edit:
It is only for test purposes. Kids, don't try it at home (or in production)
The code below works for trusting self-signed certificates. You have to use the TrustSelfSignedStrategy when creating your client:
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpGet httpGet = new HttpGet("https://some-server");
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} finally {
response.close();
}
I did not include the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER on purpose: The point was to allow testing with self signed certificates so you don't have to acquire a proper certificate from a certification authority. You can easily create a self-signed certificate with the correct host name, so do that instead of adding the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER flag.
If you are using PoolingHttpClientConnectionManager procedure above doesn't work, custom SSLContext is ignored. You have to pass socketFactoryRegistry in contructor when creating PoolingHttpClientConnectionManager.
SSLContextBuilder builder = SSLContexts.custom();
builder.loadTrustMaterial(null, new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
SSLContext sslContext = builder.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext, new X509HostnameVerifier() {
#Override
public void verify(String host, SSLSocket ssl)
throws IOException {
}
#Override
public void verify(String host, X509Certificate cert)
throws SSLException {
}
#Override
public void verify(String host, String[] cns,
String[] subjectAlts) throws SSLException {
}
#Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory> create().register("https", sslsf)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
socketFactoryRegistry);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm).build();
As an addition to the answer of #mavroprovato, if you want to trust all certificates instead of just self-signed, you'd do (in the style of your code)
builder.loadTrustMaterial(null, new TrustStrategy(){
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
or (direct copy-paste from my own code):
import javax.net.ssl.SSLContext;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.ssl.SSLContexts;
// ...
SSLContext sslContext = SSLContexts
.custom()
//FIXME to contain real trust store
.loadTrustMaterial(new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
return true;
}
})
.build();
And if you want to skip hostname verification as well, you need to set
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE).build();
as well. (ALLOW_ALL_HOSTNAME_VERIFIER is deprecated).
Obligatory warning: you shouldn't really do this, accepting all certificates is a bad thing. However there are some rare use cases where you want to do this.
As a note to code previously given, you'll want to close response even if httpclient.execute() throws an exception
CloseableHttpResponse response = null;
try {
response = httpclient.execute(httpGet);
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
}
finally {
if (response != null) {
response.close();
}
}
Code above was tested using
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
And for the interested, here's my full test set:
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.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class TrustAllCertificatesTest {
final String expiredCertSite = "https://expired.badssl.com/";
final String selfSignedCertSite = "https://self-signed.badssl.com/";
final String wrongHostCertSite = "https://wrong.host.badssl.com/";
static final TrustStrategy trustSelfSignedStrategy = new TrustSelfSignedStrategy();
static final TrustStrategy trustAllStrategy = new TrustStrategy(){
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
};
#Test
public void testSelfSignedOnSelfSignedUsingCode() throws Exception {
doGet(selfSignedCertSite, trustSelfSignedStrategy);
}
#Test(expected = SSLHandshakeException.class)
public void testExpiredOnSelfSignedUsingCode() throws Exception {
doGet(expiredCertSite, trustSelfSignedStrategy);
}
#Test(expected = SSLPeerUnverifiedException.class)
public void testWrongHostOnSelfSignedUsingCode() throws Exception {
doGet(wrongHostCertSite, trustSelfSignedStrategy);
}
#Test
public void testSelfSignedOnTrustAllUsingCode() throws Exception {
doGet(selfSignedCertSite, trustAllStrategy);
}
#Test
public void testExpiredOnTrustAllUsingCode() throws Exception {
doGet(expiredCertSite, trustAllStrategy);
}
#Test(expected = SSLPeerUnverifiedException.class)
public void testWrongHostOnTrustAllUsingCode() throws Exception {
doGet(wrongHostCertSite, trustAllStrategy);
}
#Test
public void testSelfSignedOnAllowAllUsingCode() throws Exception {
doGet(selfSignedCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
}
#Test
public void testExpiredOnAllowAllUsingCode() throws Exception {
doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
}
#Test
public void testWrongHostOnAllowAllUsingCode() throws Exception {
doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
}
public void doGet(String url, TrustStrategy trustStrategy, HostnameVerifier hostnameVerifier) throws Exception {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(trustStrategy);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).setSSLHostnameVerifier(hostnameVerifier).build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} finally {
response.close();
}
}
public void doGet(String url, TrustStrategy trustStrategy) throws Exception {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(trustStrategy);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} finally {
response.close();
}
}
}
(working test project in github)
One small addition to the answer by vasekt:
The provided solution with the SocketFactoryRegistry works when using PoolingHttpClientConnectionManager.
However, connections via plain http don't work any longer then. You have to add a PlainConnectionSocketFactory for the http protocol additionally to make them work again:
Registry<ConnectionSocketFactory> socketFactoryRegistry =
RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", sslsf)
.register("http", new PlainConnectionSocketFactory()).build();
After trying various options, following configuration worked for both http and https:
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build(), SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.
<ConnectionSocketFactory> create()
.register("http", new PlainConnectionSocketFactory())
.register("https", sslsf)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(2000);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.setConnectionManager(cm)
.build();
I am using http-client 4.3.3 : compile 'org.apache.httpcomponents:httpclient:4.3.3'
Simpler and shorter working code:
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 which you use to make post request...
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 calling and using HttpPost instance in the normal form
Here's a working distillation of the above techniques, equivalent to "curl --insecure":
HttpClient getInsecureHttpClient() throws GeneralSecurityException {
TrustStrategy trustStrategy = new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType) {
return true;
}
};
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
return HttpClients.custom()
.setSSLSocketFactory(new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(trustStrategy).build(),
hostnameVerifier))
.build();
}
When using http client 4.5 I had to use the javasx.net.ssl.HostnameVerifier to allow any hostname (for testing purposes). Here is what I ended up doing:
CloseableHttpClient httpClient = null;
try {
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
HostnameVerifier hostnameVerifierAllowAll = new HostnameVerifier()
{
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build(), hostnameVerifierAllowAll);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("192.168.30.34", 8443),
new UsernamePasswordCredentials("root", "password"));
httpClient = HttpClients.custom()
.setSSLSocketFactory(sslSocketFactory)
.setDefaultCredentialsProvider(credsProvider)
.build();
HttpGet httpGet = new HttpGet("https://192.168.30.34:8443/axis/services/getStuff?firstResult=0&maxResults=1000");
CloseableHttpResponse response = httpClient.execute(httpGet);
int httpStatus = response.getStatusLine().getStatusCode();
if (httpStatus >= 200 && httpStatus < 300) { [...]
} else {
throw new ClientProtocolException("Unexpected response status: " + httpStatus);
}
} catch (Exception ex) {
ex.printStackTrace();
}
finally {
try {
httpClient.close();
} catch (IOException ex) {
logger.error("Error while closing the HTTP client: ", ex);
}
}
class ApacheHttpClient {
/***
* This is a https get request that bypasses certificate checking and hostname verifier.
* It uses basis authentication method.
* It is tested with Apache httpclient-4.4.
* It dumps the contents of a https page on the console output.
* It is very similar to http get request, but with the additional customization of
* - credential provider, and
* - SSLConnectionSocketFactory to bypass certification checking and hostname verifier.
* #param path String
* #param username String
* #param password String
* #throws IOException
*/
public void get(String path, String username, String password) throws IOException {
final CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultCredentialsProvider(createCredsProvider(username, password))
.setSSLSocketFactory(createGenerousSSLSocketFactory())
.build();
final CloseableHttpResponse response = httpClient.execute(new HttpGet(path));
try {
HttpEntity entity = response.getEntity();
if (entity == null)
return;
System.out.println(EntityUtils.toString(entity));
} finally {
response.close();
httpClient.close();
}
}
private CredentialsProvider createCredsProvider(String username, String password) {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
return credsProvider;
}
/***
*
* #return SSLConnectionSocketFactory that bypass certificate check and bypass HostnameVerifier
*/
private SSLConnectionSocketFactory createGenerousSSLSocketFactory() {
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{createGenerousTrustManager()}, new SecureRandom());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
return new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
}
private X509TrustManager createGenerousTrustManager() {
return new X509TrustManager() {
#Override
public void checkClientTrusted(X509Certificate[] cert, String s) throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] cert, String s) throws CertificateException {
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
}
}
If you are using HttpClient 4.5.x, your code can be similar to the following:
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null,
TrustSelfSignedStrategy.INSTANCE).build();
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
sslContext, NoopHostnameVerifier.INSTANCE);
HttpClient httpClient = HttpClients.custom()
.setDefaultCookieStore(new BasicCookieStore())
.setSSLSocketFactory(sslSocketFactory)
.build();
On top of PoolingHttpClientConnectionManager along with Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslFactory).build();
If you want an asynchronous httpclient using PoolingNHttpClientConnectionManager the code shoudl be similar to following
SSLContextBuilder builder = SSLContexts.custom();
builder.loadTrustMaterial(null, new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
SSLContext sslContext = builder.build();
SchemeIOSessionStrategy sslioSessionStrategy = new SSLIOSessionStrategy(sslContext,
new HostnameVerifier(){
#Override
public boolean verify(String hostname, SSLSession session) {
return true;// TODO as of now allow all hostnames
}
});
Registry<SchemeIOSessionStrategy> sslioSessionRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create().register("https", sslioSessionStrategy).build();
PoolingNHttpClientConnectionManager ncm = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(),sslioSessionRegistry);
CloseableHttpAsyncClient asyncHttpClient = HttpAsyncClients.custom().setConnectionManager(ncm).build();
asyncHttpClient.start();
(I would have added a comment directly to vasekt's answer but I don't have enough reputation points (not sure the logic there)
Anyway... what I wanted to say is that even if you aren't explicitly creating/asking for a PoolingConnection, doesn't mean you aren't getting one.
I was going crazy trying to figure out why the original solution didn't work for me, but I ignored vasekt's answer as it "didn't apply to my case" - wrong!
I was staring at my stack-trace when low and behold I saw a PoolingConnection in the middle of it. Bang - I tired his addition and success!! (our demo is tomorrow and I was getting desperate) :-)
Trust All Certs in Apache HTTP Client
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sc);
httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
You can use following code snippet for get the HttpClient instance without ssl certification checking.
private HttpClient getSSLHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
LogLoader.serverLog.trace("In getSSLHttpClient()");
SSLContext context = SSLContext.getInstance("SSL");
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
context.init(null, new TrustManager[] { tm }, null);
HttpClientBuilder builder = HttpClientBuilder.create();
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(context);
builder.setSSLSocketFactory(sslConnectionFactory);
PlainConnectionSocketFactory plainConnectionSocketFactory = new PlainConnectionSocketFactory();
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslConnectionFactory).register("http", plainConnectionSocketFactory).build();
PoolingHttpClientConnectionManager ccm = new PoolingHttpClientConnectionManager(registry);
ccm.setMaxTotal(BaseConstant.CONNECTION_POOL_SIZE);
ccm.setDefaultMaxPerRoute(BaseConstant.CONNECTION_POOL_SIZE);
builder.setConnectionManager((HttpClientConnectionManager) ccm);
builder.disableRedirectHandling();
LogLoader.serverLog.trace("Out getSSLHttpClient()");
return builder.build();
}
Slight tweak to answer from #divbyzero above to fix sonar security warnings
CloseableHttpClient getInsecureHttpClient() throws GeneralSecurityException {
TrustStrategy trustStrategy = (chain, authType) -> true;
HostnameVerifier hostnameVerifier = (hostname, session) -> hostname.equalsIgnoreCase(session.getPeerHost());
return HttpClients.custom()
.setSSLSocketFactory(new SSLConnectionSocketFactory(new SSLContextBuilder().loadTrustMaterial(trustStrategy).build(), hostnameVerifier))
.build();
}
Initially, i was able to disable for localhost using trust strategy, later i added NoopHostnameVerifier. Now it will work for both localhost and any machine name
SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial(null, new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext, NoopHostnameVerifier.INSTANCE);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
In java 11 or later if you want to skip certificate validation just try the following its working.
For HttpClient am using java's default client with this import java.net.http.HttpClient;
static SSLContext insecureContext() {
TrustManager[] noopTrustManager = new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) {}
public void checkServerTrusted(X509Certificate[] xcs, String string) {}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
try {
SSLContext sc = SSLContext.getInstance("ssl");
sc.init(null, noopTrustManager, null);
return sc;
} catch (KeyManagementException | NoSuchAlgorithmException ex) {
return null;
}
}
and then make you HttpClient like this
HttpClient client = HttpClient.newBuilder()
.sslContext(insecureContext())
.build();
I wrote a JAVA crawler and try to use proxy and ignore any https certification.
But it does not work with
java.lang.UnsupportedOperationException
(at org.apache.http.impl.client.InternalHttpClient.getParams)
I searched solutions that mostly say my HttpClient's version is old, but I update to the latest version from apache website, this exception still happened.
Followed code is my crawler code:
public static void main(String[] args) {
try{
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, trustAllCerts, null);
LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(ctx);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslSocketFactory).build();
HttpHost proxy = new HttpHost("127.0.0.1", 8888,"http");
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,proxy);
HttpGet request = new HttpGet("https://www.javaworld.com.tw/jute/post/view?bid=29&id=312144");
CloseableHttpResponse response = client.execute(request);
String entity = EntityUtils.toString(response.getEntity(), "utf-8");
System.out.println(entity);
}catch (Exception e) {
e.printStackTrace();
}
}
Thanks a lot for any solutions.
I had the same issue and it was because the method is deprecated and not available in latest versions.
I tried the below code and it worked for me
public static HttpClient createClient() {
try {
SSLContextBuilder builder = new SSLContextBuilder();
builder.useProtocol("TLSv1.2");
builder.loadTrustMaterial(null, new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
});
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
HttpClientBuilder hcBuilder = HttpClients.custom();
HttpHost httpProxy = new HttpHost(bundle.getString("PROXY_HOST"), Integer.parseInt(bundle.getString("PROXY_PORT")));
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(httpProxy);
hcBuilder.setRoutePlanner(routePlanner);
CloseableHttpClient httpclient = hcBuilder
.setSSLSocketFactory(sslsf).build();
return httpclient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
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've made an Android application that uses a X509 certificate (that is in the folder res/raw/mykeystore.bks) to sign to remote server that respond on the 9006 port.
the server ask me for a login (username, password).
when i make an HTTPGet i've the following exeption:
org.apache.http.client.ClientProtocolException
Here is my implementation:
The main Activity:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b= (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
CredentialsProvider credProvider = new BasicCredentialsProvider();
credProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials("rat#1", "rat"));
HttpClient client = new MyHttpClient(getApplicationContext());
((AbstractHttpClient) client).setCredentialsProvider(credProvider);
//final String url = "https://211.92.106.38:9006/KPIRest/testKpi/6";
final String url = "https://211.92.106.38/KPIRest/testKpi/6";
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse response = client.execute(httpGet);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Custom Client Class:
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager() {
KeyStore trustStore = null;
trustStore = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trustStore.load(in, "root01".toCharArray());
}
} finally {
in.close();
}
SSLSocketFactory sf=null;
sf = new MySSLSocketFactory(trustStore);
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("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 9006));
return new SingleClientConnManager(params, registry);
}
}
My Customc SSLSoketFactory class:
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
#Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
#Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
what's wrong in my application? What causes that Exception?
Thank you all!
EDIT:
I was looking better the exception:
cause=
org.apache.http.auth.MalformedChallengeException: Authentication challenge is empty.
EDIT 2:
I've tryed to use this implementation with no difference, I've the same exception!
EDIT 3: I've replaced
CredentialsProvider credProvider = new BasicCredentialsProvider();
credProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials("rat#1", "rat"));
client).setCredentialsProvider(credProvider);
with the base httpclient autentication, adding the header Authorization to the httpGet:
httpGet.addHeader("Authorization", "Basic "+Base64.encodeToString("rat#1:rat".getBytes(),Base64.DEFAULT));
now the server send me this message:
HTTP/1.1 400 Bad Request
the problem was the Authorization header.
We have to use:
httpGet.addHeader("Authorization", "Basic "+Base64.encodeToString("rat#1:rat".getBytes(),Base64.NO_WRAP));
Instead of:
httpGet.addHeader("Authorization", "Basic "+Base64.encodeToString("rat#1:rat".getBytes(),Base64.DEFAULT));
because the DEFAULT parameter add "CR" line terminator at the end of string and it's uncorrect if you'll use it that header.