Web Service Client with Basic Authentication and SSL
Recently, I had to create a web service client for a web service that uses a number of Web Service Policies. In general, the web service utilizes the following policies:- Transport: Service uses one way certificates. Client had to download and check server´s certificate in order to prove the server´s identity.
- Authentication: Basic authentication is required to access the URL and the service WSDL.
- Creating the TrustStore: Access the Web Service URL, download the web service certificate and create a x509 trustStore to host the server´s certificate.
- Create the client Stub: Access the Web Service URL and create the client stub by compiling the WSDL with wsimport.
- Code and complete the service client. This has the following sub tasks:
- Code the client to use Basic Authentication
- Code the client to utilize the trustStore in order to setup SSL session with the server
- Code the client to call the web method.
Creating the SSL Trustore.
During SSL handshake, the trustStore is used to verify server´s id.Download the Server´s certificate by hitting the Web Service URL. There you will be prompted for login. You can login with the given user/password.
Then, the certificate is stored in your browser. You can export it easy but that depends to you browser. Chrome for example, the certificate can be downloaded directly as a x509 trustStore like the following image illustrates:
If you want to create the a trustStore manually you need to create a X509 keystore file using Java keytool and then import the server´s public certificate in it. The trustStore will be password protected and the certificate inside the trustStore will be password protected using "password" passphrase:
$ keytool -genkey -alias replserver -keyalg RSA -keystore mykeystore.jks -dname "cn=localhost, ou=IT, o=Continuent, c=DE" -storepass password -keypass password
Now you have the keyStore. Next you need to import the server´s public certificate in it. In the general case, supposing the Server certificate is the following one plain text file server-certificate.txt then do one of the following actions to:
Check the server´s certificate:
openssl x509 -in server-certificate.txt -text -noout
Delete previous certificate version from the trustStore if any:
keytool -delete -alias myserver-name.com -keystore mykeystore.jks
Re-import the server certificate to the trustStore:
keytool -import -alias myserver-name.com -keystore mykeystore.jks -file server-certificate.txt
Access the Web Service URL and create the client stub by compiling the WSDL with wsimport.
After running your wsimport command directly you should get a message complaining about a missing web authorization file.What you need to do is create an authorization file (usually the default name/location for it is $HOME_DIRECTORY/.metro/auth, but check the previous error message, you'll get the hint from there).
Inside this file you just write the line: "https://username:password@url?wsdl"
Now create a file called: wsimport_mysvc.bat and code the following commands:
setlocal set _JAVA_OPTIONS=%_JAVA_OPTIONS% -Djavax.net.ssl.trustStore=mykeystore.jks -Djavax.net.ssl.keyStorePassword=changeit -Djavax.net.ssl.trustStore=mykeystore.jks wsimport -s . -verbose -keep -p gr.illumine.wsclient.stub -extension https://myserver-name.com/wsd/alc_interface?wsdl endlocal
Doing so, you fulfill both conditions for basic authentication and also for transport/SSL by asking wsimport to examine what is been sent from server against to what is stored in mykeystore.jks
Run the wsimport_mysvc.bat and the client stub files will be created in the package gr.illumine.wsclient.stub
C:\>set _JAVA_OPTIONS= -Djavax.net.ssl.trustStore=cacerts -Djavax. net.ssl.keyStorePassword=changeit -Djavax.net.ssl.trustStore=cacerts C:\>wsimport -s . -verbose -keep -p gr.illumine.wsclient.stub -extension https://myserver-name.com/wsd/alc_interface?wsdl Picked up _JAVA_OPTIONS: -Djavax.net.ssl.trustStore=cacerts -Djavax.net.ssl.key StorePassword=changeit -Djavax.net.ssl.trustStore=cacerts parsing WSDL...
Code the client
The first thing you have to do is to add a static initializer that will provide the username and password for basic authentication:public class AlcClient { private static final Logger log= Logger.getLogger( AlcClient.class.getName() ); /* * Use this static initializer to provide Basic Authentication for the Web Service Consumption */ static { java.net.Authenticator.setDefault(new java.net.Authenticator() { @Override protected java.net.PasswordAuthentication getPasswordAuthentication() { return new java.net.PasswordAuthentication("happyuser", "mypassword".toCharArray()); } }); }
Next, configure your SSL settings in the code, by adding the following system parameters:
/* * Use the following settings to specify how this client will utilize the X509 trust store * called mykeystore.jks. In this trustore, it is stored the server´s public certificate * Also the trustore/keystores are password protected with a password "password" */ System.setProperty("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol"); System.setProperty("javax.net.ssl.keyStore","mykeystore.jks"); System.setProperty("javax.net.ssl.keyStorePassword","password"); System.setProperty("javax.net.ssl.keyStoreType", "JKS"); System.setProperty("javax.net.ssl.trustStore","mykeystore.jks"); System.setProperty("javax.net.ssl.trustStorePassword","password"); System.setProperty("javax.net.ssl.trustStoreType", "JKS");
Then add some debugging options to debug your SSL session. You are strongly advised to comment out the following code after testing it since it will affect the SSL performance.
/* Following options enable logging of all communication to the console * We are most interested in the request response SOAP Messages */ System.setProperty("com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", "true"); System.setProperty("com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump", "true"); System.setProperty("com.sun.xml.ws.transport.http.HttpAdapter.dump", "true"); System.setProperty("com.sun.xml.internal.ws.transport.http.HttpAdapter.dump", "true");
Now code the Web Service client instance by using the stub you have created with the wsimport:
ZALCINTERFACE_Service service = new ZALCINTERFACE_Service( new URL("myserver-name.com/wsd/alc_interface?wsdl"), new QName("urn:com:myserver-name:document:sap:soap:functions:mc-style",
"ZALC_INTERFACE")); /* * From this service get the proper port */ ZALCINTERFACE port = service.getZALCINTERFACE(); /* Make the web service call */ String responseMessage = port.callMyWebMethod();
Get the entire web service client java implementation can be downloaded here
No comments:
Post a Comment