Hi,
I'm developing a SOAP web service *client* hosted in jboss EAP 6.0.1 (CXF
2.4.6).
The service side needs a UserNameToken header but no policy have been
declared in wsdl.
I played with WSS4JOutInterceptor but it is a little bit intrusive.
I didn't found any cxf jax-ws handler for wss4j so I started to try to add
this header with ws-policy.
If I modify the wsdl to add the policy, it works:
- declare the policy in wsdl:
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu="
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd
"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:sp="
http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens>
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="
http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"
/>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
- use the policy in the same wsdl:
<wsdl:binding name="TestServiceSOAP" type="tns:TestService">
<wsp:PolicyReference xmlns:wsp="
http://schemas.xmlsoap.org/ws/2004/09/policy" URI="#UsernameToken" />
<soap:binding style="document" transport="
http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="sayHello">
- result is what I expect:
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><wsse:Security
soap:mustUnderstand="1" xmlns:wsse="
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsse:UsernameToken
xmlns:wsu="
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="UsernameToken-1"><wsse:Username>testUserName</wsse:Username><wsse:Password
Type="
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">testPassword</wsse:Password></wsse:UsernameToken></wsse:Security></soap:Header><soap:Body><ns2:sayHello
xmlns:ns2="http://www.natixis.com/midsav/wsdl/TestService/
"><message>hello</message></ns2:sayHello></soap:Body></soap:Envelope>
But in real life, I cannot modify the wsdl because I'm on client side.
So I tried to dynamically add the the policy as shortly described in
http://cxf.apache.org/using-ws-policy-in-cxf-projects.html
I put the xml ws-policy in a file, load it with neethi and passed the
policy to CXF stack with PolicyConstants.POLICY_OVERRIDE:
@WebServiceRef
private TestServiceClient testService;
public String testWs() {
TestService port = testService.getTestServiceSOAP();
// load token policy
InputStream inputStream =
Thread.currentThread().getContextClassLoader().getResourceAsStream("username-token-ws-policy.xml");
Policy wsSecuritypolicy = new
PolicyBuilder().getPolicy(inputStream);
Map<String, Object> requestContext = ((BindingProvider)
port).getRequestContext();
requestContext.put(SecurityConstants.USERNAME, "testUserName");
requestContext.put(SecurityConstants.PASSWORD, "testPassword");
requestContext.put(PolicyConstants.POLICY_OVERRIDE,
wsSecuritypolicy);
return port.sayHello("hello");
The policy seems to be well charged by the policy interceptor but it
generate a ClassCastException:
Caused by: java.lang.ClassCastException:
org.apache.neethi.builders.PrimitiveAssertion cannot be cast to
org.apache.cxf.ws.security.policy.model.UsernameToken
at
org.apache.cxf.ws.security.wss4j.UsernameTokenInterceptor.assertUsernameTokens(UsernameTokenInterceptor.java:245)
[cxf-rt-ws-security-2.4.9-redhat-2.jar:2.4.9-redhat-2]
at
org.apache.cxf.ws.security.wss4j.UsernameTokenInterceptor.addUsernameToken(UsernameTokenInterceptor.java:264)
[cxf-rt-ws-security-2.4.9-redhat-2.jar:2.4.9-redhat-2]
at
org.apache.cxf.ws.security.wss4j.UsernameTokenInterceptor.handleMessage(UsernameTokenInterceptor.java:112)
[cxf-rt-ws-security-2.4.9-redhat-2.jar:2.4.9-redhat-2]
at
org.apache.cxf.ws.security.wss4j.UsernameTokenInterceptor.handleMessage(UsernameTokenInterceptor.java:76)
[cxf-rt-ws-security-2.4.9-redhat-2.jar:2.4.9-redhat-2]
at
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
[cxf-api-2.4.9-redhat-2.jar:2.4.9-redhat-2]
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:531)
[cxf-rt-core-2.4.9-redhat-2.jar:2.4.9-redhat-2]
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:461)
[cxf-rt-core-2.4.9-redhat-2.jar:2.4.9-redhat-2]
The cast is made on made on UsernameTokenInterceptor:
private UsernameToken assertUsernameTokens(SoapMessage message,
WSUsernameTokenPrincipal princ) {
AssertionInfoMap aim = message.get(AssertionInfoMap.class);
Collection<AssertionInfo> ais =
aim.getAssertionInfo(SP12Constants.USERNAME_TOKEN);
UsernameToken tok = null;
for (AssertionInfo ai : ais) {
*tok = (UsernameToken)ai.getAssertion(); <- cast*
The ai.getAssesrtion() returns a
org.apache.neethi.builders.PrimitiveAssertion instead of
org.apache.cxf.ws.security.policy.model.UsernameToken.
What I have done wrong? I search a lot for samples with
PolicyConstants.POLICY_OVERRIDE but did not find anything.
Best regards,
Christophe