Java – What WS-Security settings should I apply to connect to wsdl descripted SOAP service

cxfjavawebservice-clientws-securitywsdl

I've been given task to create java client for a specific web service that is described by following wsdl file:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Person" targetNamespace="http://tempuri.org/">
  <wsp:Policy wsu:Id="WSHttpBinding_IPersonService_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:Strict />
              </wsp:Policy>
            </sp:Layout>
            <sp:IncludeTimestamp />
          </wsp:Policy>
        </sp:TransportBinding>
        <sp:EndorsingSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <wsp:Policy>
            <sp:SecureConversationToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
              <wsp:Policy>
                <sp:BootstrapPolicy>
                  <wsp:Policy>
                    <sp:SignedParts>
                      <sp:Body />
                      <sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing" />
                      <sp:Header Name="From" Namespace="http://www.w3.org/2005/08/addressing" />
                      <sp:Header Name="FaultTo" Namespace="http://www.w3.org/2005/08/addressing" />
                      <sp:Header Name="ReplyTo" Namespace="http://www.w3.org/2005/08/addressing" />
                      <sp:Header Name="MessageID" Namespace="http://www.w3.org/2005/08/addressing" />
                      <sp:Header Name="RelatesTo" Namespace="http://www.w3.org/2005/08/addressing" />
                      <sp:Header Name="Action" Namespace="http://www.w3.org/2005/08/addressing" />
                    </sp:SignedParts>
                    <sp:EncryptedParts>
                      <sp:Body />
                    </sp:EncryptedParts>
                    <sp:TransportBinding>
                      <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:Strict />
                          </wsp:Policy>
                        </sp:Layout>
                        <sp:IncludeTimestamp />
                      </wsp:Policy>
                    </sp:TransportBinding>
                    <sp:SignedSupportingTokens>
                      <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:Wss11>
                      <wsp:Policy />
                    </sp:Wss11>
                    <sp:Trust10>
                      <wsp:Policy>
                        <sp:MustSupportIssuedTokens />
                        <sp:RequireClientEntropy />
                        <sp:RequireServerEntropy />
                      </wsp:Policy>
                    </sp:Trust10>
                  </wsp:Policy>
                </sp:BootstrapPolicy>
              </wsp:Policy>
            </sp:SecureConversationToken>
          </wsp:Policy>
        </sp:EndorsingSupportingTokens>
        <sp:Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <wsp:Policy />
        </sp:Wss11>
        <sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <wsp:Policy>
            <sp:MustSupportIssuedTokens />
            <sp:RequireClientEntropy />
            <sp:RequireServerEntropy />
          </wsp:Policy>
        </sp:Trust10>
        <wsaw:UsingAddressing />
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>
  <wsdl:types>
    <xsd:schema targetNamespace="http://tempuri.org/Imports">
      <xsd:import schemaLocation="https://localhost:442/Services/Person.svc?xsd=xsd0" namespace="http://tempuri.org/" />
      <xsd:import schemaLocation="https://localhost:442/Services/Person.svc?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="IPersonService_GetSomething_InputMessage">
    <wsdl:part name="parameters" element="tns:GetSomething" />
  </wsdl:message>
  <wsdl:message name="IPersonService_GetSomething_OutputMessage">
    <wsdl:part name="parameters" element="tns:GetSomethingResponse" />
  </wsdl:message>
  <wsdl:portType name="IPersonService">
    <wsdl:operation name="GetSomething">
      <wsdl:input wsaw:Action="http://tempuri.org/IPersonService/GetSomething" message="tns:IPersonService_GetSomething_InputMessage" />
      <wsdl:output wsaw:Action="http://tempuri.org/IPersonService/GetSomethingResponse" message="tns:IPersonService_GetSomething_OutputMessage" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="WSHttpBinding_IPersonService" type="tns:IPersonService">
    <wsp:PolicyReference URI="#WSHttpBinding_IPersonService_policy" />
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="GetSomething">
      <soap12:operation soapAction="http://tempuri.org/IPersonService/GetSomething" style="document" />
      <wsdl:input>
        <soap12:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="Person">
    <wsdl:port name="WSHttpBinding_IPersonService" binding="tns:WSHttpBinding_IPersonService">
      <soap12:address location="https://localhost:442/Services/Person.svc" />
      <wsa10:EndpointReference>
        <wsa10:Address>https://localhost:442/Services/Person.svc</wsa10:Address>
      </wsa10:EndpointReference>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

I've created java client with Apache CXF's wsdl2java and in client invocation used new AddressingFeature(true), because services are in HTTPS, like that:

Person p = new Person();
IPersonService iPersonService = p.getWSHttpBindingIPersonService(new AddressingFeature(true));
System.out.println(iPersonService.getSomething());

but I get following exception:

org.apache.cxf.binding.soap.SoapFault: The message could not be processed. This is most likely because the action 'http://tempuri.org/IPersonService/GetSomething' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.

So far, I've tried adding ws-security.username and ws-security.password like so, but it didn't work, I get the same exception:

((BindingProvider) iPersonService).getRequestContext() 
   .put("ws-security.username", "user"); 
((BindingProvider) iPersonService).getRequestContext() 
   .put("ws-security.password", "password"); 

So, most probably I didn't applied some kind of security settings. Can anybody describe what WS-Security settings should I apply for this specific wsdl?

Update:
Added xsd schemas: https://gist.github.com/the-lay/12c2dc5091c5dc783f00

Best Answer

The problems were following:

  • I didn't realise that if I don't use cxf-rt-ws-policy dependency then the policy settings of WSDL are being silently ignored. To solve this, I've added this to my pom.xml (or you can add the whole bundle - cxf-bundle package) and starting from there I've got another exception, but that was the progress anyway.

  • After that I've got exception that "No Username provided", even though I had it in my cxf.xml. The problem was that I have used wrong jaxws:client name attribute. I've used the service name, but you must use the port name (which you can find in the end of the wsdl file) and you also have to use createdFromAPI attribute for that client. So, in the end it should look like this:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:cxf="http://cxf.apache.org/core"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
   http://cxf.apache.org/jaxws
   http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">

    <cxf:bus> <!-- it's not mandatory, just easier with this -->
        <cxf:features>
            <cxf:logging/>
        </cxf:features>
    </cxf:bus>

    <jaxws:client name="{http://tempuri.org/}WSHttpBinding_IPersonService"
                  createdFromAPI="true">
        <jaxws:properties>
            <entry key="ws-security.username" value="Username"/>
            <entry key="ws-security.password" value="Password"/>
        </jaxws:properties>
    </jaxws:client>
</beans>
Related Topic