I am using Unirest (java version) to make GET and POST request.But I encounter a problem when accessing SSL encrypted site , since my program is behind a corporate network and the network admin setup a firewall mapping for me. For example foobar.com
is mapped to 56.1.89.12:4444
. But when I make request to the address, I will received the following ssl certificate error:
com.mashape.unirest.http.exceptions.UnirestException: javax.net.ssl.SSLException: hostname in certificate didn't match: <56.1.89.12> != <www.foobar.com>
at com.mashape.unirest.http.HttpClientHelper.request(HttpClientHelper.java:131)
at com.mashape.unirest.request.BaseRequest.asString(BaseRequest.java:52)
I see Unirest
has advance configuration to use custom httpclient
.So I use
Unirest.setHttpClient(MyHttpClient.makeClient());
HttpResponse<String> res = null;
try {
res = Unirest.get(urlstr).asString();
} catch (UnirestException e) {
e.printStackTrace();
}
String jsonstr = res.getBody();
the makeClient
method of MyHttpClient
is:
public static HttpClient makeClient(){
SSLContextBuilder builder = new SSLContextBuilder();
CloseableHttpClient httpclient = null;
try {
// builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
builder.loadTrustMaterial(null, new TrustStrategy(){
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
System.out.println("custom httpclient called");
System.out.println(httpclient);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return httpclient;
}
the main idea is taken from Ignoring SSL certificate in Apache HttpClient 4.3
But still this didn't work.Any suggestions?
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(null, new TrustSelfSignedStrategy())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
Unirest.setHttpClient(httpclient);
this worked for me
This is how I finally solved my problem:
public static HttpClient makeClient(){
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
try {
schemeRegistry.register(new Scheme("https", 443, new MockSSLSocketFactory()));
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
DefaultHttpClient httpclient = new DefaultHttpClient(cm);
return httpclient;
}
I had been scratching for a whole day, I hope this could help someone.
the certificate error solution is a combination from a few places
- https://github.com/Mashape/unirest-java/issues/70, where i started.
- http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/ very good explanation.
- http://www.baeldung.com/httpclient-ssl, solution for all versions.
and a relatively complete example.
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
public class XXX {
private static HttpClient unsafeHttpClient;
static {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
unsafeHttpClient = HttpClients.custom().setSSLContext(sslContext)
.setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
e.printStackTrace();
}
}
public static HttpClient getClient() {
return unsafeHttpClient;
}
public static void main(String[] args) {
try {
HttpClient creepyClient = RestUnirestClient.getClient();
Unirest.setHttpClient(creepyClient);
HttpResponse<JsonNode> response = Unirest.get("https://httpbin.org/get?show_env=1").asJson();
System.out.println(response.getBody().toString());
} catch (UnirestException e) {
e.printStackTrace();
}
}
}
Unfortunately, Unirest does not have a native way to configure SSL, so providing a custom HttpClient instance looks like the only option. Here is a solution, which does not use deprecated classes (like 'DefaultHttpClient') and works with self-signed certificates:
protected void prepareHttpsClient() {
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
try {
String certificateStorage = <<yourCertStorageFileName>>;
String certificatePassword = <<yourCertStoragePassword>>;
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(
new File(certificateStorage), certificatePassword.toCharArray(),
new TrustSelfSignedStrategy()).build();
SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1"}, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
clientBuilder.setSSLSocketFactory(sslFactory);
}
catch (Exception e) {
throw new IllegalArgumentException("Error configuring server certificates.", e);
}
HttpClient httpClient = clientBuilder.build();
Unirest.setHttpClient(httpClient);
}
I'm using "com.konghq:unirest-java:2.3.14“
There is a config now
Unirest.config().verifySsl(false);
来源:https://stackoverflow.com/questions/23242197/how-to-make-unirestjava-ignore-certificate-error