Arsenalist

The Toronto Raptors Blog with an Arsenal touch

CXF WS-Security using JSR 181 + Interceptor Annotations (XFire Migration)

Posted by arsenalist on July 31, 2007

22 Responses to “CXF WS-Security using JSR 181 + Interceptor Annotations (XFire Migration)”

  1. Durga Says:

    Could you please include client side configuration of WSS4J handlers as well. Also can we use spring dependency injection to populate Hashmap properties? Please include spring configuration sample. Thanks.

  2. Apache CXF Artikel Says:

    [...] CXF WS-Security using JSR 181 + Interceptor Annotations [...]

  3. Kevin Says:

    Where do you get the annotation, “@InInterceptors” ?

  4. arsenalist Says:

    The fully qualified class name is org.apache.cxf.interceptor.InInterceptors. You’ll need CXF 2.0.1 or later as this was put in pretty recently:

    https://issues.apache.org/jira/browse/CXF-803

  5. Kevin Says:

    Great, thanks!
    There are typos in your example, class ValidateUserTokenInterceptor.
    for (int j = 0; j 0) // j< ?
    secRes.getPrincipal(); // what is secRes ?

    Thanks again.

  6. arsenalist Says:

    Thanks Kevin, I’ve fixed the example. WordPress really has some issues when displaying angle brackets…

  7. girish Says:

    > hi,
    > i am using cxf 2.1 and generate wsdl using jax-ws 2.0 as code first
    > aproach.
    > here my SEI throws a custom exception say MyException but when i
    generate
    > the stubs from wsdl .the implementation class throws
    > MyExceptionException_Exception so it gives me an error.
    > also this MyExceptionException_Exception and MyExceptionExceptionBean
    > class generated in the jaxws.
    > it is one error.
    >
    > when i call service from jsp i could not catch my exception and gives
    me
    > runtime error.
    >
    > but in server side it come with the proper error .
    > how can i display the error massage in jsp page.
    >
    > thanks and regards,
    > girish

  8. Shawn Says:

    Can the author post the client side code on this thread or send it to me in email?
    Many thanks!

  9. Shawn Says:

    For those who are interested in the code on the client side to make this example work, here are some of the details. Hope it would also work in your test environment and CXF settings.

    1) Run Apache CXF wsdl2java command to generate the client side stub;

    2) Code the WS Client as below:
    package test.security.client;

    import java.util.HashMap;
    import java.util.Map;

    import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
    import org.apache.cxf.endpoint.Client;
    import org.apache.cxf.endpoint.Endpoint;
    import org.apache.cxf.frontend.ClientProxy;
    import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
    import org.apache.ws.security.WSConstants;
    import org.apache.ws.security.handler.WSHandlerConstants;

    public class WsClient {

    /**
    * @param args
    */
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    SportsService_Service service = new SportsService_Service();
    SportsService port = service.getPort(SportsService.class);

    Client client = ClientProxy.getClient(port);
    Endpoint cxfEndpoint = client.getEndpoint();

    Map outProps = new HashMap();

    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
    cxfEndpoint.getOutInterceptors().add(wssOut);
    cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor());

    outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
    // Specify our username
    outProps.put(WSHandlerConstants.USER, “ws-client”);
    // Password type : plain text
    //outProps.setProperty(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);

    // for hashed password use:
    //properties.setProperty(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
    outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);

    // Callback used to retrive password for given user.
    outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordHandler.class.getName());

    String result = port.getTeam();
    System.out.println(”Result1: ” + result);

    result = port.getTeam();
    System.out.println(”Result2: ” + result);

    result = port.getTeam();
    System.out.println(”Result3: ” + result);

    }

    }

    3) Code the client side ClientPasswordHandler as below:
    package test.security.client;

    import java.io.IOException;

    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;

    import org.apache.ws.security.WSPasswordCallback;

    public class ClientPasswordHandler implements CallbackHandler {

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

    WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

    System.out.println(”Client Password for User: ” + pc.getIdentifer());

    // set the password for the outbound message.
    pc.setPassword(”password”);
    }

    }

    That is all I would need in order to see the SOAP message sent out from the client side as shown below:

    ws-clientyLOK86TGqE5NYmGx2vkpipfFwH4=nqDwJUBIicVkZA7gw1GASg==2007-10-04T16:49:34.375Z

  10. Shawn Says:

    import java.util.HashMap;
    import java.util.Map;

    import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
    import org.apache.cxf.endpoint.Client;
    import org.apache.cxf.endpoint.Endpoint;
    import org.apache.cxf.frontend.ClientProxy;
    import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
    import org.apache.ws.security.WSConstants;
    import org.apache.ws.security.handler.WSHandlerConstants;

    public class WsClient {

    /**
    * @param args
    */
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    SportsService_Service service = new SportsService_Service();
    SportsService port = service.getPort(SportsService.class);

    Client client = ClientProxy.getClient(port);
    Endpoint cxfEndpoint = client.getEndpoint();

    Map outProps = new HashMap();

    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
    cxfEndpoint.getOutInterceptors().add(wssOut);
    cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor());

    //outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
    outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN + ” ” + WSHandlerConstants.TIMESTAMP);
    // How long ( in seconds ) message is valid since send
    //outProps.put(WSHandlerConstants.TTL_TIMESTAMP, “100″);
    // if you want to use millisecond precision use this
    //outProps.put(WSHandlerConstants.TIMESTAMP_PRECISION, “true”);

    // Specify our username
    outProps.put(WSHandlerConstants.USER, “ws-client”);
    // Password type : plain text
    //outProps.setProperty(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);

    // for hashed password use:
    //properties.setProperty(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
    //outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
    outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);

    // Callback used to retrive password for given user.
    outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordHandler.class.getName());

    String result = port.getTeam();
    System.out.println(”Result1: ” + result);

    result = port.getTeam();
    System.out.println(”Result2: ” + result);

    result = port.getTeam();
    System.out.println(”Result3: ” + result);

    }

    }

  11. arsenalist Says:

    Thanks for posting this. It’s very similar to the XFire client:

    http://arsenalist.com/2007/01/18/implementing-ws-security-with-jsr181-annotations-using-wss4j-in-xfire/

  12. pokynsky Says:

    it is possible to obtain the user and password in the service?

  13. Feng Says:

    Shawn:
    I have trouble compile
    SportsService_Service service = new SportsService_Service();
    May I ask for the wsdl and the command that you use to generate the SportsService_Service class ?
    Thanks
    Feng

  14. Feng Says:

    I am also wondering what if the client is not Java based, say a .NET client, is there any example about integration ?

  15. Matt Madhavan Says:

    Hi,
    I am doing java first development. And I obtain my client proxy from the client-beans.xml file.

    How do I code my client now when I obtain my client proxy from using spring?

    Thanks
    Matt

  16. Nigel Says:

    Is there an example of a client which is a Spring application, ie

  17. Nigel Says:

    Client Bean

    Thanks

  18. yulinxp Says:

    You mention:
    Since WSS4J validates a UsernameToken only if it finds a security header we need to cover the case where no security header is specified.

    In the following snippet from WSS4JInInterceptor.java
    public void handleMessage(SoapMessage msg) throws Fault

    if (wsResult == null) { // no security header found
    if (doAction == WSConstants.NO_SECURITY) {
    return;
    } else {
    LOG.warning(”Request does not contain required Security header”);
    throw new SoapFault(new Message(”NO_SECURITY”, LOG), version.getSender());
    }
    }

    If no security header found, a SoapFault is thrown. In my test, I set WS Security in server but not in client. And my client side does receive that SoapFault. So do we still need ValidateUserTokenInterceptor?

  19. Arsenalist Says:

    I see what you’re saying and maybe they’ve changed the implementation on the server side however ValidateUserTokenInterceptor was present in the XFire samples and its use was recommended by the committers. I think you also need to look at the source code for the WSS4J class UsernameTokenProcessor to learn more.

    Have you tried the case where you specify an invalid username/password or a valid username but an invalid password? Do you still receive the SoapFault?

  20. yulinxp Says:

    It will handle PasswordDigest automatically.
    For PasswordText, I have to do the comparison and throw exception.

    public class ServerPasswordCallback implements CallbackHandler {
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

    WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

    String strClientPwd = pc.getPassword();
    int usage = pc.getUsage();

    if(pc.getIdentifer().equals(”joe”)) {

    String strServerPwd = “password”;

    if(usage == WSPasswordCallback.USERNAME_TOKEN) { //PasswordDigest
    pc.setPassword(strServerPwd);

    }else if(usage == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN) { //PasswordText
    pc.setPassword(strServerPwd);

    if(!strClientPwd.equalsIgnoreCase(strServerPwd)){ //DIY compare
    throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
    }
    }
    }
    }
    }

  21. Sai C Says:

    I am calling a .Net web service in Java (client)and used the JAXWsProxyFactoryBean by enabling the WSAddressFeature, however, my soap header does not contain a though it prints an element. Could somebody let me know how do I get wsa:action in soap header using CXF API.

    Appreciate your help.

    Regards,
    Sai

  22. Nilantha Says:

    Thanks for posting this,

    I would like to add following…

    for those who need to access Spring context in any part of the application including CallbackHanders, this would be helpful

    http://www.mail-archive.com/axis-user@ws.apache.org/msg22148.html

    please update if you come across any better way of doing that.

    Thanks,
    Nilantha