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 am using Okhttp3 in my android application to download files. I am having problem with https urls.
I have two URLS
String url1 = "https://cbsenet.nic.in/cbsenet/PDFDEC2014/Paper%20III/D-01-3.pdf";
String url2 = "https://www.ugcnetonline.in/question_papers/June2014_paper-II/J-02-14-II.pdf";
url2 is working fine while for url1 I am getting exception
Exception in thread "main" 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
I have created a sample java program to demonstrate the problem
public static void main(String[] args) throws IOException {
String url1 = "https://cbsenet.nic.in/cbsenet/PDFDEC2014/Paper%20III/D-01-3.pdf";
String url2 = "https://www.ugcnetonline.in/question_papers/June2014_paper-II/J-02-14-II.pdf";
Request request = new Request.Builder()
.url(url1)
.build();
OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
}
This is my solution, It works
private static OkHttpClient generateDefaultOkHttp() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
#SuppressLint("TrustAllX509TrustManager")
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#SuppressLint("TrustAllX509TrustManager")
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
#SuppressLint("BadHostnameVerifier")
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (Exception e) {
e.printStackTrace();
}
builder.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.retryOnConnectionFailure(true);
return builder.build();
}
Since at last, you choose to trust all cers for your url1, then how could you make your url2 worked before?
BR,
Xiangbin
HttpClient =new DefaultHttpClient();
HttpPost post = new HttpPost("https://myulr/token");
post.addHeader("Content-Type", "application/x-www-form-urlencoded");
List<BasicNameValuePair> parametersBody = new ArrayList<BasicNameValuePair>();
parametersBody.add(new BasicNameValuePair("client_id","my-client-id"));
parametersBody.add(new BasicNameValuePair("client_secret","my-secret-key"));
parametersBody.add(new BasicNameValuePair("scope","my-scope"));
parametersBody.add(new BasicNameValuePair("grant_type","client_credentials"));
try{
post.setEntity(new UrlEncodedFormEntity(parametersBody));
HttpResponse httpResponse = httpClient.execute(post);
int code = httpResponse.getStatusLine().getStatusCode();
System.out.println("Code::::: "+code);
String result=EntityUtils.toString(httpResponse.getEntity());
System.out.println("Result: "+result);
}catch(Exception e){
e.printStackTrace();
}
This code is properly executing in JDK8 but if I try to execute it in JDK7, it is throwing javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated exception. I tried to google the issue. I found that we can write X509TrustManager and X509HostnameVerifier. I tried with these implementations also, but still didn't work. Please suggest me how can I execute it in JDK7.
Again if I execute the code with X509TrustManager and X509HostnameVerifier, I am getting "java.net.SocketException: Connection reset"
I just recently researched this and i want to add this - Support for TLS 1.2 first appeared in JDK 7. For compatibility reasons, it is enabled by default on server sockets but disabled on clients.
To change it, I wrote following code and it worked for me:
HttpClient base = new DefaultHttpClient();
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
X509HostnameVerifier verifier = new X509HostnameVerifier() {
#Override
public void verify(String string, X509Certificate xc) throws SSLException {
}
#Override
public void verify(String string, String[] strings, String[] strings1) throws SSLException {
}
#Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
#Override
public void verify(String arg0, SSLSocket arg1) throws IOException {
}
};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new
SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ssf.setHostnameVerifier(verifier);
ClientConnectionManager ccm = base.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", ssf, 443));
httpClient = new DefaultHttpClient(ccm, base.getParams());
I can't fetch resources from SNI sites with HttpClient. URLs I am trying to fetch are: https://dabar.srce.hr/, https://www.lutrija.hr/cms/splash.
I get this error:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
As I understand the documentation it should work like this out of the box (and it works for non sni https sites):
url = "https://dabar.srce.hr/";
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
// trust all certificates
public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslSF).build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpclient.execute(httpGet);
System.out.println(response.getStatusLine().toString());
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity));
I tried to explicitly enable SNIExtension:
System.setProperty("jsse.enableSNIExtension", "true");
I tried overriding SSLConnectionSocketFactory:
SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE) {
String targetHost = "";
#Override
public Socket createLayeredSocket(Socket socket, String target, int port, HttpContext context)
throws IOException {
this.targetHost = target;
return super.createLayeredSocket(socket, target, port, context);
}
#Override
protected void prepareSocket(SSLSocket socket) throws IOException {
try {
PropertyUtils.setProperty(socket, "host", this.targetHost);
} catch (Exception ex) {
}
super.prepareSocket(socket);
}
#Override
public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpContext context)
throws IOException {
if (socket instanceof SSLSocket) {
try {
PropertyUtils.setProperty(socket, "host", host.getHostName());
} catch (NoSuchMethodException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
return super.connectSocket(connectTimeout, socket, host, remoteAddress,
localAddress, context);
}
};
What am I missing?
I ran into the same issue. This custom SSLConnectionSocketFactory fixed it for me:
public class TrustAllSslSocketFactory extends SSLConnectionSocketFactory {
static final HostnameVerifier ALL_HOSTNAME_VERIFIER = (String hostname, SSLSession session) -> true;
public TrustAllSslSocketFactory(SSLContext sslContext) {
super(sslContext, ALL_HOSTNAME_VERIFIER);
}
#Override
protected void prepareSocket(SSLSocket socket) throws IOException {
String hostName = socket.getInetAddress().getHostName();
SNIHostName sniHostName = new SNIHostName(hostName);
List serverNames = new ArrayList(1);
serverNames.add(sniHostName);
SSLParameters sslParameters = socket.getSSLParameters();
sslParameters.setServerNames(serverNames);
socket.setSSLParameters(sslParameters);
}
}
See http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SNIExamples
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.