I'm making a request using Apache's DefaultHttpClient and I need to override the SSL call so that I can attach a custom SSLSocketFactory (essentially a client cert) to it. To do this, I create a new custom scheme and connection manager and pass them over at httpClient creation:
...
new Scheme("https", 443, thirdPartySocketFactory);
...
DefaultHttpClient httpClient = new DefaultHttpClient(ccm);
...
The thirdPartySocketFactory passed at Scheme creation is the important part here. As the name suggests, it comes from a third party library that automatically handles mutual cert authentication with a JBoss server. I.e., it attaches a client cert + password to each outbound request.
The call itself is also made from a JBoss server (I'm actually hosting SOLR on it which is why the Apache call is necessary in the first place).
Problem is, the thirdPartySocketFactory object is of the type javax.net.SocketFactory, not org.apache.http.conn.scheme.SocketFactory which the Apache Scheme requires (see here).
Question: Is there any way to solve this nicely via some sort of wrapper? I thought the Apache SocketFactory would inherit from the javax.net one in some way but it doesn't look like it.
Alternatively, I can create a truely custom Apache SSLSocketFactory (see here), complete with truststore etc, but I really don't want to go down route until the other option is exhausted. Main reason being, the thirdPartySocketFactory method is tried and tested.
Thanks!
There is SSLSocketFactory#SSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory, X509HostnameVerifier hostnameVerifier) since version 4.2. This constructor serves as a adapter for any arbitrary JSSE SSLSocketFactory implementation.
Related
Until mongodb-java-driver 3.12.3, it is possible to use MongoClientOptions.Builder#socketFactory (deprecated) method to inject pre-made SocketFactory object to be able to use SNI to connect with SSL/TLS.
In the new driver (4.x), that has been removed (adviced to use SSLContext instead) and it is not clear how to use SNI with SSL/TLS connection. It is possible to use MongoClientSettings.Builder#applyToSslSettings(Block block) to create necessary SSLContext and invalid hostname allowance. However, as it is mentioned, it is not obvious how to set SNI to connect.
Does anybody know how to achieve this?
I am using io netty version 4.1.19.Final
I am trying to set up a client which will connect to a server using TLS.
I want the netty to perform hostname validation when it receives TLS certificates, but it looks like since I am using a custom trustManager using TLS Trust file path netty skips hostname validation completely.
Is there a way for me to specify a custom trustManager using TLS Trust file path AND have io netty perform hostname validation????
SslContextBuilder builder = SslContextBuilder.forClient();
File trustCertCollection = new File(conf.getTlsTrustCertsFilePath());
builder.trustManager(trustCertCollection);
Netty API:- https://netty.io/4.0/api/io/netty/handler/ssl/SslContextBuilder.html#trustManager-java.io.File-
Full code:-
https://github.com/apache/incubator-pulsar/blob/master/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConnectionPool.java#L97
Can you open a bug in the netty issue tracker and share some reproducer (best would a unit test)?
Is there any way to setup a separate SSL Context Factory for each route in Apache HTTP Client. From the documentation i can only see we can configure SSLContextFactory per scheme not per route.
Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", plainsf)
.register("https", sslsf)
.build();
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
HttpClients.custom()
.setConnectionManager(cm)
.build();
All my target endpoints are protected with HTTPS and mandates client certificate authentication. For each of these endpoint i have to select a specific client certificate & present it to the endpoint server. Currently i am seeing the only way is to create a separate HTTPClient instance for each target endpoint route & configure with SSLContext Factory instance.
I am here looking for any pointers to improving this design.
Thanks.
I have posted this question in Apache HTTP Client Forums & got the solution on how to handle this.
One can use 'http.socket-factory-registry' context attribute to that
end but please note this feature is considered undocumented.
http://hc.apache.org/httpcomponents-client-4.5.x/httpclient/xref/org/apache/http/impl/conn/DefaultHttpClientConnectionOperator.html#66
Please also note that one can build a custom ConnectionSocketFactory
that makes use of custom context attributes when creating SSL sockets.
That would be the recommended way to solve the issue.
My project use xfire as a web service client api. My project is in legacy Servlet/JSP. We used XFire eclipse plugin to generate client stub.
Web-service has Migrated to SLL (HTTPS). Is there any easy way to consume Webservice over SSL in XFire.
I found some code at http://docs.codehaus.org/display/XFIRE/HTTP+Transport.
I have some confusion there too. It motivates to use not-so-common-ssl which is in Alpha and I don't know if it is stable enough to be used in production.
// Technique similar to http://juliusdavies.ca/commons- ssl/TrustExample.java.html
HttpSecureProtocol protocolSocketFactory = new HttpSecureProtocol();
// "/thecertificate.cer" can be PEM or DER (raw ASN.1). Can even be several PEM certificates in one file.
TrustMaterial trustMaterial = new TrustMaterial(getClass().getResource("/thecertificate.cer"));
// We can use setTrustMaterial() instead of addTrustMaterial() if we want to remove
// HttpSecureProtocol's default trust of TrustMaterial.CACERTS.
protocolSocketFactory.addTrustMaterial(trustMaterial);
// Maybe we want to turn off CN validation (not recommended!):
protocolSocketFactory.setCheckHostname(false);
Protocol protocol = new Protocol("https", (ProtocolSocketFactory) protocolSocketFactory, 8443);
Protocol.registerProtocol("https", protocol);
Now above is a way to create a Protocol factory and getting it registered with Apache HTTPclient api. But id doesnot say what to do further with the generated stub.
Please feel free to ask more information if any.
We can't move to other web-service client api so that is not an option.
Managed to solve my own problem.
This is how I did it. XFire use Apache Http client internally so setting Security certifect detail on this Api will do the job. We will use no-yet-common-ssl.jar for this purpose.
First we will create org.apache.commons.ssl.TrustMaterial using commons and then set it in HttpSecureProtocol which is a child of javax.net.ssl.SSLSocketFactory.
Suppose XYZ.cer is the client certifect provided by service provider.
HttpSecureProtocol protocolSocketFactory = new HttpSecureProtocol();
protocolSocketFactory.addTrustMaterial(TrustMaterial.DEFAULT); //for trusting all the certifects in java trusted Store.
protocolSocketFactory.addTrustMaterial(new TrustMaterial(getClass().getResource("/XYZ.cer")));
Protocol protocol = new Protocol("https", (ProtocolSocketFactory)protocolSocketFactory, 443);
Protocol.registerProtocol("https", protocol);
If this is a web Application you can do this in ServletContextListener or in any part of code that executes when application boots.
Now you can use any ssl service using Xfire client stub. Any service which implement the above certifect.
Now why this work. Because XFire uses Apache Http Client as a connection api and we are telling Http client to use the above TrustManager when HTTPS is used.
I am writing a routine to access a remote server. This server I am connecting to requires mutual authentication so I have to provide a keystore, and while I'm at it I'd like to put a proper truststore in place as well.
I can find plenty of tutorials on how to create a keystore with keytool and multiple ways to get an Apache HTTP client to recognize it, but not where to store it in a Tomcat environment so that the application can find it. Somehow putting it in the application's war file seems like a bad idea to me.
Again, this is not to permit Tomcat to handle inbound https connections - I have a reverse proxy set up by our admin team for that. I'm creating outgoing https connections that require mutual authentication, i.e., both accepting a self-signed destination server certificate, and providing my server's self-signed client certificate.
Where do you store the actual keystore and truststore files in a Tomcat environment for use by a web application?
You can put your keystore wherever you want, as long as you know how to tell httpclient where to load the keystore.
That, of course, is the trick.
Using Apache httpclient for https
Buried in all that mess of code in the accepted answer is the key (ha!) to using httpclient with your own custom keystore. It's unfortunate that httpclient doesn't have a simple API like "here's the path to my keystore file, now use it" or "here are the bytes for my keystore, use those" (if you wanted to load the keystore from the ClassLoader or whatever), but that seems to be the case.
The honest truth is that using keystores and truststores in Java is messy business, and there's usually no way around it. Having written a client-cert-capable HTTP client myself using nothing other than HttpsURLConnection and then also adding raw-socket components to that, I know how painful it is.
The code in the above-linked article is fairly straightforward if a bit verbose. Unfortunately, you're going to need to make it a lot messier for production-quality code because you've got to do error-checking, etc. for every step of the process to make sure your service doesn't fall-over when you are trying to set up the various stores and make your connection.
This is basically a comment to Christopher Schultz's answer, but since it involves some code snippets please excuse my putting it here
It's unfortunate that httpclient doesn't have a simple API like
"here's the path to my keystore file, now use it" or "here are the
bytes for my keystore, use those" (if you wanted to load the keystore
from the ClassLoader or whatever), but that seems to be the case
This is how one can configure Apache HttpClient 4.3 to use a specific trust store for SSL context initialization.
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(trustStore)
.build();
CloseableHttpClient client = HttpClients.custom()
.setSslcontext(sslContext)
.build();
One can load trust material from a resource like that
URL resource = getClass().getResource("/com/mycompany/mystuff/my.truststore");
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream inputStream = resource.openStream();
try {
trustStore.load(inputStream, null /*usually not password protected*/);
} finally {
inputStream.close();
}