I'm currently facing the issue, that I can not consume a SOAP webservice via camel-cxf. The exception is the following:
org.apache.cxf.ws.policy.PolicyException: These policy alternatives can not be satisfied:
{http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}TransportBinding: Received Timestamp does not match the requirements
{http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}IncludeTimestamp
at org.apache.cxf.ws.policy.AssertionInfoMap.checkEffectivePolicy(AssertionInfoMap.java:179) ~[109:org.apache.cxf.cxf-rt-ws-policy:3.2.6]
at org.apache.cxf.ws.policy.PolicyVerificationInInterceptor.handle(PolicyVerificationInInterceptor.java:102) ~[109:org.apache.cxf.cxf-rt-ws-policy:3.2.6]
at org.apache.cxf.ws.policy.AbstractPolicyInterceptor.handleMessage(AbstractPolicyInterceptor.java:44) ~[109:org.apache.cxf.cxf-rt-ws-policy:3.2.6]
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) ~[78:org.apache.cxf.cxf-core:3.2.6]
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:813) [78:org.apache.cxf.cxf-core:3.2.6]
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1695) [102:org.apache.cxf.cxf-rt-transports-http:3.2.6]
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream$1.run(HTTPConduit.java:1194) [102:org.apache.cxf.cxf-rt-transports-http:3.2.6]
at org.apache.cxf.workqueue.AutomaticWorkQueueImpl$3.run(AutomaticWorkQueueImpl.java:421) [78:org.apache.cxf.cxf-core:3.2.6]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?]
at org.apache.cxf.workqueue.AutomaticWorkQueueImpl$AWQThreadFactory$1.run(AutomaticWorkQueueImpl.java:346) [78:org.apache.cxf.cxf-core:3.2.6]
at java.lang.Thread.run(Thread.java:748) [?:?]
and the SOAP answer the following:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><s:Fault><faultcode xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">a:InvalidSecurity</faultcode><faultstring xml:lang="de-DE">An error occurred when verifying security for the message.</faultstring></s:Fault></s:Body></s:Envelope>
I used the maven cxf-codegen-plugin
to generate the Java-classes via the wsdl2java
goal.
The security part of the wsdl looks like this:
<wsp:Policy wsu:Id="BasicHttpBinding_IUserManagementService_policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken RequireClientCertificate="false"/>
</wsp:Policy>
</sp:TransportToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Lax/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
</wsp:Policy>
</sp:TransportBinding>
<sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssUsernameToken10/>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SignedSupportingTokens>
<sp:Wss10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy/>
</sp:Wss10>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
and I want to use the UsernameToken
authentication.
Maven dependencies:
camel version: 2.20.3
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-blueprint</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-soap-starter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-security</artifactId>
<version>3.2.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-policy</artifactId>
<version>3.2.6</version>
<scope>provided</scope>
</dependency>
I tried to connect to the api via SoapUI and everything worked well. Either with the authentication-part of SoapUI or with specifying the security part in the SoapHeader, both worked.
My camel route-builder looks like this:
SoapJaxbDataFormat soap = new SoapJaxbDataFormat("org.tempuri", new ServiceInterfaceStrategy(IUserManagementService.class, true));
from("direct:userdata.soap.requests")
// .marshal(soap) // not sure, if I need to marshal here
.to("cxf://{{SOAP_URL}}" +
"?serviceClass=org.tempuri.IUserManagementService" +
"&serviceName={http://tempuri.org/}UserManagementService" +
"&endpointName={http://tempuri.org/}BasicHttpBinding_IUserManagementService" +
"&wsdlURL={{WSDL_URL}}" +
"&dataFormat=MESSAGE" +
"&username={{SOAP_USERNAME}}" +
"&password={{SOAP_PASSWORD}}" +
"&allowStreaming=false");
and I'm sending to the queue like this:
@EndpointInject(uri = "direct:userdata.soap.requests")
Endpoint endpoint;
@Produce(uri = "direct:userdata.soap.requests")
ProducerTemplate channel;
....
private Object sendRequest(Object request, String operationName) throws Exception{
Exchange inExchange = endpoint.createExchange(ExchangePattern.InOnly);
inExchange.getIn().setHeader(CxfConstants.OPERATION_NAME, operationName);
inExchange.getIn().setHeader(CxfConstants.OPERATION_NAMESPACE, "http://tempuri.org/");
inExchange.getIn().setBody(request);
Map<String, Object> context = new HashMap<>();
context.put("ws-security.username", soapUsername);
context.put("ws-security.password", soapPassword);
inExchange.getIn().setHeader(Client.REQUEST_CONTEXT, context);
Exchange outExchange = channel.send(inExchange);
log.error(outExchange.getOut().getBody(String.class));
Object result = outExchange.getIn().getBody(Object.class);
if(result.getClass().equals(FaultException.class)){
throw (FaultException) result;
}
return result;
}
where endpoint
is type org.apache.camel.Endpoint
and channel
is type org.apache.camel.ProducerTemplate
The request
-Object is of type from the autogenerated classes by the plugin.
I also tried, writing my own WSS4JOutInterceptor to handle the security part, but this also did not work.
Please let me know, if I need to provide more information.
Many thanks in advance
It turned out, there was an issue, interpreting the SOAP answer.
So actually the route works like this. Just set the headers ws-security.username
and ws-security.password
and the cxf will take care of creating the correct header.
I've also changed the dataformat to PAYLOAD
and marshalling is not needed at this point.
Thanks anyway for reading