P.H.
P.H.

Reputation: 481

Configuring WSS4J with CXF

I was doing pretty well with setting up a contract first set of web services using CXF until I started adding in the WSS4J piece.

I'm trying to debug sending a password and login in the soap header. I am getting null when I call getPassword() in the WSPasswordCallback class. I can see from the soap envelope that a password was sent.

This post, http://old.nabble.com/PasswordDigest-and-PasswordText-difference-td24475866.html, from 2009, made me wonder if I am missing (need to create) a UsernameTokenHandler.

And if that is true, can someone point me to how I would configure it in the spring/cxf bean xml file?

Any advice or suggestions would be appreciated.

Here's the Java file in question:

package com.netcentric.security.handlers;

import java.io.IOException;
import javax.annotation.Resource;
import javax.com.urity.auth.callback.Callback;
import javax.com.urity.auth.callback.CallbackHandler;
import javax.com.urity.auth.callback.UnsupportedCallbackException;
import org.apache.ws.com.urity.WSPasswordCallback;

public class ServicePWCallback implements CallbackHandler
{
   @Override
   public void handle(Callback[] callbacks) throws IOException, 
                UnsupportedCallbackException {
        try {
            for (int i = 0; i < callbacks.length; i++) {
                if (callbacks[i] instanceof WSPasswordCallback) {

                    WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];

                    sString login = pc.getIdentifier();

                    String password = pc.getPassword();
                    // password is null, not the expected myPASSWORD**1234

                    int n = pc.getUsage(); 
                    // this is 2 == WSPasswordCallback.USERNAME_TOKEN

              //...

The CXF/Spring configuration file:


    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:jee="http://www.springframework.org/schema/jee"
           xmlns:jaxws="http://cxf.apache.org/jaxws"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"
        default-dependency-check="none" default-lazy-init="false">

        <import resource="classpath:META-INF/cxf/cxf.xml" />
        <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

        <bean id="serverPasswordCallback" class="com.netcentric.security.handlers.ServicePWCallback"/>
        <bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
            <constructor-arg>
                <map>
                    <entry key="action" value="UsernameToken"/>
                    <entry key="passwordType" value="PasswordText"/>
                                    <entry key="passwordCallbackRef">
                        <ref bean="serverPasswordCallback"/>
                    </entry>
                </map>
            </constructor-arg>
        </bean>

        <jaxws:endpoint id="FederationImpl"
            implementor="com.netcentric.services.federation.FederationImpl"
            endpointName="e:federation"
            serviceName="e:federation"
            address="federation"
            xmlns:e="urn:federation.services.netcentric.sec">

                    <jaxws:inInterceptors>
                            <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
                            <ref bean="wss4jInInterceptor"/>
                    </jaxws:inInterceptors>
        </jaxws:endpoint>
    </beans

The soap message:


    <?xml version="1.0" encoding="UTF-8"?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <soapenv:Header>
            <wsse:comurity xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wscomurity-comext-1.0.xsd" soapenv:mustUnderstand="1">
                <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wscomurity-utility-1.0.xsd" wsu:Id="Timestamp-16757598">
                    <wsu:Created>2011-09-22T18:21:23.345Z</wsu:Created>
                    <wsu:Expires>2011-09-22T18:26:23.345Z</wsu:Expires>
                </wsu:Timestamp>
                <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wscomurity-utility-1.0.xsd" wsu:Id="UsernameToken-16649441">
                    <wsse:Username>pam</wsse:Username>
                    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">myPASSWORD**1234</wsse:Password>
                </wsse:UsernameToken>
            </wsse:comurity>
        </soapenv:Header>
        <soapenv:Body>
            <getVersion xmlns="urn:federation.services.netcentric.com">
                <getVersionRequest/>
            </getVersion>
        </soapenv:Body>
    </soapenv:Envelope>

Upvotes: 0

Views: 12506

Answers (3)

Brahim
Brahim

Reputation: 1

I add this :

// set the password on the callback. 
This will be compared to the            
// password which was sent from the client.            
pc.setPassword("password");

==> the password between "" will be compared with password sended by client.

Client side: write login = bob ; Password = bobPassword (will be digested)

Server side: Catch user = bob and the function user.setPassword(bobPassword) verify if the password received is correct or no.

Upvotes: 0

P.H.
P.H.

Reputation: 481

Thanks for all your help. I have made progress on this. I am using CXF 2.4.2 and WSS4J 1.6.2. The framework now takes care of checking the password for you. So the correct inside section is

            if (callbacks[i] instanceof WSPasswordCallback) {
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                sString login = pc.getIdentifier();
                String password = getPassword(login);
                pc.getPassword(login); 
                //...
            }

Instead of retrieving the password from the soap header to compare against the expected value, you lookup the expected value and pass it to the framework to do the comparison.

Upvotes: 3

Daniel Kulp
Daniel Kulp

Reputation: 14607

If using CXF 2.4.x, I would recommend reading:

http://coheigea.blogspot.com/2011/02/usernametoken-processing-changes-in.html

and seeing if that helps provide some extra information. Colm's blog is a treasure trove of useful info about recent WSS4J releases.

Upvotes: 5

Related Questions