Skip to Content
Technical Articles
Author's profile photo ASUTOSH MAHARANA

SAP Cloud Integration: Web Services Security UsernameToken

Introduction

This document describes how to use the UsernameToken with the WSS: SOAP Message Security specification in SAP CPI iFlow. A web service consumer can supply a UsernameToken as a means of identifying the requestor by “username”, and optionally using a password (or shared secret, or password equivalent) to authenticate that identity to the web service producer.

There is standard configuration feature provided in SOAP 1.x channel in SAP CPI. But there might be some custom requirement which requires additional scripts.

Main

The <wsse:UsernameToken> element is introduced in the WSS: SOAP Message Security documents as a way of providing a username. Under <wsse:UsernameToken> element, we can specify below 3 elements.

  1. <wsse:Username> : This element contains the username of the user which is known to the webservice provider.
  2. <wsse:Password> : (Optional) Any password equivalent such as a derived password or S/KEY (one time password) can be used. This element has an attribute name type which can have 2 values.
    • PasswordText: Password in clear text format
    • PasswordDigest: Passwords of type PasswordDigest are defined as being the Base64 encoded, SHA-1 hash value, of the UTF8 encoded password. (Password_Digest = Base64(SHA-1(nonce + created + password)))
  1. <wsse:Nonce> : A nonce is a random value that the sender creates to include in each UsernameToken that it sends.
  2. <wsu:Created> : Creation Timestamp.

We will discuss below 3 scenarios.

  1. Standard SAP CPI SOAP channel with UsernameToken password type as “PasswordText”.
  2. Standard SAP CPI SOAP channel with UsernameToken password type as “PasswordDigest”.
  3. Custom requirement to have Nonce and created time with password type as “PasswordText”.
    • Password should have password type “PasswordText”.
    • Password should be SHA256 encrypted.
    • Created time should be in OffsetDateTime Java format rather than Instant Java format.

Scenario 1

Standard SAP CPI SOAP channel with UsernameToken password type as “PasswordText”.

Channel%20Configuration

Channel Configuration

MPL%20Log%20Payload

MPL Log Payload

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
        <wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-0f4c1454-cc6a-45b5-ac7e-6e97a0859743">
                <wsse:Username>asutosh</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:UsernameToken>
        </wsse:Security>
    </soap:Header>
    <soap:Body>
        <NumberToDollars xmlns="http://www.dataaccess.com/webservicesserver/">
            <dNum>500</dNum>
        </NumberToDollars>
    </soap:Body>
</soap:Envelope>

Observation

By default, it’s not generating the Nonce and created element if we choose Password Type as “PasswordText”.

 

Scenario 2

Standard SAP CPI SOAP channel with UsernameToken password type as “PasswordDigest”.

Channel%20Configuration

Channel Configuration

MPL%20Log%20Payload

MPL Log Payload

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
        <wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-eb17926b-f05e-47ed-b745-4e3da22b7f71">
                <wsse:Username>asutosh</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">zzNBkzinVYR0DEBt45zR2eRyD40=</wsse:Password>
                <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">XbGt7Y3GbO701D48CcLiTQ==</wsse:Nonce>
                <wsu:Created>2021-12-19T13:30:07.211Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </soap:Header>
    <soap:Body>
        <NumberToDollars xmlns="http://www.dataaccess.com/webservicesserver/">
            <dNum>500</dNum>
        </NumberToDollars>
    </soap:Body>
</soap:Envelope>

Observation

This configuration generates the password in hashed format but there is no standard configuration available to change the Created element as per time zone requirement.

 

Scenario 3

Custom requirement to have Nonce and created time with password type as “PasswordText”.

  1. Password should have password type “PasswordText”.
  2. Password should be SHA256 encrypted.
  3. Created time should be in OffsetDateTime Java format rather than Instant Java format.

SOAP%20Message%20via%20HTTPS%20Adapter%20using%20Script

SOAP Message via HTTPS Adapter using Script

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import java.io.IOException;
import java.security.MessageDigest;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.common.util.*;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.message.WSSecHeader;
import org.apache.wss4j.dom.message.WSSecUsernameToken;
import org.w3c.dom.Document;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.xml.sax.InputSource;
import org.apache.commons.codec.digest.DigestUtils;

def Message processData(Message message) {
    //Build w3c Document from CPI message Body which should be in SOAP format
    def body = message.getBody(String);
    def username = "asutosh";
    def password = "password";
    String sha256hexPassword = org.apache.commons.codec.digest.DigestUtils.sha256Hex(password);
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = null;
    builder = factory.newDocumentBuilder();
    Document doc = builder.parse(new InputSource(new StringReader(body)));
    //Add WSS Header to the Document
    WSSecHeader secHeader = new WSSecHeader(doc);
    secHeader.insertSecurityHeader();
    //Add UsernameToken to the WSS Header
    WSSecUsernameToken builder1 = new WSSecUsernameToken(secHeader);
    builder1.setPasswordType(WSConstants.PASSWORD_TEXT);    //Define Password type
    builder1.setUserInfo(username, sha256hexPassword);          //Define Username and Password
    builder1.addNonce();                                    //Add Nonce
    Instant instant = Instant.now();                        //Get Current UTC time
    ZoneOffset offset = ZoneId.of("-05:00").getRules().getOffset(instant);
    OffsetDateTime odt = instant.atOffset(offset);          //Get Peru time which is -0500
    builder1.addCreated();                                  //Add Created time to UsernameToken
    Document utDoc = builder1.build();                      
    //Convert Document to string
    DOMSource domSource = new DOMSource(utDoc);
    StringWriter writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer transformer = tf.newTransformer();
    transformer.transform(domSource, result);
    def body3 = writer.toString();
    //Replace UTC time with Peru Time
    def body4 = body3.replaceAll(instant.toString(), odt.toString());
    body4 = body4.replaceAll("Header>", "soap:Header>");
    //Set SOAP Specific Header
    message.setHeader("Content-Type", "text/xml");
    message.setHeader("SOAPAction", "\"#POST\"");
    //Set the message to Body
    message.setBody(body4);
    return message;
}

MPL%20Log%20Payload

MPL Log Payload

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap: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" soap:mustUnderstand="1">
            <wsse:UsernameToken wsu:Id="UsernameToken-fefbc88c-ad91-4bff-9887-c8514eeb6dda">
                <wsse:Username>asutosh</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8</wsse:Password>
                <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">/u4eo1lijXzNerUn/6VLZg==</wsse:Nonce>
                <wsu:Created>2021-12-19T08:48:20.029-05:00</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </soap:Header>
    <soap:Body>
        <NumberToDollars xmlns="http://www.dataaccess.com/webservicesserver/">
            <dNum>500</dNum>
        </NumberToDollars>
    </soap:Body>
</soap:Envelope>

Observation

I have used Apache WSS4J library which requires no external jar to be imported in SAP CPI. You can explore the library for all kinds of custom requirements for WS-Security specifications. We were able to generate Nonce and Created element for Password Type “PasswordText”. It’s also possible to modify the created time for time zone specific requirement.

 

Conclusion

There are certain requirements which require custom scripting. You can take reference of this document for further understanding of SOAP Web Services Security Specifications.

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo prachetas singh
      prachetas singh

      Nice blog!

      Was looking for this for a very long time.