Search code examples
node.jssoapws-securitynode-soap

How to change node-soap timestamp duration and prefix?


I am trying to consume a SOAP service using node-soap using WSSecurityCert. The service requires me to set the timestamp in such a way that the SOAP request has a validity of 5 minutes and wsu prefix. The node-soap library has 10 minutes of validity "hard-coded", with no obvious way to override it. I don't know how or if I can just modify the timestamp before it is sent, because the WSSecurityCert signature might be invalidated.

My code:

const client = await soap.createClientAsync(url);

const securityOptions = {
  hasTimeStamp: true,
}

const wsSecurity = new soap.WSSecurityCert(PRIVATE_KEY, PUBLIC_CERT, '', securityOptions);

client.setSecurity(wsSecurity);

const result = await client.method(args);

The generated timestamp looks like this:

<Timestamp
  xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  Id="_1">
  <Created>2024-05-08T13:20:09Z</Created>
  <Expires>2024-05-08T13:30:09Z</Expires>
</Timestamp>

I need to make the timestamp look something like this:

<wsu:Timestamp wsu:Id="TS-7C14BF4AA3E26845E015637928928701">
  <wsu:Created>2024-05-08T13:20:09Z</wsu:Created>
  <wsu:Expires>2024-05-08T13:25:09Z</wsu:Expires>
</wsu:Timestamp>

I tried to add created and expires among other things to securityOptions, to no avail.

Is it possible to achieve this with the node-soap library without forking it?


Solution

  • soap doesn't offer any way to customize the timestamp header, see the hardcoded lines: https://github.com/vpulim/node-soap/blob/master/src/security/WSSecurityCert.ts#L124.

    But you can disable the library's timestamp generation and add your own.

    Step 1: Disable hasTimestamp, add signing reference

    const options: IWSSecurityCertOptions = {
      hasTimeStamp: false,
      additionalReferences: [
        'wsu:Timestamp',
        'wsa:To',
      ],
      signerOptions: {
        prefix: 'ds',
        attrs: { Id: 'Signature' },
        existingPrefixes: {
          wsse11: 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd',
        },
      },
    };
    const wsSecurity = new WSSecurityCert(privateKey, publicKey, password, options);
    soapClient.setSecurity(wsSecurity);
    

    Step 2: Add your own timestamp

    const expiry = '2100-05-08T00:00:00Z'; // TODO: compute this
    const id = 'TS-7C14BF4AA3E26845E015637928928701'; // TODO: compute this
    soapClient.addSoapHeader((methodName, location, soapAction, args) => {
      return '<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" soap:mustUnderstand="1">' +
        `<wsu:Timestamp wsu:Id="${id}">` +
        `<wsu:Created>${new Date().toISOString()}</wsu:Created>` +
        `<wsu:Expires>${expiry}</wsu:Expires>` +
        '</wsu:Timestamp>' +
        '</wsse:Security>';
    });
    

    Note that toISOString() will have the timestamp with miliseconds, this wasn't an issue for the SOAP service I'm working with.

    Notice that the security header is included in here. This works because there is logic within soap to adjust accordingly, see https://github.com/vpulim/node-soap/blob/master/src/security/WSSecurityCert.ts#L141.

    Side note: I had to write my import statement like the following for the security classes, not sure if there's a better way:

    import { IWSSecurityCertOptions, WSSecurityCert } from 'soap/lib/security/WSSecurityCert';
    

    RESULT

    Your SOAP security header will have:

    <wsu:Timestamp wsu:Id="TS-7C14BF4AA3E26845E015637928928701">
        <wsu:Created>
            2024-05-10T17:23:56.937Z
        </wsu:Created>
        <wsu:Expires>
            2100-05-08T00:00:00Z
        </wsu:Expires>
    </wsu:Timestamp>
    

    And a signed reference like:

    <ds:Reference URI="#TS-7C14BF4AA3E26845E015637928928701">
        <ds:Transforms>
            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
        </ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        <ds:DigestValue>
            GR__REDACTED__e24=
        </ds:DigestValue>
    </ds:Reference>