Hi all,
i have two questions concerning how to implement WS-Security with CXF.
1) First question: how on the server side to read CallbackHandler supplied password?Followoing instructions on CXF homesite and from several articles, I have created simple HelloWorldService and attached to it following interceptors:
<jaxws:endpoint id="helloWorld" implementor="demo.spring.HelloWorldImpl" address="/HelloWorld" >
<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"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackClass" value="demo.interceptors.AuthenticationCallbackHandler"/>
</map>
</property>
</bean>
<bean class="demo.interceptors.ValidateUserTokenInterceptor"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
AuthenticationCallbackHandler is very simple it just does the following:
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if (pc.getIdentifer().equals("joe")) {
pc.setPassword("password");
}
}
I also wrote my demo.interceptors.ValidateUserTokenInterceptor which should Validate received token.
public void handleMessage(Message message) throws Fault {
boolean userTokenValidated = false;
logger.debug("Invoked - ValidateUserToken: " + message);
//logger.debug("messagePwd: " + message.get);
Vector result = (Vector) message.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
if (result==null) {
throw new IllegalArgumentException(WSHandlerConstants.RECV_RESULTS + " Property not found in MessageContext?!");
}
for (int i = 0; i < result.size(); i++) {
WSHandlerResult res = (WSHandlerResult) result.get(i);
for (int j = 0; j < res.getResults().size(); j++) {
WSSecurityEngineResult secRes = (WSSecurityEngineResult) res.getResults().get(j);
int action = secRes.getAction();
logger.debug("Checking: " + secRes);
// USER TOKEN
if ((action & WSConstants.UT) > 0) {
WSUsernameTokenPrincipal principal = (WSUsernameTokenPrincipal) secRes.getPrincipal();
logger.debug("name=" + principal.getName());
logger.debug("password=" + principal.getPassword());
logger.debug("passwordType=" + principal.getPasswordType());
logger.debug("createdTime=" + principal.getCreatedTime());
if (principal.getPassword() == null) {
throw new RuntimeException("Invalid Security Header");
} else {
// NOW COMPARE PASSWORDS - HOW????
userTokenValidated = true;
}
}
}
}
if (!userTokenValidated) {
throw new RuntimeException("Security processing failed");
}
}
So far i was able to read information from WSSE:Security header - ie. username and pwd supplied by the Client. But i do not know how to address the password value supplied by AuthenticationCallbackHandler inside this interceptor??
2) Second question: how to properly configure interceptors on client using spring?To test the service i wrote simple HelloClient:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/clientAppContext.xml");
HelloWorld client = (HelloWorld) context.getBean("client");
System.out.println("Invoking service...");
String text = client.sayHi("Domagoj");
System.out.println("Response=: " + text);
}
This is my clientAppContext.xml:
<bean id="client" class="demo.spring.HelloWorld" factory-bean="clientFactory" factory-method="create"/>
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="demo.spring.HelloWorld"/>
<property name="address" value="
http://localhost:8080/SoaLab/HelloWorld"/>
<property name="outInterceptors">
<list>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<property name="properties">
<map>
<entry key="action" value="UsernameToken"/>
<entry key="user" value="joe"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackClass" value="demo.interceptors.ClientPasswordCallback"/>
</map>
</property>
</bean>
</list>
</property>
</bean>
The problem i have is that Response i receive from HelloWorld service is null??
If i comment interceptors on both client and server side it all works fine.
Any suggestions?
Thx in advance....