Sunday, February 7, 2010

How to create a Password Callback class

Most of web services have been secured using various WS security  methods. Therefore we need to implements clients that support WS-Security to invoke these web services.

If you are using Rampart or WSS4J for WS-Security for processing in client side,  you may need to create a password callback class for following

1) Get the password to build the username token

2) Get the private key password for signture or decryption


It is very easy to write a Password callback. Following Java code is for simple Password callback class

package org.wso2.samples.pwcb;

import org.apache.ws.security.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;

public class PWCBHandler implements CallbackHandler {

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

            for (int i = 0; i < callbacks.length; i++) {
                WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
                String id = pwcb.getIdentifer();
                int usage = pwcb.getUsage();


                   if (usage == WSPasswordCallback.USERNAME_TOKEN) {
                   // Logic to get the password to build the username token
                        if ("admin".equals(id)) {pwcb.setPassword("admin");}
                } else if (usage == WSPasswordCallback.SIGNATURE || usage == WSPasswordCallback.DECRYPT) {
                // Logic to get the private key password for signture or decryption
                        if ("client".equals(id)) {pwcb.setPassword("apache");}
                        if ("service".equals(id)) {pwcb.setPassword("apache");}
                }

            }
        }
}

Lets see how you can use this password class back class with the WSO2 products such as ESB and BPS. For ESB, we need a class back class to invoke a secured BE services where ESB Proxy service would act as client for BE service.  Also when external partner service is invoked by a BPEL is act as a client to the external web service.

Therefore we need to create a jar file ... 

Step1 : Creating a jar file 

Note :  If you are familiar with maven. Please find the maven project of callback class from here 

1. Copy sample Password callback in to text file and save it as PWCBHandler.java

2. Create a directory called "temp"  ...any where you like,

3. Go in to temp directory and create following directory structure   org/wso2/samples/pwcb

4. Copy PWCBHandler.java in to pwcb directory

5. Download wss4j.jar from here (http://ws.apache.org/wss4j/) and copy it to temp directory

6. Compile PWCBHandler.java pointing classpath to wss4j.jar from pwcb directory

Ex:-
#javac PWCBHandler.java -classpath /home/asela/temp/PWC/org/wso2/samples/pwcb/wss4j-1.5.8.jar

7. Go in to temp directory and create a jar file issuing following

#jar cf PWCBHandler.jar org/wso2/samples/pwcb/*.class

Step2 : Adding jar file in to classpath

1. Now you have created your  PWCBHandler.jar and Copy jar in to <CARBON_HOME> /repository/components/lib

2. Restart Server


That All........!!!

5 comments:

  1. hello;
    please, how I can point my policy file of the External partner service to the password Callback jar?

    can you give me an example.

    thanks

    ReplyDelete
  2. Great post - this is what I was looking for :) I couldn't figure out why this bloody ESB doesn't work - now it's fine :) Thanks!!!

    ReplyDelete
  3. Great comment, am having an issue with compiling the PWCBHandler.java and i think the jar file i have used is cause of the problem.

    It returns the error below on unix: PWCBHandler.java:22: error: package org.apache.ws.security does not exist
    import org.apache.ws.security.WSPasswordCallback;
    ^
    PWCBHandler.java:33: error: cannot find symbol
    WSPasswordCallback pwcb = (WSPasswordCallback) callback;
    ^
    symbol: class WSPasswordCallback
    location: class PWCBHandler
    PWCBHandler.java:33: error: cannot find symbol
    WSPasswordCallback pwcb = (WSPasswordCallback) callback;
    ^
    symbol: class WSPasswordCallback
    location: class PWCBHandler
    PWCBHandler.java:36: error: cannot find symbol
    if (usage == WSPasswordCallback.USERNAME_TOKEN) {
    ^
    symbol: variable WSPasswordCallback
    location: class PWCBHandler
    PWCBHandler.java:41: error: cannot find symbol
    } else if (usage == WSPasswordCallback.SIGNATURE || usage == WSPasswordCallback.DECRYPT) {
    ^
    symbol: variable WSPasswordCallback
    location: class PWCBHandler
    PWCBHandler.java:41: error: cannot find symbol
    } else if (usage == WSPasswordCallback.SIGNATURE || usage == WSPasswordCallback.DECRYPT) {
    ^
    symbol: variable WSPasswordCallback
    location: class PWCBHandler
    6 errors

    ReplyDelete
  4. Hi, I have implemented the same callback method for WSO2 ESB, but in this way the password is actually hard-coded in the jar file. What I am looking for is a solution that can enable us to retrieve the password from somewhere else - for example the WSO2 Secure Vault.

    Do you know any approach that can achieve that? I have been looking for the answers for long time.

    ReplyDelete