WSF/Spring, Axis2 + Spring Security with WS-Signature

Hi, I want to comment my experience on setting up a web service using WSF/Spring to expose and axis2 web service and integrating this with Spring Security so the authentication gets done by spring.

I will asume you have already set up a web service with WSF/Spring (just WSF for brevity) + WS-Signature (using rampart) and that you know about spring security, I will only show how to add an axis2 handler to WSF to intercept incoming web services operations and authenticate them using spring security and WS-Signature.

Axis2 Handler for Spring Security Integration



import util.ServiceContext;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import javax.security.auth.Subject;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.List;

/**
* Executed in a custom phase after the security phase has been proccesed
*
* Creado por: jaime
* 28/12/11
*/
public class SpringSecurityHandler extends AbstractHandler {

@Override
public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {


//  get xmldsig and authenticate
List<Object> results = (List<Object>) msgContext.getProperty(WSHandlerConstants.RECV_RESULTS);
if (results == null) {
return InvocationResponse.ABORT;
}


for (Iterator iter = results.iterator(); iter.hasNext(); ) {
WSHandlerResult hr = (WSHandlerResult) iter.next();
if (hr == null || hr.getResults() == null) {
return InvocationResponse.ABORT;
}
for (Iterator it = hr.getResults().iterator(); it.hasNext(); ) {
WSSecurityEngineResult er = (WSSecurityEngineResult) it.next();
if (er != null && er.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE) instanceof X509Certificate) {
X509Certificate x509Cert= (X509Certificate) er.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);

// TODO check against database

SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(x509Cert, null));


return InvocationResponse.CONTINUE;
}
}
}
return InvocationResponse.ABORT;
}

}

 

axis2Config.xml (Displaying only modified parts)


<bean id="axis2InFaultPhaseOrder">
<property name="phaseOrderType" value="InFaultFlow"></property>
<property name="phases">
<list>
<ref bean="axis2AddressingPhase"/>
<ref bean="security"/>
<ref bean="springSecurityCheckPhase"/>
<ref bean="preDispatchPhase"/>
<bean id="InFaultDispatchPhase">
<property name="name" value="Dispatch"></property>
<property name="clazz" value="org.apache.axis2.engine.DispatchPhase"></property>
<property name="handlers">
<list>
<ref bean="RequestURI"/>
<ref bean="SOAPAction"/>
<ref bean="RequestURIOperation"/>
<ref bean="SOAPMessageBody"/>
<ref bean="HTTPLocationBased"/>
</list>
</property>
</bean>
</list>
</property>
</bean>

<bean id="axis2InPhaseOrder">
<property name="phaseOrderType" value="InFlow"></property>
<property name="phases">
<list>
<ref bean="axis2TransportPhase"/>
<ref bean="axis2AddressingPhase"/>
<ref bean="security"/>
<ref bean="springSecurityCheckPhase"/>
<ref bean="preDispatchPhase"/>
<bean id="InDispatchPhase">
<property name="name" value="Dispatch"></property>
<property name="clazz" value="org.apache.axis2.engine.DispatchPhase"></property>
<property name="handlers">
<list>
<ref bean="RequestURI"/>
<ref bean="SOAPAction"/>
<ref bean="RequestURIOperation"/>
<ref bean="SOAPMessageBody"/>
<ref bean="HTTPLocationBased"/>
</list>
</property>
</bean>

</list>
</property>
</bean>



....

<!-- add a handler in the Security phase after SecurityInHandler-->

<bean id="springSecurityHandlerBean">
<property name="name" value="SpringSecurityHandler"></property>
<property name="clazz" value="com.kprtech.service.ws.security.SpringSecurityHandler"></property>
</bean>

<bean id="springSecurityCheckPhase">
<property name="name" value="SpringSecurityCheckPhase" />
<property name="handlers">
<list>
<ref bean="springSecurityHandlerBean"/>
</list>
</property>
</bean>


The last part of xml is creating a new phase with a handler (SpringSecurityHandler) and attaching it to axis2InPhaseOrder and axis2InFaultPhaseOrder after the Security proccesing of rampart.