To recap the previous article, it is very simple to expose a code first webservice using Apache CXF with Spring. Apache CXF provides a custom Spring namespace to easily configure the endpoint:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <bean id="memberendpoint" class="org.bk.memberservice.endpoint.DefaultMemberEndpoint"/> <jaxws:endpoint address="/memberservice" id="memberservicehttp" implementor="#memberendpoint" > </jaxws:endpoint> </beans>This exposes the memberendpoint bean above as a fully configured webservice.
To secure this service using usernametoken, first implement a callback for CXF to invoke to validate the credentials passed by the user:
package org.bk.memberservice.endpoint; 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 UsernameTokenCallback implements CallbackHandler { @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { Callback callback = callbacks[0]; WSPasswordCallback pc = (WSPasswordCallback) callback;
// Retrieve and set the real password..which will be validated
// by CXF validator against the digest password
pc.setPassword("test"); System.out.println("Received cred: " + pc.getIdentifier() + " : " + pc.getPassword()); // validate the credentials // boolean isValid = true; // throw IO Exception if the credentials are not valid // if (!isValid) { // throw new IOException("Bad Credentials"); // } } }
To wire this Callback handler with the service endpoint, CXF uses a concept called the interceptor, basically the webservice call is handled by the interceptors before being handed over to the service.
<jaxws:endpoint address="/memberservice" id="memberservicehttp" implementor="#memberendpoint"> <jaxws:inInterceptors> <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken" /> <entry key="passwordType" value="PasswordDigest" /> <entry key="passwordCallbackRef"> <ref bean="usernameTokenCallback" /> </entry> </map> </constructor-arg> </bean> </jaxws:inInterceptors> </jaxws:endpoint>That's it!! the endpoint is now secured using UsernameToken profile. To test this, bring up the endpoint, use SOAP UI to send a normal request, it will fail with the message that a ws-security header is required - this is the username token soap header that is expected as part of the request.
Fix this by adding the username and password, select "digest" as the password type and the service invocation should just work.
Updated Sample available at: git://github.com/bijukunjummen/memberservice-codefirst.git
Reference:
1. WS-Security reference in Wikipedia: http://en.wikipedia.org/wiki/WS-Security
2. WS-Secuirty usernametoken profile specs at OASIS: http://www.oasis-open.org/committees/download.php/16782/wss-v1.1-spec-os-UsernameTokenProfile.pdf
3. Apache CXF reference: http://cxf.apache.org/docs/ws-security.html
4. New changes as part of WSS4J - http://coheigea.blogspot.com/2011/02/wspasswordcallback-changes-in-wss4j-16.html
However, the WSDL doesn't contain the security policy. This make it difficult for client to know that WS-Security is to be used.
ReplyDeletenicely & cleanly explained
ReplyDeleteRaman