Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SOAPFaultException "MustUnderstand headers (oasis-200401-wss-wssecurity-secext-1.0.xsd) are not understood"

I try to get information from web service that uses PasswordText WSS type. Firstly, I test it using soapUI and successfully got data. Then I implemented authentication on Java, writing SecurityHandler:

public final class SecurityHandler implements SOAPHandler<SOAPMessageContext> {

...

@Override
public boolean handleMessage(SOAPMessageContext messageContext) {
    boolean outInd = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    if (outInd) {
        try {
            WSSecUsernameToken builder = new WSSecUsernameToken();
            builder.setPasswordType(WSConstants.PASSWORD_TEXT);
            builder.setUserInfo(_username, _password);
            builder.addNonce();
            builder.addCreated();

            Document doc = messageContext.getMessage().getSOAPPart().getEnvelope().getOwnerDocument();
            WSSecHeader secHeader = new WSSecHeader();
            secHeader.insertSecurityHeader(doc);
            builder.build(doc, secHeader);
        } catch (Exception e) {
            LOGGER.error("Unable to handle SOAP message", e);
            return false;
        }
    }
    return true;
}

...
}

I checked doc object with XMLUtils.PrettyDocumentToString(doc) and saw, that it look likes XML sent by soupUI - all authentication information (login, password, nonce and created time) were on place, mustUnderstand attribute of Security tag was true.

Then I faced with error:

javax.xml.ws.soap.SOAPFaultException: MustUnderstand headers:[{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood

I found advices to remove mustUnderstand attribute from Security tag, but it not helps. Do you have any ideas?

P.S.

Web service endpoint is on HTTPS.

Policy part from WSDL:

<wsp:Policy wsu:Id="BasicHttpBinding_RelateService_policy">
    <wsp:ExactlyOne>
        <wsp:All>
            <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:Lax/>
                        </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:Wss10>
                <wsp:Policy/>
            </sp:Wss10>
        </wsp:All>
    </wsp:ExactlyOne>
</wsp:Policy>

soapUI request:

<soapenv:Envelope xmlns:ns="http://api.example.com/RelateService/1.0"
                  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <wsse:Security soapenv:mustUnderstand="1"
                       xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsse:UsernameToken wsu:Id="UsernameToken-37"
                                xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                <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">
                    password
                </wsse:Password>
                <wsse:Nonce
                        EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
                    li/0YK2wxrmrHL7Cg+etdQ==
                </wsse:Nonce>
                <wsu:Created>2012-02-21T08:59:10.262Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </soapenv:Header>
    <soapenv:Body>
        <ns:RetrieveCustomerByEmail>
            <ns:email>[email protected]</ns:email>
            <ns:firstName/>
            <ns:lastName/>
        </ns:RetrieveCustomerByEmail>
    </soapenv:Body>
</soapenv:Envelope>

My request:

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header>
        <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"
                       S:mustUnderstand="1">
            <wsse:UsernameToken wsu:Id="UsernameToken-1">
                <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">
                    password
                </wsse:Password>
                <wsse:Nonce
                        EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
                    +jeleKO9zr0/wLjAIYcmSg==
                </wsse:Nonce>
                <wsu:Created>2012-02-21T09:42:03.760Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </S:Header>
    <S:Body>
        <ns5:RetrieveCustomerByEmail xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
                                     xmlns:ns2="http://schemas.datacontract.org/2004/07/XXX.Service"
                                     xmlns:ns3="http://schemas.datacontract.org/2004/07/XXX.Service.Relate.Contract"
                                     xmlns:ns4="http://schemas.datacontract.org/2004/07/XXX.Service.Dto"
                                     xmlns:ns5="http://api.example.com/RelateService/1.0"
                                     xmlns:ns6="http://schemas.microsoft.com/2003/10/Serialization/">
            <ns5:email>[email protected]</ns5:email>
            <ns5:firstName/>
            <ns5:lastName/>
        </ns5:RetrieveCustomerByEmail>
    </S:Body>
</S:Envelope>
like image 288
Marboni Avatar asked Feb 20 '12 16:02

Marboni


3 Answers

You could get this error when the service does not handle the headers. The service needs to implement a SOAPHandler with a getHeaders() that would resolve the headers. For the above mentioned fault the correct implementation would be as follows

 @Override 
    public Set<QName> getHeaders() { 
        QName securityHeader = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", 
                "Security"); 
        HashSet<QName> headers = new HashSet<QName>(); 
        headers.add(securityHeader);         
        return headers; 
    }

It is also possible to get this when the service is actually not secure, but the client is attempting to use security configuration (possibly using a XWSS security configuration) For this, just check the published wsdl from a browser and make sure it contains the expected security policy (append ?wsdl to its endpoint URL)

like image 74
Joseph Rajeev Motha Avatar answered Oct 01 '22 02:10

Joseph Rajeev Motha


I found the solution. Following dependencies were required:

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>2.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>2.2.3</version>
</dependency>

Good article on this topic and some pitfalls of cxf: http://www.logicsector.com/java/how-to-create-a-wsdl-first-soap-client-in-java-with-cxf-and-maven/

like image 32
Marboni Avatar answered Oct 01 '22 02:10

Marboni


Here is what worked for me. Basically, it's an application of the idea pronounced by @Joseph Rajeev Motha (although I found it elsewhere, here: https://dwuysan.wordpress.com/2012/04/02/jax-ws-wsimport-and-the-error-mustunderstand-headers-not-understood/#comment-215 ), but his answer does not provide boilerplate, and without it, the answer is pretty mysterious.

Please note that this sequence applies to the standalone case (where you publish an Endpoint yourself).

Step 1

Create a SOAPHandler that will 'understand' the header:

public class WSSESecurityUnderstandPretender implements SOAPHandler<SOAPMessageContext> {
    @Override
    public Set<QName> getHeaders() {
        final QName securityHeader = new QName(
            "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
            "Security",
            "wsse");

        final Set<QName> headers = new HashSet<>();
        headers.add(securityHeader);

        // notify the runtime that this is handled
        return headers;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        // we must return true, or else the runtime will return
        // wrong wrapper element name (like makeTransfer instead of
        // makeTransferResponse)
        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        // we must return true, or else the runtime will return
        // wrong wrapper element name (like makeTransfer instead of
        // makeTransferResponse)
        return true;
    }

    @Override
    public void close(MessageContext context) {
    }
}

Step 2

Create a handler-chain.xml file and put it on classpath:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains
     xmlns:javaee="http://java.sun.com/xml/ns/javaee"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <javaee:handler-chain>
    <javaee:handler>
      <javaee:handler-class>com.mypackage.WSSESecurityUnderstandPretender</javaee:handler-class>
    </javaee:handler>
  </javaee:handler-chain>
</javaee:handler-chains>

Step 3

Annotate your implementation class (class that is annotated with @WebService) with a reference to the handler chain file:

@HandlerChain(file = "handler-chain.xml")

Step 4

Publish your endpoint:

Endpoint endpoint = Endpoint.publish(url, impl);

An important note

handleMessage() and handleFault() defined by the handler must return true. Otherwise, you will get strange errors like 'Unexpected wrapper element' because a different wrapper element name will be used.

like image 4
Roman Puchkovskiy Avatar answered Oct 01 '22 02:10

Roman Puchkovskiy