Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
vinayak_adkoli
Advisor
Advisor

Introduction:

Yes, you read it right (and you read it right here !). There is an out-of-the-box approach to achieving a single sign-on (SSO) experience for user flows between a corporate identity provider (that authenticates and authorizes the user) and a tenant of Cloud Integration runtime (loosely called CPI worker) fully within the BTP ecosystem.

Ok, let’s zoom out a bit and break this down.

If you are reading this blog post, you probably know already that SAP BTP Services can leverage the OpenID Connect federation-based mechanics of SAP Cloud Identity Service (read: SAP IAS) to connect users from corporate Identity Providers like Entra ID (formerly known as Azure AD), Okta, etc. to XSUAA BTP’s OAuth Authorization Server.
This is certainly not uncharted and I did a detailed blog post a few months ago demonstrating this setup.

However, this setup applied mostly to browser-based SaaS applications (read: Design Time applications with a web frontend), and that brings us to the objective of this blog -> Customers want to put together a similar setup for their client applications that interface with SAP Cloud Integration’s IFLows (in other words, the CPI runtime).
Certainly, this is not impossible to achieve and solution blueprints like these have existed in the past:

  • My colleague Francisco’s blog puts API Management in between a client and Cloud Integration and enforces API Management to perform an OAuthSAMLBearer handshake.
  • Microsoft champion Martin Raepple teaches how to set up SAML Trust between Entra ID Identity Provider and BTP to set up a user impersonation flow.

However, these approaches were often seen as cumbersome to set up / troubleshoot and certainly not for the faint-hearted!

Solution Summary:

An easier solution can be described in two phrases: 'OpenID Connect' and 'Authorization Code grant type'. If you are super-smart then you've figured it out already. You can stop reading this blog and hack this yourself.
I wish you a nice day ahead! If you are like me and need a bit more explanation, keep reading 🙂

Here is the solution blueprint that explains that handshake:

Picture1.png

SCENARIO: Flows that require end-user authentication from external Identity Providers can natively do so with OIDC and Authorization Code grant type

Step 0: Generate Service Instance / Service Key SAP Cloud Integration Runtime. Refer to this link. Instead of Client Credentials make sure to select  Authorization Code.

Step 1: Onboard the needed corporate identity providers in SAP IAS and set up the 'Application' that connects back to your SAP BTP Subaccount as a Trusted Identity Provider via OpenID Connect. Refer to my previous blog post for a detailed procedure. 

Step 2: Client (end-user)  initiates a connection to the required IFlow (or API artifact). This kicks off the 3-legged OAuth user login flow.

Step 3: As the user is not signed in, she is redirected to XSUAA's login endpoint, and upon login the IAS tenant's  OAuth server authorization endpoint at https://<IAS  tenant name>.accounts.ondemand.com/oauth2/authorize is invoked using the authorization code grant type. The details of the actual federation as part of the handshake have been omitted here for simplicity. But suffice it to say that the authorization code from the identity provider is made available to the IAS's callback endpoint and finally made available to XSUAA's authorize endpoint and exchanged for the actual access token. This access token will bear the user's scopes and role permissions needed to access the Cloud Integration's IFlow resource. 

Step 4: Once successfully authorized, on the receiver side of the IFlow, we will establish connections to 3 different types of backends for illustration purposes. a) S/4HANA Onpremise system over Cloud Connector and Principal Propagation b) SuccessFactors and c) S/4HANA Cloud with OAuth2 SAMLBearer Assertion security material. 

Putting it all together:

Let's get our hands dirty by putting together the sequence now. The prerequisites to follow along are listed below:

  • Administrator privileges in the BTP subaccount where the Integration Suite subscription exists.
  • An IAS Tenant (with Administrator privileges) that can be coupled (read: Trusted) with the said BTP Subaccount.
  • Privileges to create Applications (read: IDP configurations) in Entra ID (Azure AD) and/or Okta.
  • Postman Client.
  • Backend systems to which the frontend user principal can be propagated to. Either of S/4HANA OnPrem, S/4HANA Cloud, or SuccessFactors tenant.

Step 0: Create a Service Instance for the Authorization Code grant type

Create an instance of the 'Process Integration Runtime' Service (integration-flow service plan)  specifically with the authorization code grant type. You can copy the JSON snippet pasted below. Do not worry about the location of the redirect_uri. (When we get down to testing the flow, the browser will invoke the redirect_uri, but this has no consequence as the 'code' will be available for us to copy as a query parameter from the URL itself. When we test this from Postman the client, Postman does not invoke the URL. If you are curious to know, you can read about it here.) Also, make a note that we have specified refresh_token as part of the requested grant type. This will let us demonstrate the ability for clients to refresh the access token post-expiry. 

 

{
    "grant-types": [
        "refresh_token",
        "authorization_code"
    ],
    "redirect-uris": [
        "http://localhost"
    ],
    "roles": [
        "ESBMessaging.send"
    ]
}

 

With the service instance created, generate a service key (example block is pasted below). Grab the clientid, clientsecret, authorizationurl, tokenurl attributes. We will need these later.

Screenshot 2024-04-05 at 8.58.50 PM.png

 

Step 1: Configure OpenID Connect based Trusted Identity Provider of SAP IAS in your SAP BTP subaccount

This step is the heart-and-soul of our approach. We will couple an SAP IAS tenant with our BTP subaccount that has the subscription of our SAP Cloud Integration (SAP Integration Suite) tenant using OpenID Connect protocol and then onboard the desired external Identity Providers (I will demonstrate Entra ID and Okta) as corporate identity providers in the IAS administration console.
Since I've documented the steps in my previous blog, I will not repeat the exact steps here. Please refer to the following sections in the linked blog.

 

ObjectiveSteps to follow from the linked blog
Couple your BTP subaccount and your SAP IAS tenant.Steps 1-6
Configure applications (relying party) in Azure AD and Okta IDP based on OpenID Connect and SAP IAS as the callback URI.Steps 7 - 25
Configure application in Okta with SAML Trust to SAP IAS.Steps 26 - 33
Onboard the above Corporate Identity Provider configurations into SAP IAS.
Steps 34 - 46
configure IAS as the proxy Identity Provider and SAP BTP as the Service Provider.Steps 47 - 52

Nevertheless, here is a summary of the main steps involved in the setup.

1. The subaccount where the Integration Suite subscription exists has a 'Trusted connection' with the OpenID Connect protocol (not SAML) to the IAS tenant.

Screenshot 2024-04-06 at 9.54.43 PM.png

2. The IAS tenant has a 'Corporate Identity provider' connection to Azure AD (Entra ID) via a set of Application credentials and OpenID Connect protocol.

Screenshot 2024-04-06 at 9.38.55 PM.png

 

3. Notice the 'Application' settings on the Azure side. The redirect URI has been set to the IAS tenant's '../oath2/callback' segment

Screenshot 2024-04-06 at 9.36.29 PM.png

4. The IAS tenant has a 'Corporate Identity provider' connection to Okta IDP via a set of Application credentials and OpenID Connect protocol.

Screenshot 2024-04-06 at 9.39.59 PM.png

 

5. Notice the 'Application' settings on the Okta side. The redirect URI has been set to the IAS tenant's '../oath2/callback' segment.

Screenshot 2024-04-06 at 9.37.38 PM.png

6. We will not leverage this flow in our demonstration but note that it is very much possible to use SAML bindings between the Corporate Identity Provider and IAS. The federation works exactly as OIDC.

Screenshot 2024-04-06 at 10.45.14 PM.png

 

7. Next, we want to demonstrate a dynamic / Group assertion / Role Collection based user role/authorization determination. For that note that on the Azure side, we have a group called 'IntegrationDevelopers' that contains the users who must be authorized to call the IFlow / API on the Cloud Integration side. 

Screenshot 2024-04-06 at 9.46.09 PM.png

8. Notice how the 'groups' claim on the IAS side resolves to the value of the group from Azure.

Screenshot 2024-04-06 at 9.44.09 PM.png

9. Similarly, see that the target user has been assigned to the 'IntegrationSuiteDevelopers' Group in Okta.

Screenshot 2024-04-06 at 9.41.35 PM.png

10. Okta presents the user's 'Groups' claim to IAS that XSUAA will resolve in a later step. 

Screenshot 2024-04-06 at 9.44.47 PM.png

11. As a last configuration step, notice that there is a RoleCollection on the BTP side (with the 'MessagingSend' role assigned) mapped to the respective groups from the source identity providers.

Screenshot 2024-04-06 at 10.16.35 PM.png

 

Step 2 & 3: Initiate the client flow.

The easiest way to demonstrate a client flow is to do so in Postman which natively supports simulating an OAuth 2.0 3-legged Authorization Code grant flow. We can break down the segments of the 3-legged flow in a browser as well. I will demonstrate both of these user agents.

Summary of the steps about to be performed in this section

ObjectiveSteps
Use Postman to set up Authorization Code flow with Okta Identity Provider1-8
Use Postman to set up Authorization Code flow with Entra ID Identity Provider9
Usage of Refresh Tokens13-14
Use Browser to set up Authorization code flow with Identity Providers15-18

1. Within the 'Authorization' tab in Postman, set the 'Type' to 'OAuth 2.0' and the 'Grant type' to 'Authorization Code'.

Screenshot 2024-04-07 at 11.15.05 AM.png

2. Enter the values for the Callback URL, Auth URL, Access Token URL, Client ID, Client Secret from the values saved in the Step 0 block above.

Screenshot 2024-04-07 at 11.15.39 AM.png

3. Click on 'Get New Access Token'. Make sure to turn on the 'Console' tab at the bottom to keep track of requests and responses across the wire.

Screenshot 2024-04-07 at 11.16.06 AM.png

4. Postman will launch the Logon pop-up from BTP's Authorization Server. Notice that you are presented with a list of Identity Providers to log into as configured in BTP's Trust Management section. Select the one that corresponds to your IAS Tenant.
Pay attention to the GET requests in the Console tab. You will see that the request to the 'authorize' resource is being redirected to the login page.

Screenshot 2024-04-07 at 11.16.34 AM.png

5. The system will prompt you to present the user identifier, this will serve as an input to the 'Conditional Authentication' block set in the IAS tenant to resolve which corporate identity provider to redirect to, for the user logon challenge.

Screenshot 2024-04-07 at 11.16.57 AM.png

6. The system determines that the challenge should come from Okta IDP for my *.sap.com user name. Please refer to the 'Conditional Authentication' screenshot to get a summary of the determination process.
In the 'Console' section, make a note of how the callbacks are handled.

Conditional Authentication section in SAP IASConditional Authentication section in SAP IAS

 

Screenshot 2024-04-07 at 11.17.19 AM.png

7. Okta will authenticate the user and present back the 'authorization code' to IAS.

Screenshot 2024-04-07 at 11.17.23 AM.png

8. Finally the client will exchange the authorization code for the access token from the configured token endpoint.

Screenshot 2024-04-07 at 11.17.30 AM.png

9. Let us now perform steps nos. 3-8 again, but this time let us log in with our *.outlook.com user that gets authenticated and authorized from Entra ID (Azure AD).

Screenshot 2024-04-08 at 5.57.54 PM.png

Screenshot 2024-04-08 at 5.55.56 PM.png

10. Upon inspection, you will note that the access token issued by XSUAA has the 'ESBMessaging.send' scope as determined by the 'Groups' claim presented by the source IDP. You will remember that we created a mapping for this resolution in a previous step. Also, note that the system bears a refresh_token.

Screenshot 2024-04-07 at 11.17.51 AM.png

11. Further, if you inspect the respective JWTs issued by Okta and Entra ID, you will see that the tokens contain the claims that represent the Groups, RoleCollections, and User Identifier info.

Screenshot 2024-04-08 at 6.02.17 PM.png

Screenshot 2024-04-08 at 6.01.10 PM.png

12. Simply go ahead and 'Use Token' to load the token to make your request.

Screenshot 2024-04-07 at 11.18.01 AM.png

13. Using the refresh_token -> Notice that the token will expire after a set duration (based on the 'expiry' setting). As you can see in the screenshot below, Postman detects that the available token is expired. It gives an option to 'Refresh' the token. Click on this button.

Screenshot 2024-04-07 at 12.58.21 PM.png

14. Make a note in the Console tab that the client POSTs to the token endpoint with the available refresh_token and the refresh_token grant_type to get a fresh access token.

Screenshot 2024-04-07 at 12.59.15 PM.png

15. In the next screenshots, let us perform the same set of steps in a browser. We will need to frame the URL to the /oauth/authorize endpoint. The easiest way to do so would be to copy the URL from the Postman Console we referred to before. The URL is in the format :

https://<tenant-id>>/authentiation.<dc>.hana.ondemand.com/oauth/authorize?
response_type=code&client_...

Screenshot 2024-04-08 at 8.58.56 AM.png

16. Invoke the URL in a browser.

Screenshot 2024-04-08 at 9.24.05 AM.png

17. After the 'login' and 'authenticate' procedures, you will see that the browser is redirected to the redirect_uri location. You can copy the 'code' parameter from the URL. 

Screenshot 2024-04-08 at 8.59.57 AM.png

18. Go back to Postman and POST the Access Token endpoint with the grant_type set to authorization_code and the copied code and the redirect_uri. The server will respond with the access_token with the same set of attributes populated as demonstrated in Step 11.

Screenshot 2024-04-08 at 9.03.29 AM.png

 

Step 4: Integration Flow Reciever side propagation

Now that we have an access_token that can be presented to the Cloud Integration runtime (to a 'Sender Adapter'), let us put together a simple IFlow that can demonstrate the fact that the user's identity from the external identity provider can be propagated to 3 backend systems - a) S/4HANA Onpremse, b) SuccessFactors and c) S/4HANA Cloud via Principal Propagation and OAuth2SAMLBearer mechanisms respectively.

Here is a summary of the steps we intend to achieve:

ObjectiveSteps
Create a sample IFlow that demonstrates the user propagation sequence to 3 different types of backend systems.1-2
Invoke S4HANA Cloud backend 3 - 7
Invoke SAP SuccessFactors backend8 - 13
Invoke SAP S/4HANA Onpremise backend14 - 17

1. Let's start by putting together a simple IFlow to illustrate the user propagation flow. Since we are planning to invoke with 3 backends, the quickest way to demonstrate this would be to create a Router that has 3 branches. Each with a 'Request-Reply' step for the backend type, S/4HANA Cloud, SuccessFactors, and S/4HANA OnPremise respectively.

Screenshot 2024-04-09 at 5.04.01 PM.png

2. The logic we will follow is that the client passes a value in a custom header named 'target' that shall determine which of the routes is to be invoked.

Screenshot 2024-04-09 at 5.11.04 PM.png

3. In the property sheet of the HTTP Receiver for S/4HANA Cloud backend, notice that we've used a credential named 's4hanaCloudCredentials' with the OAuth2 SAML Bearer Assertion type.

Screenshot 2024-04-09 at 5.04.51 PM.png

4. I will not get into the details behind how the attributes of this Security Material have been formulated. Refer to parts of this blog post for details. The points worth mentioning here are that a) we are using the target system type SAP BTP (CF) and b) the 'userIdSource' attribute is annotated for 'email' & nameIdFormat is set to 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', thereby implying that the user identifier from our original JWT token negotiated with the corporate identity provider will serve as the user principal to be propagated.

Screenshot 2024-04-09 at 5.08.29 PM.png

5. Let us make a call to the IFlow URL with the access token set from step 8 described in the above section. Note that we've set the 'target' header attribute to 's4hanacloud'  so that the call gets executed in the first route. We get an HTTP 200 OK and the service document as the response and there you have it! We were able to successfully propagate the user from an external identity provider and execute a call in an S/4HANA backend with the user's context.

Screenshot 2024-04-09 at 5.11.42 PM.png

6. How do I prove my point that the user was indeed propagated? The next two screenshots do so. Note that on the S/4HANA side, I have a 'Business User' that bears my (that is propagated from Okta) emailID. Also, note that the HTTP Call is executed with this user context and NOT with a Communication User (technical user) attached to the Communication Arrangement.

Screenshot 2024-04-09 at 4.24.48 PM.png

7. Further to prove my point, I execute step no. 5, this time by presenting my *@outlook.com user (that comes from Entra ID), you see that the call fails and the error description calls out that the backend was not able to resolve the presented *.outlook.com user.

Screenshot 2024-04-09 at 5.13.21 PM.png

8. Let us now look at the 2nd route, the one that invokes a SuccessFactors URL. We extend the same 'OAuthSAMLBearer Assertion' type with a credential named 'SFSFUserPrincipal'. On the processing tab, you will see that I'm invoking a GET Query on the JobProfile resource.

Screenshot 2024-04-09 at 5.06.05 PM.png

Screenshot 2024-04-10 at 8.36.23 PM.png

9. In the details of the Security Material, note that we've set the attributes per SuccessFactors documentation. The User ID is set for principal propagation. Like before, we've used the same nameIdFormat as set in step 4 above, and don't forget to include the apiKey attribute as well.

Screenshot 2024-04-09 at 5.09.01 PM.png

10. Let us now invoke the IFlow, this time around with the header 'target' set to 'sfsf'. I get back a response from SuccessFactors with the JobProfile details.

Screenshot 2024-04-09 at 5.16.44 PM.png

11. Again, how do we prove that the call indeed was made in the signed-in user's context? There are many ways to establish this. A simple way I followed was to put a 'proxy' layer like API Management before the call hits the SuccessFactors backend and print out the 'Bearer token' from the 'Authorization' header.  Upon Base64 decoding the token, you will see that the token bears a 'sfPrinciple' attribute with the employee ID identifier. 

Screenshot 2024-04-09 at 2.54.16 PM.png

12. Look up the employee profile of the user in question in your SuccessFactors tenant and you can verify the matching employee ID and the corresponding email address.

Screenshot 2024-04-09 at 2.53.41 PM.png

13. Negative testing -> If I perform the call again, this time by signing in with the email address from Entra ID you should see a 401 unauthorized exception stating that the propagated user wasn't resolved. 

Screenshot 2024-04-09 at 5.15.20 PM.png

14. Finally, we are down to the last segment of our testing. A connection to S/4HANA On-premise. I've configured an SAP Cloud Connector and an X.509 certificate signing procedure (that is beyond the scope of this demonstration) and have dialed 'Principal Propagation' for the authentication type. 

Screenshot 2024-04-09 at 5.06.26 PM.png

15. Invoking the client this time around with the 'target' header set to 's4hanaonpremise'. I get back a response from the server with my service document for the invoked GWSAMPLE_BASIC OData service.

Screenshot 2024-04-10 at 9.42.33 PM.png

16. As a quick verification step, let us go to the 'Monitor' section in the Cloud Connector and within the 'Most Recent Requests' tab, you can see a record for the 'User' that was propagated.

Screenshot 2024-04-09 at 4.54.26 PM.png

17. Open the LJSTrace log file and you can hunt down a log entry that corresponds to the user subject that was propagated via the short-lived x.509 certificate.

Screenshot 2024-04-09 at 5.02.03 PM.png

Phew!

Summary:

It is beyond doubt that 'client credentials' and 'x.509 certificate' are the two most prominent and widely popular ways to authenticate to an Integration Flow / API artifact in SAP Integration Suite, but should you have a requirement to authenticate and authorize with the client user's identity from a corporate Identity Provider, OpenID Connect support from SAP Cloud Identity Service along with the Authorization Code grant type in SAP Integration Suite provide an excellent and out-of-box approach to get your job done.

Cheers, and more power to the  SAP Integration Suite  Community!

3 Comments