Introduction:

Hello Integration Experts!!

I would glad to let you know that recently we had a business requirement where we need to Integrate with the Bloomberg to retrieve the daily exchange rates. Bloomberg is the global leader in business and financial datahttps://www.bloomberg.com/

Bloomberg supports Webservices, SFTP, REST API for Integration. We are using REST API with JWT (JSON Web Token) Oath authentication as latest, secure, and recommended approach by Bloomberg. This blog explains how you can Integrate SAP CI with the Bloomberg API with JWT signed by ClientSecret.

Use Case:

You might have created JWT and sign it using the X509 certificate’s Private key created and assigned with “SimpleSigner” pallet function of SAP CI.

But in this use case, we did not have that option to use private key pair and share the public certificate to Bloomberg to verify the signature.

Instead, we explored how you can implement the Signature by a valid ClientSecret. you can use the ClientSecret shared by Bloomberg and Create the Signature using HMAC SHA256 algorithm to generate the JWT and get authenticated with Bloomberg. Each request to Bloomberg API must include the unique JWT.

In this blog. I will explain how to create the JWT, Sign it by ClientSecret using the HMAC SHA256 and get authenticated with Bloomberg.

So, let’s get started. 🙂  Before that just wanted to Thank my friend saurabh sharma Nitin Pandey Nawaz Shareef who also contributed to explore on the same. Cheers 🙂

Prerequisites:

  1. Register your application, whitelist the IPs with Bloomberg and generate the ClientId, ClientSecret.
  2. Use the generated ClientSecret in sap CI to create the Signature.

Process steps:

JWT is a special JSON object with signature for verification that the request comes from the trusted source. JWTs Include a header, Payload with claim set and signature signed by a valid credential (ClientSecret).

The JWT is divided into three base64url encoded parts separated by. (dot) character.

  • JWT Header
  • JWT Payload
  • JWT Signature

Check here: https://jwt.io/

We can generate the JWT token by implementing the signature using HMAC SHA256 algorithm by using the Groovy Script in SAP CI.

  • Create a JWT header with this format: {“alg”:”HS256″,”typ”:”JWT”} and encode it using the Base64.
  • Create a JSON Claims Set for the JWT with iat, exp, nbf, iss, method, path, host, request_id, region and encode it using Base64.
  • Concatenate JWT Header and JWT Claim by dot (.) character and define as unsigned token.
  • Sign the resulting string using HMAC SHA256 by a valid Credential (ClientSecret) and encode the signature using Base64.
  • Convert the ClientSecret hex string to byte array before passing the same into HMAC SHA256 method of groovy.
  • Concatenate the unsigned token and signature by dot(.) which is nothing but the JWT to authenticate with Bloomberg.

Sample CI Integration Flow

you can declare the parameters in Exchange Property of Content Modifier as shown below.

Groovy Script for Generating the JWT

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;

def Message processData(Message message) {
    
    //Properties 
    map = message.getProperties();
    def clientSecret = map.get("clientSecret");
    def clientId = map.get("clientId");
    
    //convert Hex String to Byte array
    def clientSecretBlob = hexStringToByteArray(clientSecret);
   
    // Prepare JWT Header
    def jwtHeader = JWTHeader()
    
    // Prepare JWT JWTClaim
    def jwtClaim = JWTClaim()
    
    // Concat JWT Header and JWT Claim
    def unsignedToken= "${jwtHeader}" + "." + "${jwtClaim}";
    
    //JWT Signature
    def hash = hmac_sha256(clientSecretBlob, unsignedToken)
    signature = hash.encodeBase64().toString().replaceAll("n","").replaceAll("\+","-").replaceAll("/", "_").replaceAll("\=","");
    
    //Headers
    def content = "application/json";
    message.setHeader("Content-Type", content);
    message.setHeader("api-version", 2);
    message.setHeader("jwt", unsignedToken + "." + signature);

    return message;
}

def JWTHeader() {
    def jwtHeader = """
            {"alg":"HS256","typ":"JWT"}
            """
    def jwtHeader_str = Base64.encodeBase64URLSafeString(jwtHeader.replaceAll("\s","").getBytes("UTF-8"));

    return jwtHeader_str;
}

def JWTClaim() {
    def iat = (int)(new Date().getTime() / 1000);
    def exp = (int)((new Date().getTime() / 1000) + 30);
    def nbf = (int)(new Date().getTime() / 1000);
    def iss = map.get("clientId");
    def method = map.get("method");
    def path = map.get("path");
    def host = map.get("host");
    def request_id = UUID.randomUUID().toString();
    def region = map.get("region");
    def jwtClaim = """
            {"exp":${exp},"iat":${iat},"nbf":${nbf},"iss":"${iss}","method":"${method}","path":"${path}","host":"${host}","request_id":"${request_id}","region":"${region}"}
            """
    def jwtClaim_str = Base64.encodeBase64URLSafeString(jwtClaim.replaceAll("n","").replaceAll("\\","/").getBytes("UTF-8"));
    
    return jwtClaim_str;
}

def hexStringToByteArray(String s){
    def len = (int) s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        int j = i / 2;
        String byte_hex = s.substring(i, i + 2);
        try {
            int byte_value = Integer.parseInt(byte_hex, 16);
            data[j] = (byte) byte_value;
        } catch (NumberFormatException error) {
            throw new IllegalArgumentException("Bad hex byte value " + byte_hex);
        }
    }
    return data;
}
def hmac_sha256(secretKey, String data) {
    try {
         Mac mac = Mac.getInstance("HmacSHA256")
         SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, "HmacSHA256")
         mac.init(secretKeySpec)
         byte[] digest = mac.doFinal(data.getBytes())
         return digest
        } catch (InvalidKeyException e) {
        throw new RuntimeException("Invalid key exception while converting to HMac SHA256")
    }
   }

 

Testing

Providing the screenshot from the SAP CI Trace.

 

Conclusion:

That’s how we successfully authenticated with Bloomberg using JWT signed by ClientSecret using HMAC SHA256 implementing the Groovy Script in SAP CI.

Hope this blog is useful to you. let me know your feedback and comments.

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x