Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

Swisscom, the leading ICT House in Switzerland provides under api-developer.swisscom.com a central API platform with a hugh number of different APIs. For example, it is possible to sent SMS messages or realize SMS Token authentication.

Within a project I had to realize an interface to one oft he provided APIs. Before a single API can be used it is necessary to call the authentication API (based on oAuth2) to receive an access token. The received token has to included into the http header when you call the real API. The authentication process has been realized based on the oAuth 2.0 standard. This standard is used on many API platforms and cloud services so it can also be interested for you.

The biggest problems have been:

  • To oAuth Service has to be called by a post. And the http body did not include a XML message.
  • As I had some problem to overwrite some http header values in the REST Adapter I had to use the HTTP Adapter why I had to write my own JSON to XML conversion.

Calling the oAUTH Service

If you want to authenticate against the oAUTH service it is necessary to send a client id and a secret key. Client id and secret key have to be combined.

            <client id>:<secret key>

And after that create combination has to become 64 Bit encoded. That 64 Bit encoded string has to send within the http header to the authentication service.

I decided to define on sender side the following structure.

The idea behind was that the sender has the flexibility to send directly the base64 encode string (base64) or client id and secret key ()client_id, client_secret) so that the mapping encodes the values. Furthermore he has the possibility to take influence on the authentication service with the grant_type element. The grant_type by default is client_credentials. In that case a new access token ist created. But if the grant type is set to refresh_token an existing token is renewed.

As the http request had to be posted and the http body hat too look like

grant_type=client_credentials / grant_type=refresh_token

I used a java mapping wishing the interface. The used Code is:


package com.my.mapping;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import com.sap.aii.mapping.api.AbstractTrace;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.DynamicConfiguration;
import com.sap.aii.mapping.api.DynamicConfigurationKey;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
import com.sap.aii.utilxi.core.io.IOUtil;
import org.apache.commons.codec.binary.Base64;

If the request is sending id and key it has to be base64 encoded. For that I integrated a library from Apache. That can be downloaded here.


public class CreateHTTPBody extends AbstractTransformation {
            public void transform(TransformationInput input, TransformationOutput output)
                                   throws StreamTransformationException {
                       try {
                                   AbstractTrace absTraceLog = this.getTrace();
                                   absTraceLog.addDebugMessage("\n Start Java Mapping-");
                                   DocumentBuilder domFactory = DocumentBuilderFactory.newInstance()
                                                          .newDocumentBuilder();
                                                              
                                   Document doc = domFactory.parse(input.getInputPayload()
                                                          .getInputStream());
                                   doc.getDocumentElement().normalize();
               
                                   String authCode = "";
                           
                                   //User / Passwort vorhanden?
                                   if (doc.getDocumentElement().getElementsByTagName("client_id")
                                                          .getLength() > 0 &&
                                               doc.getDocumentElement().getElementsByTagName("client_secret")
                                                          .getLength() > 0
                                                          &&
                                                          doc.getDocumentElement().getElementsByTagName(
                                                          "client_id").item(0).getTextContent() != ""
                                                                      &&
                                                                      doc.getDocumentElement().getElementsByTagName(
                                                                      "client_secret").item(0).getTextContent() != ""
                                                          )
                                       
                                   {
                                       
                                               String toEncode = doc.getDocumentElement().getElementsByTagName(
                                               "client_id").item(0).getTextContent() + ":" + doc.getDocumentElement().getElementsByTagName(
                                               "client_secret").item(0).getTextContent();
                                       
                                               authCode = new String(Base64.encodeBase64(toEncode.getBytes()));
                                               absTraceLog.addDebugMessage("\n Auth Code: " + authCode);
                                       
                                   }
                           
                                   if (doc.getDocumentElement().getElementsByTagName("base64")
                                                          .getLength() > 0
                                                          &&
                                                          doc.getDocumentElement().getElementsByTagName(
                                                          "base64").item(0).getTextContent() != ""
                                   ) {
                                       
                                               absTraceLog.addDebugMessage("\n base64 Anzahl: "
                                                                      + doc.getDocumentElement().getElementsByTagName("base64")
                                                                                             .getLength());
                                                                                     
                                               absTraceLog.addDebugMessage("\n base64 Value : "
                                                                      + doc.getDocumentElement().getElementsByTagName(
                                                                                             "base64").item(0).getTextContent());
                           
                                               authCode = doc.getDocumentElement().getElementsByTagName("base64").item(0).getTextContent();
                                               absTraceLog.addDebugMessage("\nBase 64:" + authCode); 
                           
                                   }

For the authentication it is necessary that later in the http header the base64 encoded authentication string is send. For that I used the folliwng

solution. The string is written into the dynamic configuration of the message.


                                   // Create Dynamic Configuration Object
                                    DynamicConfiguration conf = input.getDynamicConfiguration();
                                   DynamicConfigurationKey keyHeader1 = DynamicConfigurationKey.create( "http://sap.com/xi/XI/System", "HeaderFieldOne");
                                   conf.put(keyHeader1, "Basic " + authCode);                           

The information is written into the HeaderFieldOne field. So that it can be accessed later by the adapter.


absTraceLog.addDebugMessage("\n-------------------------------------");
                                  String strFlatData = "";
                                   InputStream inputStream = input.getInputPayload().getInputStream();
                                   inputStream.close();
                                   strFlatData = IOUtil.copyToString(inputStream, "UTF-8");
                                   strFlatData = strFlatData.replaceAll("&amp;", "&");
                                   if (doc.getDocumentElement().getElementsByTagName(
                                                                                             "base64").item(0).getTextContent() != "") {
                                         
                                               strFlatData = "grant_type=" + doc.getDocumentElement().getElementsByTagName(
                                               "grant_type").item(0).getTextContent();
                                         
                                   } else {
                                               strFlatData = "grant_type=client_credentials";
                                   }
                                   // output.getOutputPayload().getOutputStream().write(strFlatData.substring(strFlatData.indexOf("?>")+2).getBytes());
                                   output.getOutputPayload().getOutputStream().write(
                                                          strFlatData.getBytes());
                       } catch (Exception ie) {
                       }
            }




In case you want to use the mapping also you don't forget to upload the Apache Base64 Library as imported archive into your ESR.

At first I wanted to use the new REST Adapter. But as I had some issues by manipulating the http header. I decided to use the http Adapter. On the created communication channel it following settings has been necessary.

At first I had to set the content-type within the http header.

Furthermore the authentication string that has been put into the dynamic configuration has to be overtaken into the http Adapter. For that you have to activate the Adapter-Specific Message Properties. There check HTTP Header Fields and configure the HeaderFieldOne to Authorization.

Later during the runtime the Adapter will take the information from HeaderFieldOne and send it with the http header as

Authorization:base64encodedString


Processing the oAUTH Service response


The oAuth service sends his response back in JSON. As I used the http Adpater it was necessary that I transform the JSON result to XML. For that I created a java mapping that is running before my origin message mapping.



package com.my.mapping;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import com.sap.aii.mapping.api.AbstractTrace;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
import org.json.JSONObject;

For an easy and fast transformation from JSON to XML I used an additional JAR library that can be downloaded here.


The additional JAR library has to imported also as Imported Archive into the ESR.

In the Operation Mapping I configured two Mappings. The first is the JAVA mapping that transforms the JSON and after that the Message Mapping is used.


When the interface runs the son response is transformed into XML before the origin mapping runs.

JSON ResponseTransformed XML
{
   "access_token": "myToken",
   "scope": "read-mobiletypes",
   "token_type": "bearer",
   "expires_in": "2591999"
}
<?xml version="1.0" encoding="UTF-8"?>
<ns0:scsApiTokenResponse xmlns:ns0="http://pi.com/pi1/Standard">
  
<access_token>myToken</access_token>
  
<scope>read-mobiletypes</scope>
  
<token_type>bearer</token_type>
  
<expires_in>2591999</expires_in>
</ns0:scsApiTokenResponse>


Now the client (SAP PI) is identified at the platform. Later in the process the sender can use the token to authenticate against the API platform.

10 Comments
Labels in this area