How to property call SSL(https) url in Java? - java

It is spring based web app, using below method to accept all SSL certificates. This method works and I get results back,but it does not seems great. Please suggest. The endpoint( url) SSL has a verisign certificate)
private void prepareHttpsConnnection() throws NoSuchAlgorithmException,
KeyManagementException {
System.setProperty("https.proxyHost", proxyHost);
System.setProperty("https.proxyPort", proxyPort);
System.setProperty("jsse.enableSNIExtension", enableSNIExte`enter code here`nsion);
SSLContext 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());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext
.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
}

Related

okHttpClient proxy connection gives unexpected end of stream exception

I am trying to make a proxy connection using okHttpClient. Target connection requires basic authentication that I am doing using Authenticator. Proxy requires a header to connect to the target URL. I am passing this header in the authenticator header.
Below is the code that I am trying but it gives unexpected end of stream exception.
#Configuration
public class FeignClientConfig {
#Value("localhost")
private String proxyHost;
#Value("8443")
private int proxyPort;
#Value("root")
private String user;
#Value("abcd")
private String password;
#Bean
public Client feignClientConfig() throws NoSuchAlgorithmException, KeyManagementException {
OkHttpClient okHttpClient;
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
TrustManager[] trustAllCerts = getTrustManagers();
// SSLContext sslContext = SSLContext.getInstance("SSL");
// sslContext.init(null, trustAllCerts, new SecureRandom());
// SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = (hostname, session) -> true;
okHttpClient = new OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.sslSocketFactory(Objects.requireNonNull(getSSLSocketFactory()), (X509ExtendedTrustManager) trustAllCerts[0])
.hostnameVerifier(allHostsValid)
.proxy(proxy)
.proxyAuthenticator(authenticator())
.build();
return new feign.okhttp.OkHttpClient(okHttpClient);
}
private okhttp3.Authenticator authenticator() {
return (route, response) -> {
String credential = okhttp3.Credentials.basic(user, password);
return response.request().newBuilder()
.header("Authorization", credential)
.header("Content-Type", "application/json")
//this header is required by proxy not the target connection
.header("X-Connect-Client-Id", "xyz")
.build();
};
}
private SSLSocketFactory getSSLSocketFactory() {
try {
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
};
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
return sslContext.getSocketFactory();
}
catch (Exception exception) {
log.error("Error while getting SSLSocketFactory: "+exception.getMessage());
}
return null;
}
private TrustManager[] getTrustManagers() {
return new TrustManager[]{
new X509ExtendedTrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
#Override
public void checkServerTrusted(X509Certificate[] xcs, String string, Socket socket) throws CertificateException {
}
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
}
#Override
public void checkClientTrusted(X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {
}
}
};
}
}

How do I use an SSL client certificate with jersey client in java

I am trying to connect server using https url But still could not understand how should I add SSL certificate to jersey client
private static String post() throws Exception {
String url ="https://www.test.lk/services/erl/es/erl/view/index.action";
Client client =createClient();
try {
return client
.target(url)
.request()
.get()
.readEntity(String.class);
} finally {
client.close();
}
}
private static Client createClient() throws Exception {
SSLContext ctx = SSLContext.getInstance("SL");
ctx.init(null, getTrustManager(), new SecureRandom());
HostnameVerifier verifier = new HostnameVerifier() {
#Override
public boolean verify(String hostName, SSLSession sslSession) {
return true;
}
};
return ClientBuilder.newBuilder().sslContext(ctx).hostnameVerifier(verifier).build();
}
private static TrustManager[] getTrustManager() {
return new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// Trust all servers
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// Trust all clients
}
} };
}
I found the solution. I just need to add certificate to the java KeyStore This helped me

How to bypass ssl certificate checking in java

I want access a SOAP webservice url having https hosted in a remote vm. I am getting an exception while accessing it using HttpURLConnection.
Here's my code:
import javax.net.ssl.*;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* Created by prasantabiswas on 07/03/17.
*/
public class Main
{
public static void main(String [] args)
{
try
{
URL url = new URL("https://myhost:8913/myservice/service?wsdl");
HttpURLConnection http = null;
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
https.setHostnameVerifier(DO_NOT_VERIFY);
http = https;
} else {
http = (HttpURLConnection) url.openConnection();
}
String SOAPAction="";
// http.setRequestProperty("Content-Length", String.valueOf(b.length));
http.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
http.setRequestProperty("SOAPAction", SOAPAction);
http.setRequestMethod("GET");
http.setDoOutput(true);
http.setDoInput(true);
OutputStream out = http.getOutputStream();
}
catch (Exception e)
{
e.printStackTrace();
}
}
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
private static void trustAllHosts() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException
{
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
} };
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
}
I'm getting the following exception:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1283)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1258)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at Main.main(Main.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
at sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(SSLContextImpl.java:1055)
at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.java:981)
at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:923)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
... 18 more
Tried different solution from the google search, Non of them worked. I want to avoid using keytool because I will be running my tests on different vm.
Does anyone have any solution for this?
Using X509ExtendedTrustManager instead of X509TrustManager() solved the problem. Here's the example:
public void trustAllHosts()
{
try
{
TrustManager[] trustAllCerts = new TrustManager[]{
new X509ExtendedTrustManager()
{
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return null;
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
{
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
{
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] xcs, String string, Socket socket) throws CertificateException
{
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] xcs, String string, Socket socket) throws CertificateException
{
}
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException
{
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException
{
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier()
{
#Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
catch (Exception e)
{
log.error("Error occurred",e);
}
}
Edit : Understand the vulnerability this would cause before using it. This is by no means recommended for production use.
The best way is to create a dummy trustmanager that trusts everything.
TrustManager[] dummyTrustManager = 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) {
}
} };
Then use the dummy trustmanager to initialize the SSL Context
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, dummyTrustManager, new java.security.SecureRandom());
Finally use the SSLContext to open connection
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL("https://myhost:8913/myservice/service?wsdl");
This question has already been answered here in more detail
Java: Overriding function to disable SSL certificate check
Update:
Above issue is due to certificate signature algorithm not being supported by Java. As per this post, later releases of Java 8 have disabled md5 algorithm.
To enable md5 support, locate java.security file under <jre_home>/lib/security
and locate the line (535)
jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024,
and remove MD5
Try with Apache HTTP client, this works for me.
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
});
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
// GET or POST request with the client
...
Instead of using HttpsURLConnection.setDefaultSSLSocketFactory and your own implementation of TrustManager or X509ExtendedTrustManager, you can use TrustManagerFactory with a KeyStore with the certificate that issued the certificate you need to trust (for a self-signed certificate, this is the same as the host certificate) and call HttpsURLConnection.setSSLSocketFactory on the specific instance. This is both less code and avoids the security problems with trusting all HTTPS certicates.
In main:
if (url.getProtocol().toLowerCase().equals("https")) {
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
https.setSSLSocketFactory(createSSLSocketFactory());
http = https;
}
The method createSSLSocketFactory looks like this:
private static SSLSocketFactory createSSLSocketFactory() {
File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
return sslContext.getSocketFactory();
}

Apache HttpClient Error: javax.net.ssl.SSLPeerUnverifiedException: Peer Not Authenticated

I'm trying to configure org.apache.http.client.HttpClient to work with https. This is the client configuration:
TrustManager[] trustManagers = new TrustManager[] { new DummyTrustManager() };
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
SSLSocketFactory sf = new SSLSocketFactory(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme scheme = new Scheme("https", 443, sf);
SchemeRegistry registry = new SchemeRegistry();
registry.register(scheme);
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(registry);
DefaultHttpClient client = new DefaultHttpClient(cm, httpParameters);
This is the code of DummyTrustManager:
public static class DummyTrustManager implements X509TrustManager {
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
And when I send request, I get
`javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated`
What could be the problem?
You also need to adjust the TrustStrategy:
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] certificate, String authType) {
return true;
}
};
SSLSocketFactory sf = new SSLSocketFactory(acceptingTrustStrategy, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
...
see a full example at: http://www.baeldung.com/httpclient-ssl

How can we do our own Certificate Verification Step in HTTPS

I need to put my own certificate verification step in SSL Handshake when making an HTTPS connection with HttpsURLConnection. I have written my own certificate verification code to verify some property in the host certificates say Certificate Revocation Status using Online Certificate Status Protocol. What is the proper way to include this step in Java. I can add it as a part of the default HostNameVerifier as follows but is there a proper way to do this?
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
public boolean verify(String s, SSLSession sslSession) {
return verifier.verify(s, sslSession) && MyVerifier.doMyVerification(sslSession);
}
});
Figured out a cleaner way. Can use our own TrustManager to do the custom certificate verification. Here is the code,
public class Test {
public static void main(String [] args) throws Exception {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
SSLContext.setDefault(ctx);
URL url = new URL("https://www.google.com");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
System.out.println(conn.getResponseCode());
conn.disconnect();
}
private static class DefaultTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
//Do certificate verification here and throw exception if invalid
throw new CertificateException();
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}
The correct way would be to get the peer certificate from the SSLSession in your HostnameVerifier and check it there.

Categories

Resources