CallbackHandler in CXF 3.X and WSS4J 2.X

I am trying to upgrade our current application to CXF 3 and WSS4J 2. This is giving me a headache.

Current client application code:

private void secureWebService( Client client, final Credentials credentials ) {

  // set some WS-Security information
  Map<String,Object> outProps = new HashMap<String,Object>();
  outProps.put( WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN );
  outProps.put( WSHandlerConstants.USER, credentials.getUsername() );
  outProps.put( WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT );

  // Callback used to retrieve password for given user.
  outProps.put( WSHandlerConstants.PW_CALLBACK_REF, new CallbackHandler() {
     @Override
     public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
        pc.setPassword( credentials.getPassword() );
     }
  });

  WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor( outProps );
  client.getOutInterceptors().clear();
  client.getOutInterceptors().add( wssOut );
}

      

Server side ...

public class ServerPasswordCallback implements CallbackHandler {
    public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback pc = (WSPasswordCallback)callbacks[0];
        boolean result = false;
        try {
            LoginContext lc = new LoginContext( container, new CallbackHandler() {
                public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException {
                    NameCallback nc = (NameCallback)callbacks[0];
                    nc.setName( myGetName() );

                    PasswordCallback pc2 = (PasswordCallback)callbacks[1];
                    String clientPasssword = pc.getPassword(); //Used to contain the password but is now NULL
                    pc2.setPassword( clientPasssword.toCharArray() );
                }
            } );
            lc.login();
            result = true;
        } catch( LoginException le ) {
            le.printStackTrace(); //current stack trace is a NULLPointerException since "clientPassword" is NULL
            // We haven't authenticated, so false will be returned
        } catch( SecurityException se ) {
            throw new IOException( "Cannot create LoginContext. " + se.getMessage() );
        }
        return result;
    }
}

      

JAX-WS endpoint configuration:

<bean id="wss4jPasswordCallback" class="com.mycompany.webservice.security.ServerPasswordCallback"/>

<jaxws:endpoint id="customerEndpoint" implementor="#customerWebService" address="/Customer">
    <jaxws:inInterceptors>
        <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
            <constructor-arg>
                <map>
                    <entry key="action" value="UsernameToken"/>
                    <entry key="passwordType" value="PlainText"/>
                    <entry key="passwordCallbackRef">
                        <ref bean="wss4jPasswordCallback"/>
                    </entry>
                </map>
            </constructor-arg>
        </bean>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalInjectorInterceptor"/>
    </jaxws:inInterceptors>
    <jaxws:outInterceptors>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalRemoverInterceptor"/>
    </jaxws:outInterceptors>    
    <jaxws:outFaultInterceptors>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalRemoverInterceptor"/>
    </jaxws:outFaultInterceptors>   
</jaxws:endpoint>

      

In particular, the WSPasswordCallback object now passes NULL, rather than the password it used to. From my reading, CXF just decided to stop doing it with insufficient documentation as to what I would do for the update path. What is the upgrade path for this?

Also, I noticed that WSS4J changes where he lives. He moved from "org.apache.ws.security" to "org.apache.wss4j.common.ext". I also updated all my constants to "org.apache.wss4j.dom.WSConstants" and "org.apache.wss4j.dom.handler.WSHandlerConstants" to be able to compile. This also changed the old "org.apache.ws.security.validate.Validator" class in "org.apache.commons.validator.Validator" a lot. The classes are completely different now. Maybe "org.apache.wss4j.dom.validate.KerberosTokenValidator" is a new replacement? Again, I couldn't find any documentation on this fact.

Please note: this code works before upgrading to the new version of CXF and WSS4J!

+3


source to share


2 answers


Due to the considerable time I wasted on this issue, I wanted to make sure to provide my own solution. It may not be for everyone, but if your code is similar to my question, it should get you on the right track.

First, what was the Validator class, now an interface after CXF 3. What I'm working on is org.apache.wss4j.dom.validate.UsernameTokenValidator instead of what was org.apache.ws.security.validate. Validator. This critical piece of information was missing from my searches.

Therefore, if you are using CallbackHandler to perform custom authentication, you need to switch to UsernameTokenValidator. This is what my code looks like.

JAX-WS configuration:

<!-- Bean for custom authentication of web service -->
<bean id="UsernameTokenLDAPValidator" class="com.mycompany.webservice.security.UsernameTokenLDAPValidator"/>

<jaxws:endpoint id="customerEndpoint" implementor="#customerWebService" address="/Customer">
    <jaxws:inInterceptors>
        <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
            <constructor-arg>
                <map>
                    <entry key="action" value="UsernameToken"/>
                    <entry key="passwordType" value="PasswordText"/>
                </map>
            </constructor-arg>
        </bean>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalInjectorInterceptor"/>
    </jaxws:inInterceptors>
    <jaxws:outInterceptors>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalRemoverInterceptor"/>
    </jaxws:outInterceptors>    
    <jaxws:outFaultInterceptors>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalRemoverInterceptor"/>
    </jaxws:outFaultInterceptors>   
    <jaxws:properties>
        <entry key="ws-security.enable.nonce.cache" value="false" />
        <entry key="ws-security.enable.timestamp.cache" value="false" />
        <entry key="ws-security.ut.validator" value-ref="UsernameTokenLDAPValidator"/>
    </jaxws:properties>
</jaxws:endpoint>

      



NEW UsernameTokenLDAPValidator class

public class UsernameTokenLDAPValidator extends UsernameTokenValidator {


    public Credential validate( Credential credential, RequestData request ) throws WSSecurityException {
        UsernameToken userToken = credential.getUsernametoken();
        final String userId = userToken.getName();
        final String password = userToken.getPassword();
        String securityDomainName = "SecurityDomainNameNameOfJBOSSConfig"; //<login-module>

        LoginContext lc;
        try {
            lc = new LoginContext( securityDomainName, new CallbackHandler() {
                public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException {
                    NameCallback nc = (NameCallback)callbacks[0];
                    nc.setName( userId );

                    PasswordCallback pc2 = (PasswordCallback)callbacks[1];
                    pc2.setPassword( password.toCharArray() );
                }
            } );
            lc.login();
        } catch( LoginException e ) {
            throw new WSSecurityException( ErrorCode.FAILED_AUTHENTICATION, e );
        }

        return credential;
    }

}

      

Notes:

  • I removed my old CallbackHandler class (ServerPasswordCallback) (in the question)
  • I have not made any changes to the client application code (in the question)
+4


source


It looks like you are upgrading from an older version of CXF that used WSS4J 1.5.x. As of WSS4J 1.6.x, the CallbackHandler no longer ships with a password, but should instead set a password in the callback. See here:

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



Colm.

+1


source







All Articles