Popular Posts

Sunday, February 14, 2010

How to invoke a secured web service without maintaining a policy at the client side

When we call a secure web service, the most common way of invocation is to use a policy which is compliant with the service policy at the client side. Usually, the client side policy is placed at the client file system. We have observed how this is done in few posts which published earlier.
However, there is a major drawback in this method, user has to change the client policy whenever the service policy is changed.
In order to overcome this limitation, we can use Axis2 DynamicClient to derive client policy by referring to the service WSDL which essentially keeps the service policy.

Lets see how this can be done using WSO2 WSAS-3.1.*

Pre-requisite:

Download and install WSO2 WSAS-3.1.*

Step 1

We are going to secure the default HelloService shipped with WSAS. We configure HelloService with "Sign and Encrypt - X509 Authentication" policy. In order to do that, first start WSO2 WSAS server by running wso2server.sh which is located at WSO2WSAS_HOME/bin directory.
Then, log in to the management console by accessing https://localhost:9443/carbon

Select the default HelloService and navigate to the service dashboard. Click on Security and configure Sign and Encrypt - X509 Authentication security scenario as shown below. Make sure to use wso2carbon.jks as trusted key store and private key store.



Thats all we have to do at the server side. Lets write a client to invoke the service.

Step 2

Here we are going to use Axis2 Dynamic Client which is an extension of the ServiceClient class.
First, instantiate a dynamicClient object using RPCServiceClient by passing ConfigurationContext, WSDL Url of the service, the QName of the service and the port name as parameters.

RPCServiceClient dynamicClient = new RPCServiceClient(null, new URL("http://localhost:9763/services/HelloService?wsdl"),
new QName("http://www.wso2.org/types", "HelloService"), "HelloServiceHttpSoap12Endpoint");

Then, we can engage rampart module as follows.
dynamicClient.engageModule("rampart");
Now we should update the client side policy with the rampart-config programatically.


RampartConfig rc = new RampartConfig();

rc.setUserCertAlias("wso2carbon");
rc.setEncryptionUser("wso2carbon");
rc.setPwCbClass(SecureClient.class.getName());

CryptoConfig sigCryptoConfig = new CryptoConfig();

sigCryptoConfig.setProvider("org.apache.ws.security.components.crypto.Merlin");

Properties prop1 = new Properties();
prop1.put("org.apache.ws.security.crypto.merlin.keystore.type", "JKS");
prop1.put("org.apache.ws.security.crypto.merlin.file", "/home/charitha/products/wsas/wso2wsas-3.1.3/resources/security/wso2carbon.jks");
prop1.put("org.apache.ws.security.crypto.merlin.keystore.password", "wso2carbon");
sigCryptoConfig.setProp(prop1);

CryptoConfig encrCryptoConfig = new CryptoConfig();
encrCryptoConfig.setProvider("org.apache.ws.security.components.crypto.Merlin");

Properties prop2 = new Properties();

prop2.put("org.apache.ws.security.crypto.merlin.keystore.type", "JKS");
prop2.put("org.apache.ws.security.crypto.merlin.file", "/home/charitha/products/wsas/wso2wsas-3.1.3/resources/security/wso2carbon.jks");
prop2.put("org.apache.ws.security.crypto.merlin.keystore.password", "wso2carbon");
encrCryptoConfig.setProp(prop2);

rc.setSigCryptoConfig(sigCryptoConfig);
rc.setEncrCryptoConfig(encrCryptoConfig);

Next, we can add the above rampartConfig to the service policy derived from the wsdl as follows.


Map endPoints = dynamicClient.getAxisService().getEndpoints();
AxisBinding axisBinding = ((AxisEndpoint) endPoints.values().iterator().next()).getBinding();
Policy policy = axisBinding.getEffectivePolicy();
policy.addAssertion(rc);
axisBinding.applyPolicy(policy);
Now, we can invoke the service using dynamicClient by passing the parameters as an object array and return types as an class array.


Object[] returnArray = dynamicClient.invokeBlocking(new QName("http://www.wso2.org/types", "greet"),
new Object[]{"hello"}, new Class[]{String.class});

System.out.println(returnArray[0]);


Thats all! To complete our scenario, make sure to have callback handler method similar to the one below.



public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

WSPasswordCallback pwcb = (WSPasswordCallback) callbacks[0];
String id = pwcb.getIdentifer();
if ("wso2carbon".equals(id)) {
pwcb.setPassword("wso2carbon");
}

No comments: