Skip to Content
Author's profile photo Eng Swee Yeoh

HCI: Developing custom OAuth 2.0 authentication in iFlows

Introduction

OAuth 2.0 is becoming a common authentication method to access REST-based services (i.e. Concur, Google, SFDC). Unfortunately, different organizations might have different implementations of OAuth 2.0 and thus there is lack of a standard approach to it. According to the blog Authenticating from HANA Cloud Integration, HCI currently only supports the Client Credentials Grant Type for OAuth 2.0.

Unlike PI, fortunately HCI has a flexible pipeline processing based on Apache Camel and this allows for easy inclusion of intermediate request-reply calls before the message reaches the final target.

In this blog, I will share how we can take advantage of HCI’s flexible iFlow model to design a solution using custom OAuth 2.0 authentication that has yet to be supported by HCI natively. For the example, I will implement Concur’s OAuth 2.0 Native Authorization Flow to retrieve an access token prior to accessing Concur’s REST API. This is analogous to Option 3 of the following article detailing the support for Concur’s OAuth 2.0 in PI’s REST adapter.

PI REST Adapter – Connect to Concur

Component Details

As HCI is a cloud solution with automatic rolling updates, these steps are valid for the following versions and may change in future updates.

Below are component versions of the tenant and Eclipse plugins.

HCI Tenant Version: 2.8.5

Eclipse Plugin Versions: Adapter 2.11.1, Designer 2.11.1, Operations 2.10.0

iFlow Design

Below is the design of the iFlow for this example. For simplicity sake, it uses a start timer to trigger the flow once it is deployed. The target recipient is an HTTP server that logs the message posted to it.

/wp-content/uploads/2015/12/oauth_iflow_854235.png

Following is an overview of the various sections involved in the flow, which will be elaborated further.

  • Step 1 – Retrieve the user credentials and execute call to Concur token endpoint to retrieve the token
  • Step 2 – Extract the access token value from response of previous call and formulate the HTTP header for authentication using OAuth
  • Step 3 – Execute call to Concur REST API
  • Step 4 – Send REST API response to HTTP target

Design & Configuration

In this section, I will elaborate further on the design and configuration of each step.

Step 1

In order to retrieve an OAuth 2.0 access token from Concur, we first need to perform an HTTP GET call to its token endpoint. This token endpoint expects basic authentication which consists of the Base64 encoded value of the credential (userID:password) in the HTTP header. Additionally, the consumer key needs to be also passed in the HTTP header.

In order to achieve this, we first make use of the User Credentials artifact to securely store and deploy the user ID and password. For more details on that, refer to the following blog on how to configure and deploy the artifact. For this example, I have deployed the credentials under the artifact name ConcurLogin.

Building your first iFlow – Part 4: Configuring your credentials

Within the iFlow, this credential will be retrieved using a Groovy script by utilizing the SecureStoreService API.

/wp-content/uploads/2015/12/script1_854267.png

Below is the logic for the Groovy script. Basically it retrieves the user credential from artifact ConcurLogin. It then encodes the login credentials in Base64. Finally it sets the two required HTTP header fields (note that I have deliberately modified the actual value of the consumer key).


import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import javax.xml.bind.DatatypeConverter;
import com.sap.it.api.ITApiFactory;
import com.sap.it.api.securestore.SecureStoreService;
import com.sap.it.api.securestore.UserCredential;
def Message processData(Message message) {
  def service = ITApiFactory.getApi(SecureStoreService.class, null);
  def credential = service.getUserCredential("ConcurLogin");
  if (credential == null){
    throw new IllegalStateException("No credential found for alias 'ConcurLogin'");
  }
  String user = credential.getUsername();
  String password = new String(credential.getPassword());
  def credentials = user + ":" + password;
  def byteContent = credentials.getBytes("UTF-8");
  // Construct the login authorization in Base64
  def auth = DatatypeConverter.printBase64Binary(byteContent);
  message.setHeader("Authorization", "Basic " + auth);
  message.setHeader("X-ConsumerKey", "xxxx");
  return message;
}





Subsequently, the message is processed by a Request-Reply step that calls the token endpoint using the following channel configuration.

/wp-content/uploads/2015/12/token_channel_854276.png

Step 2

After the call to the token endpoint, the token is provided in an XML response as shown below.

/wp-content/uploads/2015/12/token_854277.png

We will then use a Content Modifier step to extract the token value via XPath and store it in a property.

/wp-content/uploads/2015/12/extract_854278.png

To access Concur’s REST API, it requires the OAuth token to be specified in the HTTP header as shown below:-

Authorization: OAuth <token_value>

Once we have the token value, it will be used in the following Groovy script logic to set the HTTP header.


import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message) {
  // Get the OAuth token value from the properties
  def map = message.getProperties();
  def token = map.get("token");
  // Remove the Consumer key from previous header
  map = message.getHeaders();
  map.remove("X-ConsumerKey");
  // Set the OAuth authorization credentials
  message.setHeader("Authorization", "OAuth " + token);
  return message;
}



Step 3

Once the OAuth token has been set in the HTTP header, the subsequent call to Concur’s REST API is configured as an HTTP receiver channel. In the example below, I configure the channel to use Concur’s Extract API to retrieve an extract file.

/wp-content/uploads/2015/12/restchannel_854288.png

Step 4

Finally, the response of the REST API call is sent to a target HTTP logging system. For the example, I have used the tool described in the following blow.

Testing: Test Tools…Part 1 *HTTP *

Testing Results

Once the iFlow has been completed and deployed, the interface will be triggered and the outcome can be seen on the POST Test Server log. As shown below, we were able to retrieve the extract file using Concur’s Extract API utilizing a custom OAuth 2.0 authentication.

/wp-content/uploads/2015/12/output_854290.png

Conclusion

As shown above, HCI’s flexible pipeline allows us to built quite complex iFlows. Together with custom Groovy scripts, it allows for a lot of possibility to design a customized solution. In this example, I have shown how it is utilized to built a custom OAuth 2.0 authentication that has not been supported by HCI natively. These days, more and more services are using two-step approaches involving tokens and session IDs, and as such having such a flexible pipeline comes in very handy to tackle those integration requirements.

Assigned Tags

      16 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Lavanya Musuvadhi Mothilal
      Lavanya Musuvadhi Mothilal

      Hi Eng Swee,

      1. You have used Basic authentication in step1 but in the receiver channel, the authentication is set to "None"

      2. Similarly, you used OAuth authentication in Step 3 but the authentication is set to "None" in the receiver channel

      How does it work in spite of setting the authentication to None ?

      Thanks,

      Lavanya

      Author's profile photo Former Member
      Former Member

      Hello,

      Basic and O auth login was achieved in Groovy script. And Plain HTTP adapter used at receiver side.

      reg, avi

      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh
      Blog Post Author

      Hi Lavanya

      The standard authentication function in the receiver channels are not sufficient to achieve login for both steps. Therefore authentication for both channels are set to None, and actually authentication is achieved by setting the required HTTP headers using Groovy script.

      Regards

      Eng Swee

      Author's profile photo Karan K
      Karan K

      Hello Eng,

       

      I have raised one new question on below URL, i am trying to integrate Linkedin using HTTP OAuth2. It will be helpful if you assist on the same.

      URL : https://answers.sap.com/questions/719860/linkedin-integration-with-cpi-using-http-oauth2.html

      I refered your blog but still have some queries.

      Kindly check and revert.

      Thanks & Regards,

      Karan K

       

      Author's profile photo Former Member
      Former Member

      Hello,

      With first request to fetch / refresh token from Concur i am getting below error.I followed same steps mentioned above. Could you please help me here.

      Error               = javax.net.ssl.SSLHandshakeException: General SSLEngine problem, cause: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

                                            Sent To URI         = direct://ConcurtoSFTP_TimerEventDefinition_1

      Rgds,

      -Amol

      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh
      Blog Post Author

      Hi Amol

      You need to add Concur's Root CA cert to the system.jks keystore in your tenant. Refer following blog:-

      HCI: Testing Outbound Connections from HCI

      Regards

      Eng Swee

      Author's profile photo Bhavesh Kantilal
      Bhavesh Kantilal

      Hello Eng Swee,

      Great Blog! I am surprised you dont have a fan following on SCN, will happen soon I am sure 🙂

      Regards,

      Bhavesh

      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh
      Blog Post Author

      "Fan following" - where do I sign up to get one? 😛

      Author's profile photo Amber Badam
      Amber Badam

      very informative . Thanks for Sharing.

      Author's profile photo Alexey Dmitriev
      Alexey Dmitriev

      Hi Eng Swee Yeoh,

      does anything changed since 2015 in regards to Oauth 2.0 in hci, or still need this iflow development?

      Author's profile photo Former Member
      Former Member

      Hi Eng Swee Yeoh,

       

      Nicely explained. Thank you for sharing.

      Well, I have similar question as Alexey's above. Has anything changed in 2017 regarding HCI supporting Oauth 2.0?

       

      Best Regards,

      Harsh

       

      Author's profile photo Alberto Delgado
      Alberto Delgado

      I´m still waiting for this to be answered as well. Any news on this topic?

      Author's profile photo Beverely Parks
      Beverely Parks

      Hi Eng Swee Yeoh,

      First, thank you for this blog as it has been very helpful.  I'm hoping that you can help me find a solution to a issue that I'm encountering.   I am needing to perform a token request in JSON format.  Currently, I am using a Content Modifier to hard code the client_id and client_secret into the XML body and then I am using the XML to JSON Converter.  My current road block is that our client secret contains the some characters <n/ and the remaining characters of the password.  The XML to JSON Converter is giving me the error (of course)      Error               = javax.xml.stream.XMLStreamException: ParseError at [row,col]:[4,26]
      Message: Element type "n" must be followed by either attribute specifications, ">" or "/>".

      Any idea how to get around this other than requesting a new password and ensuring that it doesn't contain any < or >?

      Thank you!!!

       

      Author's profile photo Julius Cesnakauskas
      Julius Cesnakauskas

      Just came across this blog post. It's an asset I bookmarked in my library:) Thanks for sharing!

      Author's profile photo Vinithra Iyangar
      Vinithra Iyangar

      Hello ,

       

      I came accross this blog because of a requirement i am working on. I am trying to connect sharepoint online. However it requires an additional parameter "resource" to be passed in the body while we retrieve access token. Unfortunately i was not able to find an option in the salesforce open connector or the standard odata v2 http adapter to pass the resource parameter. while the 2 step process works i would prefer if we can use the standard tools provided by SAP. any inputs how can an additional parameter be passed in odata v2 adapter (security) ?

      Thanks,

      Author's profile photo Jovita Coutinho
      Jovita Coutinho

      Hi Eng Swee,

       

      Nice Blog !!!

      Is there any way to have a setup of 'client_credential' grant type in SFDC.

      I know my query is related to SFDC system alone, but i saw a Blog that explains CPI integration with SFDC with Client Credentials grant type, let me know if you have any idea or if you have any blogs.

       

      Thanks,

      Jovita