I'm trying implement WS-Policy in my services with CXF 3.1.0 and Spring 4.1.6
Most of examples that I found was with CXF 2 and structures like cxf-extension-policy.xml and cxf-extension-ws-security.xml changed in CXF new version.
I tried something like:
package spring;
import java.util.LinkedList;
import java.util.List;
import javax.xml.ws.Endpoint;
import org.apache.cxf.Bus;
import org.apache.cxf.feature.AbstractFeature;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.ws.policy.WSPolicyFeature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import com.student.StudentService;
import com.student.service.StudentServiceImpl;
@Configuration
@ImportResource({"classpath:META-INF/cxf/cxf.xml"})
public class CXFConfig {
@Autowired
private Bus cxfBus;
@Bean
public StudentService service(){
return new StudentServiceImpl();
}
@Autowired
@Bean
public Endpoint serviceImpl(
final StudentService service){
EndpointImpl endpoint = new EndpointImpl(this.cxfBus, service);
endpoint.setAddress("/StudentService");
endpoint.publish();
return endpoint;
}
}
My WSDL have some policies and is basically the WSDL from this tutorial
I generate my Java classes using Contract-first.
When I run my project my policies don't appears.
I tried
final Map<String, Object> properties = new HashMap<>();
properties.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
properties.put(WSHandlerConstants.PW_CALLBACK_REF, ServerPasswordCallback.class.getName());
EndpointImpl endpoint = new EndpointImpl(this.cxfBus, portType);
endpoint.setProperties(properties);
endpoint.setAddress("/StudentService");
endpoint.publish();
return endpoint;
I also tryed
final Map<String, Object> properties = new HashMap<>();
properties.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
properties.put(WSHandlerConstants.PW_CALLBACK_REF, ServerPasswordCallback.class.getName());
cxfBus.getFeatures().add(new WSPolicyFeature());
cxfBus.getInInterceptors().add(new WSS4JInInterceptor(properties));
EndpointImpl endpoint = new EndpointImpl(this.cxfBus, portType);
endpoint.setAddress("/StudentService");
endpoint.publish();
return endpoint;
And
WSPolicyFeature wsPolicyFeature = new WSPolicyFeature();
wsPolicyFeature.initialize(this.cxfBus);
None of this works.
Does someone knows how to configure this with Spring annotations?
After a while, I discover that WSS4J uses the idea of interceptor instead of policies in contract.
I changed my spring implementation to
EndpointImpl endpoint = new EndpointImpl(this.cxfBus, flightService);
endpoint.setAddress("/FlightService");
endpoint.setWsdlLocation("src/main/resources/wsdls/flightservice_v1r1.wsdl");
endpoint.getProperties().put("ws-security.callback-handler", new ServerPasswordCallback());
endpoint.publish();
However, even with that configuration when I deployed my contract it showed 2 wsdl:binding and 2 wsdl:service...
I found than another way to solve my problem and less couple than the first one, I externalize my policies in a XML file and anotated my service with
@Policies({
@Policy(uri="classpath:policies/usernameToken.xml", includeInWSDL=true)
})
My Spring configuration was reduced to
EndpointImpl endpoint = new EndpointImpl(this.cxfBus, new FlightServiceImpl());
endpoint.setAddress("/FlightService");
endpoint.getProperties().put("ws-security.callback-handler", new ServerPasswordCallback());
endpoint.publish();
When I deploy me project, finally I see
<wsdl:service name="FlightServiceImplService">
<wsdl:port binding="tns:FlightServiceImplServiceSoapBinding" name="FlightServiceImplPort">
<soap:address location="http://localhost:8080/ws-security/FlightService"/>
</wsdl:port>
<wsp:PolicyReference URI="#authenticationPolicy"/>
</wsdl:service>