Hi folks -

 

I've done the research into several places on the web and found a way to
get CXF + ACEGI to work on my app.  I'm just using the plain text
password, however, so I'd like a few other folks to bang on this before
I add it to the wiki:

 

Spring config - this goes in your cxf-servlet.xml file:

 

      <jaxws:endpoint id="XScoutCXF_xml_bare"

            implementor="[my implementation class - see standard docs
for what this should be]"

            wsdlLocation="WEB-INF/wsdl/XScoutCXF.wsdl"
address="/XScoutCXF">

            <jaxws:inInterceptors>

              <bean
class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>

              <bean
class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">

                <property name="properties">

                  <map>

                    <entry key="action" value="UsernameToken
Timestamp"/>

                    <entry key="passwordType" value="PasswordText"/>

                    <entry key="passwordCallbackClass" value="[your
class that extends CallbackHandler"/>      

                  </map>

                </property>

              </bean>

              <bean class="com[your class that extends
AbstractPhaseInterceptor]"/>

            </jaxws:inInterceptors>

            <jaxws:features>

                  <bean class="org.apache.cxf.feature.LoggingFeature" />

            </jaxws:features>

      </jaxws:endpoint>

 

The class that extends AbstractPhaseInterceptor has several required
constructors, but doesn't include a default constructor.  You have to
add it though, and I found that this works:

 

public ValidateUserTokenInterceptor()

{

            super(Phase.UNMARSHAL);

}

 

This is the essential method I had to add to the class that extends
AbstractPhaseInterceptor.  I haven't figured out exactly how it works
yet, except that it errors out if the password isn't validated in the
class extending CallbackHandler:

 

      public void handleMessage(Message message) throws Fault {

            ApplicationContext ctx = getApplicationContext();

            connector =
(SecurityConnector)ctx.getBean("securityConnector");

            boolean userTokenValidated = true;

            WSUsernameTokenPrincipal principal = null;

            Vector<Object> result = (Vector) message

 
.getContextualProperty(WSHandlerConstants.RECV_RESULTS);

            for (int i = 0; i < result.size(); i++) {

                  WSHandlerResult res = (WSHandlerResult) result.get(i);

                  String actor = res.getActor();

                  for (int j = 0; j < res.getResults().size(); j++) {

                        WSSecurityEngineResult secRes =
(WSSecurityEngineResult) res

                                    .getResults().get(j);

                        //

 

                        int action = secRes.getAction();

                        

                        switch(action)

                        {

                        case WSConstants.UT:

                              principal =
(WSUsernameTokenPrincipal)secRes.getPrincipal();

                              log.info(principal.getName());

                              break;

                              

                        case WSConstants.SIGN:

                              principal =
(WSUsernameTokenPrincipal)secRes.getPrincipal();

                              log.info(principal.getName());

                              java.security.cert.X509Certificate cert =
secRes.getCertificate();

                              Principal subjectPrincipal =
cert.getSubjectDN();

                              log.info(subjectPrincipal.getName());

                              Principal issuerPrincipal =
cert.getIssuerDN();

                              log.info(issuerPrincipal.getName());

                              break;

                        

                        case WSConstants.ENCR:

                              log.info("encrypted");

                              break;

                              

                        case WSConstants.TS:

                              log.info("timestamp created:
"+secRes.getTimestamp().getCreated());

                              log.info("timestamp expires:
"+secRes.getTimestamp().getExpires());

                              break;

                        

                        case WSConstants.NO_SECURITY:

                              log.info("No security");

                        

                        }

                  }

            }

 

            if (!userTokenValidated) {

                  throw new RuntimeException("Security processing
failed");

            }

      }

 

Here's the essential method in the class that extends CallbackHandler.
This is where you actually look up your user to confirm the credentials.
The logic is: validate the user is in your system, then set the password
here to the password passed back.  If the passwords don't match, the
system throws an error.  So, in my case, with a plain text password,
pc.setPassword(pc.getPassword()); seems kinda weird, but it works.

 

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

                  UnsupportedCallbackException {

            ApplicationContext ctx = getApplicationContext();

            connector =
(SecurityConnector)ctx.getBean("securityConnector");

            

            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

            System.out.println("we\'re in the callback handler");

            

            if(pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN)

            {

                  // @TODO: password is sent in digest mode.  we'll have
to code this to pull the clear password from the

                  // database to compare it at this end using the
following.  Until then, we'll just need to set the 

                  // password to something generic

                  /* to be implemented later:

                   * String plainText =
connector.getPassword(pc.getIdentifer());

                   *** this will throw an error if the incoming password
doesn't match what we found:

                   * pc.setPassword(plainText);

                   */

                  /** interim code - set generic password */

                  pc.setPassword(PLAIN_TEXT);

            }

            else if(pc.getUsage() ==
WSPasswordCallback.USERNAME_TOKEN_UNKNOWN)

            {

                  int userId = connector.getUser(pc.getIdentifer(),
pc.getPassword());

                  if(userId < 1)

                  {

                        throw new IOException("password incorrect for
user: " + pc.getIdentifer());

                  }

                  else

                  {

                        System.out.println("user id: " + userId +
"username: " + pc.getIdentifer());

                        pc.setPassword(pc.getPassword());

                  }

            }

            else

            {

                  throw new UnsupportedCallbackException(callbacks[0],
"Unrecognized Callback");

            }

      }

 

Anne Racel

Senior Software Engineer

Cormine Intelligent Data

 

Reply via email to