Consume Web service over ssl using XFire - java

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.

Related

Configuring Jetty HTTP/2 Client to use my HostnameVerifier implementation

I am using Jetty HTTP2 Client 9.4.12 to support HTTP/2 server connection. It's working fine but on top of verifying the certificate, I also want to verify the Hostname using my javax.net.ssl.HostnameVerifier implementation. According to the doc https://www.eclipse.org/jetty/javadoc/9.4.12.v20180830/org/eclipse/jetty/util/ssl/SslContextFactory.html I can use setEndpointIdentificationAlgorithm("HTTPS") to enable hostname verification but how do I configure Jetty to use my implementation?
Thanks.
Jetty's HttpClient does not support javax.net.ssl.HostnameVerifier.
An enhancement request exists for this ...
https://github.com/eclipse/jetty.project/issues/3154
Feel free to comment on the open enhancement requesting it, and providing an example of how you would use it.
The support has been added in Jetty v9.4.15.v20190215.
final SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setHostnameVerifier((hostname, sslSession) -> {
// logic to verify hostname
return false;
});

Axis2 problem after consume different webservice with https but only one uses certificate authentication

I have an Java Web Application, which consumes different WebServices.
Now I have to consume one WebService that needs both way authentication.
I use SSLClientAxisEngineConfig implementation (https://github.com/linhkuivanen/axistools) that I send as parameter to my class that extends org.apache.axis.client.Service.
It worked.
But only if it is the first use of some Axis Client.
After that, if I consume a WebService with 'https' that does not require certificate, I got error "Untrusted Server Certificate Chain".
If I consume first a Webservice that does not require certificate authentication, when I try to consume the other one that need authentication, I got "Handshake failure" error.
I assume that Axis has some kind of cache that reuses the first configuration, but I cannot figure out a way to solve my problem.
Edit: I solved the problem.
I generated a new Axis Client with wsdl2java (Axis2-1.7.8), instead of using the Eclipse Web Service Client generator. Before consume the WebService, I register a new https protocol with client certificate and cacerts:
Protocol protocol = new Protocol("https", socketFactoryDinamico, 443);
Protocol.registerProtocol("https", protocol);
and after using it, I unregister the protocol:
Protocol.unregisterProtocol("https");
After this, I can consume other WebServices without certificate authentication without problems.
Edit2:
The classes generated by Eclipse:
public class NfseWSServiceLocator extends org.apache.axis.client.Service implements NfseWSService {
}
public interface NfseWSService extends javax.xml.rpc.Service {
}
And the class generated by Axis2:
public class NfseWSServiceStub extends org.apache.axis2.client.Stub {
}
"Untrusted Server Certificate Chain" means that your client doesn't trust the server certificate that is trying to establish a connection. In order to properly configure a HTTPS enabled communication scenario, both communication parties must trust each other.
The RFC 5246 defines the following:
unknown_ca
A valid certificate chain or partial chain was received, but the
certificate was not accepted because the CA certificate could not
be located or couldn't be matched with a known, trusted CA. This
message is always fatal.
Usually is the client that requires to trust the server certificate chain to establish the connection, since the server could be operating in anonymous mode not requesting a client certificate from the peer.

Netty skips hostname validation when we use trust manager with trustCertCollectionFile

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)?

Mutual Authentication (2-way SSL) in AWS Lambda

I am building an AWS Lambda service for a small PoC. The flow in PoC is :
take a (text) input via POST,
performs a small string manipulation +
store the manipulated value into DynamoDB, and then
send the same (manipulated) value to a particular URL via HTTP POST
Seems like a simple lambda tutorial example, but the tricky part for me was the authorization. The URL that I have to POST to only allows requests that are mutually authenticated via a SSL cert. How can I achieve this in Lambda ?
I could not find enough answers to make this work. I looked at using the AWS API gateway 2-way ssl cert option. However, For that to work, I need to install the receiving part cert into cert store. Is the even possible ? Or the only way is to use a micro-EC2 box ?
At Lambda, I am okay to use Node.JS, Java, or Python.
How to implement mutual TLS in AWS Lambda?
First big applause for Hakky54 for this good tutorial on mutual TLS.
https://github.com/Hakky54/mutual-tls-ssl
I followed his tutorial to understand and implement MTLS for AWS Lambdas. You can also test your implementation locally before deploying to AWS by just running the spring-boot app which saves a lot of time.
Steps (all commands are documented on the above link)
Export server cert and import it to client trust store
Load your client key store and trust store, I saved both in s3 bucket
Create TLS Context
SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(keyStore, stores.getKeyStorePassword().toCharArray())
.loadTrustMaterialtrustStore, (X509Certificate[] chain, String authType) -> true)
.build();
Create a new Jersey client
Client client = ClientBuilder.newBuilder()
.withConfig(new ClientConfig())
.sslContext(sslContext.get())
.trustStore(trustStore)
.keyStore(keyStore, keyStorePassword)
.build();
Make the call to the API
client.target(endpoint).get();
I am storing my keystore credentials in parameter store.

Apache SocketFactory compatible with java.net SocketFactory?

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.

Categories

Resources