tomcatsoapapache-axisrampartusernametoken

Securing Web Service with UsernameToken profile 1.0 using Axis2 and Rampart


this is my first question in stack overflow.

I'm not a expert java programmer but I have previous experience with the language and diffent IDEs.

I have a scenario where a customer requires that from a given WSDl I create a service that must be authenticated using a UsernameToken Profile 1.0 OASIS Standard 200401. It will be secured under ssl on production servers.

I've been doing some research and tried to implement different cases and I arrived at a point where nothing is working properly for me.

I'm using :

To ilustrate the current situation, here I show you the structure that eclipse creates for me when generating the java bean service structure from the wsdl eclipse as the base IDE.

https://dl.dropboxusercontent.com/u/71031985/schema.png


configuration applied:

in WebContent/WEB-INF/conf/axis2.xml I enable the rampart module and the passwordCallbackClass to be able to handle the username and password provided in the soap headers.

<module ref="rampart" />

<parameter name="InflowSecurity">
    <action>
        <items>UsernameToken</items>
        <passwordCallbackClass>
            serviceManager.ServiceAuthUserNameToken
        </passwordCallbackClass>
        <passwordType>PasswordText</passwordType>
    </action>
</parameter>

...

In the file located in /WebContent/WEB-INF/services/ProveedorCentroTFWS/META-INF/services.xml I place the rampart policy to be able to accomplish the usernametoken requirement:

    <wsp:Policy wsu:Id="UTOverTransport" 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">
<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:Basic128/>
          </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:SignedSupportingTokens>

    <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy"> 
        <ramp:passwordCallbackClass>serviceManager.ServiceAuthUserNameToken</ramp:passwordCallbackClass>
    </ramp:RampartConfig>

  </wsp:All>
</wsp:ExactlyOne>

When performing the call from a test client provided by the customer (and it cannot be modified) it sends the following soap message:

    <?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soapenv:mustUnderstand="1">
        <wsse:UsernameToken wsu:Id="UsernameToken-3">
            <wsse:Username>username</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">definedpwd</wsse:Password>
        </wsse:UsernameToken>
    </wsse:Security>
    <wsa:To>http://localhost:8080/ProveedorCentroTFWS</wsa:To>
    <wsa:MessageID>urn:uuid:f2fb54d9-8957-49a2-88a7-de6d209e6d35</wsa:MessageID>
    <wsa:Action>getActionList</wsa:Action>
</soapenv:Header>
<soapenv:Body>
    <ns3:getActionListxmlns:ns3="http://impl.ws.application.proveedorcentro.meyss.spee.es" />
</soapenv:Body>

The error returned is the following one once the soap message is sent:

    java.lang.RuntimeException: Malformed uri: UsernameTokenPolicy

And the stack trace that it follows is:

    org.apache.neethi.PolicyReference.getRemoteReferencedPolicy(PolicyReference.java:155)
org.apache.neethi.PolicyReference.normalize(PolicyReference.java:110)
org.apache.axis2.util.PolicyUtil.getMergedPolicy(PolicyUtil.java:267)
org.apache.axis2.description.AxisBindingMessage.calculateEffectivePolicy(AxisBindingMessage.java:294)
org.apache.axis2.description.AxisBindingMessage.getEffectivePolicy(AxisBindingMessage.java:225)
org.apache.axis2.context.MessageContext.getEffectivePolicy(MessageContext.java:1617)
org.apache.rampart.RampartMessageData.&lt;init&gt;(RampartMessageData.java:233)
org.apache.rampart.MessageBuilder.build(MessageBuilder.java:61)
org.apache.rampart.handler.RampartSender.invoke(RampartSender.java:65)
org.apache.axis2.engine.Phase.invokeHandler(Phase.java:340)
org.apache.axis2.engine.Phase.invoke(Phase.java:313)
org.apache.axis2.engine.AxisEngine.invoke(AxisEngine.java:262)
org.apache.axis2.engine.AxisEngine.sendFault(AxisEngine.java:516)
org.apache.axis2.transport.http.AxisServlet.handleFault(AxisServlet.java:433)
org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:216)
javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

I checked everything and every way to try to make it accept the soap messages, but I cannot make it work.

thanks for your support and attention


Solution

  • The solution to this problem is that the provided WSDL misses some parts to be able to autenticate under the UsernameToken Profile 1.0 OASIS Standard 200401.

    Found the solution to this under a IBM page about WS-Security with Metro.

    In the WSDL document, under a binding tag was a policy reference:

    <wsp:PolicyReference URI="#UsernameTokenPolicy" wsdl:required="true"/>
    

    Reading online documentation I saw that it was pointing to nowhere and it's necessary to add a policy entry at the same WSLD file like the next one having the identifier Name (#UsernameTokenPolicy) or the desired name of the policy we want to apply:

    <wsp:Policy wsu:Id="UsernameTokenPolicy" xmlns:wsp="http://www.w3.org/ns/ws-policy"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <sp:SupportingTokens
        xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
            <sp:UsernameToken
                sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                <wsp:Policy>
                    <sp:WssUsernameToken11 />
                </wsp:Policy>
            </sp:UsernameToken>
        </wsp:Policy>
    </sp:SupportingTokens>
    <wsss:ValidatorConfiguration wspp:visibility="private"
          xmlns:wsss="http://schemas.sun.com/2006/03/wss/server"
          xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy">
        <wsss:Validator name="usernameValidator" classname="[packageName].[callBackValidatorName]"/>
        </wsss:ValidatorConfiguration>
    </wsp:Policy>
    

    Once this is done, you need to create a callback Validator with the responibility to process the header credentials of the SOAP request, like the next example provided:

    package [packageName];
    
    
    import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
    import java.io.IOException;
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.UnsupportedCallbackException;
    
    public class [callBackValidatorName] implements PasswordValidationCallback.PasswordValidator{
    
    @Override
    public boolean validate(PasswordValidationCallback.Request request) throws PasswordValidationCallback.PasswordValidationException {
    
        PasswordValidationCallback.PlainTextPasswordRequest ptreq;
    
        ptreq = (PasswordValidationCallback.PlainTextPasswordRequest) request;
    
        return "[HARCODED_USERNAME]".equals(ptreq.getUsername()) &&
            "[HARCODED_PWD]".equals(ptreq.getPassword());
    }
    }
    

    Once all this is done, you must be able to autenticate a SOAP message that matches the UsernameToken Profile 1.0 OASIS Standard 200401 under a Java web service at server side.