[SalesForce] Constructing SOAP Security Header for wsse:UserToken

I'm trying to callout from Apex to an Address Validation webservice that requires a SOAP <Security> header to be set. But I can't seem to get it right.

From the WSDL:

<s0:Policy s1:Id="derm.service.common.esb.wspolicy.UNT.1">
        <wssp:Identity xmlns:wssp="http://www.bea.com/wls90/security/policy">
            <wssp:SupportedTokens>
                <wssp:SecurityToken TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#UsernameToken">
                <wssp:UsePassword Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-usernametoken-profile-1.0#PasswordText" />
                </wssp:SecurityToken>
            </wssp:SupportedTokens>
        </wssp:Identity>
    </s0:Policy>

Full WSDL: http://pastebin.com/Z5VswYNF

From the documentation linked from the WSDL (http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf) I retrieved this example:

<wsse:Security>
   <wsse:UsernameToken>
   <wsse:Username>REDACTED_PLAINTEXT_USERNAME</wsse:Username>
   <wsse:Password>REDACTED_PLAINTEXT_PASSWORD</wsse:Password>
   </wsse:UsernameToken>
</wsse:Security>

Replacing the values with the Username / Password I've been supplied and firing off the sample request from the documentation doesn't work.

Sample request with Security header:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soap="information.qld.gov.au/service/Addressing/ValidationService/2/soap">
<soapenv:Header>
    <wsse:Security>
       <wsse:UsernameToken>
       <wsse:Username>REDACTED_PLAINTEXT_USERNAME</wsse:Username>
       <wsse:Password>REDACTED_PLAINTEXT_PASSWORD</wsse:Password>
       </wsse:UsernameToken>
    </wsse:Security>
</soapenv:Header>
<soapenv:Body>
<soap:ParseValidAddress>
<soap:addressString>867 Main Street Woolloongabba Queensland</soap:addressString>
<soap:postcodeOption>Include</soap:postcodeOption>
<soap:meshblockOption>Exclude</soap:meshblockOption>
</soap:ParseValidAddress>
</soapenv:Body>
</soapenv:Envelope>

I've also tried the following from elsewhere on stackexchange:

  <wsse:Security SOAP-ENV:mustUnderstand="1" xmlns:SOAP-ENV="SOAP-ENV">
     <wsse:UsernameToken wsu:Id="UsernameToken-1" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:Username>oneview</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">oneview123</wsse:Password>
     </wsse:UsernameToken>
  </wsse:Security>

Everything I try gets a generic error message

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Client</faultcode>
         <faultstring>The requested operation was rejected. Please consult with your administrator.Your support ID is: REDACTED_SUPPORT_ID</faultstring>
         <detail/>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

What am I doing wrong?

Best Answer

Finally got to the bottom of this... The <wsse:Nonce> and <wsu:Created> elements were required. The following header included in the requests worked.

I use the same Nonce on each request. The Created date can be generated in Apex using

String requestTimeStamp = datetime.now().formatGMT('yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'');

The complete <Header> element:

<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" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:UsernameToken wsu:Id="UsernameToken-2E66C7C5CE47F74A5314575223194135">
            <wsse:Username>REDACTED_PLAINTEXT_USERNAME</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">REDACTED_PLAINTEXT_PASSWORD</wsse:Password>
            <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">0S0T0SfUpdJ7A1Wom+g1hg==</wsse:Nonce>
            <wsu:Created> + requestTimeStamp + </wsu:Created>
        </wsse:UsernameToken>
    </wsse:Security>
   </soapenv:Header>

In addition http headers on the request were set to:

req.setEndpoint('https://information.qld.gov.au/service/land/property/ValidationService/2/soap');

req.setHeader('Content-Type', 'text/xml;charset=UTF-8');
req.setHeader('SOAPAction', '"information.qld.gov.au/service/Addressing/ValidationService/2/soap/IValidationServiceEnhanced/ValidateLotPlan"');
req.setHeader('Content-Length', String.valueOf(requestXML.length()));
Related Topic