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: 
CarlosRoggan
Product and Topic Expert
Product and Topic Expert
0 Kudos
790

SAP Cloud Integration (aka CPI) offers an “Advanced Event Mesh Adapter” which is well integrated with the “Advanced Event Mesh” broker.
This article shows how to set up a scenario where we send a message from iFlow via “Advanced Event Mesh Adapter” to SAP Integration Suite, Advanced Event Mesh (AEM) with OAuth Authentication.
The OAuth flow “Authorization Code” is used.
The user is stored in Microsoft Entra ID, in Azure cloud.
There’s no IAS-proxy in the setup.
See Links section for other OAuth scenarios

Technologies covered in this blog post:

  • SAP Cloud Integration (CPI)
  • SAP Integration Suite, Advanced Event Mesh (AEM)
  • Microsoft Entra ID, Microsoft Azure
  • OAuth 2.0

Content

0. Introduction
1. Entra ID: Configurations for User and OAuth
2. AEM: Configurations for OAuth and User
3. CPI: Configurations for Security and iFlow
4. Run Scenario
5. Troubleshooting

Prerequisites

  • To follow this tutorial, access to  SAP Advanced Event Mesh is required.
  • Access to Microsoft Azure with admin permissions
  • Access to CPI tenant with permissions to create and deploy iFlow 
  • Access to the previous tutorials of this series

0. Introduction

Please refer to one of the previous tutorials for an introduction into the scenario.
Instead of repeating, we focus on the specialties of Microsoft Entra in the scenario.
Below diagram shows our setup:

diagram1.jpg

We can see that a user stored in Entra ID is used for the authorization code flow.
The OAuth client created in Entra ID (App registration) is configured in CPI and in AEM.

1. Entra ID: Configurations for User and OAuth

To access Microsoft Azure portal, we go to
https://portal.azure.com
and login with an admin user (can be a trial admin).

1.1. Create user

For this tutorial we create a new test user.
This chapter can be skipped if a suitable user is available.

Note:
In this scenario, where we’re sending messages, we don’t need a user group.

To create a user, we go to portal -> Entra ID -> Manage -> Users -> New user
In my example, the new user has my favorite name "Joe Cool".
Any other name should be fine as well.
During creation, we have to copy the generated password, as it needs to be changed afterwards.

entra_createuser.jpg

After creation we’re taken to the Users list screen where we might need to press “Refresh” to see the new user.
We click on it to go to the details page.

entra_userDetails.jpg

We take a note of the principal name and the object ID.

Change initial password

With a different browser, we login at https://microsoft365.com and enter our new user / initial password.
We change the password.
We take a note of it.
We can skip the "Authenticator" step for test user.
We log off again.

1.2. Create OAuth Client

In the OAuth model, a web application is a "client" that acts on behalf of a user, without getting in touch with the user's password. That's taken care of by the "Authorization Server", in our scenario it is provided by Entra ID. In order to communicate with the Authorization Server, the client needs credentials. Therefore, it must be "registered" at the Authorization Server.
In Entra ID, creating an OAuth client is called: create a new "App Registration".

1.2.1. Create App Registration

We go to Azure Portal -> "Entra ID" -> "Manage" -> "App registrations" -> “New registration”.
We enter the following data:

Name:
Enter any name of your choice.
In my example: "AppForAEM".

Account Type:
Single Tenant (default).

Redirect:
Web
URL:
The redirect url points to the endpoint that is provided by the CPI system exactly for the purpose of receiving redirects from Authorization Servers.
Adapt below URL to match your system:

 

 

 

 

 

 

 

https://subdomain.integrationsuite-it-abc01.cfapps.eu12.hana.ondemand.com/itspaces/odata/api/v1/OAuthTokenFromCode

 

 

 

 

 

 

 

Note: In chapter 3.1. we’ll learn the safe way to retrieve the URL

Press “Register”.
We’re taken to the overview page where we can view the details.
We take a note of the application ID, which is the OAuth client ID-.
In my example:
Client ID: 90212675-6ba3-4465

1.2.2. Configure App Registration: Define Credentials

We cannot use the OAuth client without credentials.
So we create the client secret now.
In the screen of our created App registration, we click on "Manage" -> "Certificates & secrets " in the navigation pane.

Then click on "New client secret".
We enter any description and press “Add”.

entra_appSecret.jpg

Afterwards we should not forget to take a note of the secret, as it won’t be shown anymore.
Note:
In case you lost your secret, you can always create and use a new one.

1.3. Endpoints

We go back to the overview screen of our App Registration.
On the top menu, we press on “Endpoints”.

entra_appEndpoints.jpg

We take a note of the following:

OAuth 2.0 authorization endpoint (v2)
E.g.

 

 

 

 

 

 

https://login.microsoftonline.com/111/oauth2/v2.0/authorize 

 

 

 

 

 

 

OAuth 2.0 token endpoint (v2)
E.g.

 

 

 

 

 

 

https://login.microsoftonline.com/111/oauth2/v2.0/token 

 

 

 

 

 

 

OpenID Connect metadata
E.g.

 

 

 

 

 

 

https://login.microsoftonline.com/111/v2.0/.well-known/openid-configuration 

 

 

 

 

 

 

Recap

The configuration required in Microsoft Entra ID comprise:

  • User and unique user data (principal name and/or object ID).
    Change PWD.
  • Create application,
    add redirect URL
    create secret

Our scratchpad contains:
User principal name: joe.cool@haugmail.onmicrosoft.com 
Object ID (of user): bc6588e2
Client ID: 90212675
Client secret: ZCu8Q
OAuth 2.0 authorization endpoint (v2): ...microsoftonline.com/11/oauth2/v2.0/authorize 
OAuth 2.0 token endpoint (v2): ...microsoftonline.com/11/oauth2/v2.0/token 
OpenID Connect metadata: ...microsoftonline.com/11/v2.0/.well-known/openid-configuration 

2. AEM: Configurations for OAuth and User

Below configurations enables AEM to validate the incoming JWT token when the iFlow connects to AEM.
These steps are required:

  • Enable OAuth (only once)
  • Create OAuth Profile (for each OAuth client)
  • Set default profile (in case of multiple profiles)
  • create username

2.1. Optional: Enable OAuth Authentication

We login to AEM, click on Cluster Manager, choose our broker and click on the Manage tab.
In the section Event Broker Service Settings we click on Authentication.
We enable OAuth Provider Authentication and Save.

This step needs to be executed only once.

2.2. Create OAuth Profile

In Cluster Manager, we choose our broker and click on "Open Broker Manager".
There, we click on Messaging -> Access Control on the left navigation pane.
Below "Client Authentication" tab, we go to the sub-tab "OAuth Profiles" and "Create" a mew profile.

Settings

name
Any name of your choice, in my example "aucoEntra".
After pressing "Create" we can start to configure this new profile.
Note:
One profile corresponds to one OAuth client.
In our case, the OAuth client is an “App Registration” in Entra ID, but it could be as well an XSUAA service instance or an "Application" in IAS, etc

Enabled
yes

OAuth Client ID
Here we enter the clientid which we stored in scratchpad.
In my example, I enter 90212675...

Change OAuth Client Secret
We should not forget to click here, although it doesn’t seem to be a field. 
Here we enter the clientsecret which we stored in scratchpad.
In my example, I enter ZCu8Q...

OAuth Role
This is a confusing setting.
Anyways, in case of OAuth flow, we choose Resource Server.
It makes sense, because in the OAuth diagram we assigned the role of Resource Server to AEM.
With other words, this is the setting for the “client-credentials” scenario.

Issuer Identifier
In my example, I enter: "entraForAem"
Note: this works if there’s only one profile, otherwise it wouldn’t be found.
In that case, make sure to copy the issuer from the JWT token, as shown in chapter below.

Discovery Endpoint
Here we enter the metadata endpoint which we stored in scratchpad.
In my example:
...microsoftonline.com/11/v2.0/.well-known/openid-configuration 

JWKS Endpoint
It is not required in our scenario

Introspection Endpoint
Not available.

Authorization Groups Claim Name
We leave this empty.

Username Claim Name
In our tutorial we use: "unique_name"

Parse Access Token
This is an important setting, we have to set it to enabled.

Validate Access Token Audience
We set to disabled.

Validate Access Token Issuer
We set to disabled.

Validate Access Token Scope 
We set to disabled.

Validate Access Token Type
We set to disabled.

aemProfile_simple.jpg

Finally, we can press “Apply” in the right upper corner.

2.3. Configure Default Profile

There's a setting in the "Client Authentication" Tab which allows to define which of the existing profiles should be used as default.
Within "Broker Manager" we go to
"Access Control" -> "Client Authentication" -> "Settings"
and press "Edit"
We make sure that "OAuth Authentication" is enabled.
Now we select our OAuth Profile which we created above as Default Profile Name from the drop-down.
Finally, we press “Apply”.

2.4. Create Username

This is an important section.
AEM requires a user context when sending messages.
In case of “Authorization Code” flow, we’re dealing with a user-centric JWT token.
As such, the real user (although probably a technical user) has to be created in AEM.
Not just the client ID, as we did in client-credentials scenario (previous blog posts based on XSUAA and IAS)

Now the first interesting question is: who is the user?
The answer:
The user who is used for doing the login in chapter 3.1. (Security Artifact)
In my example: the user “Joe Cool”

The second question, even more interesting: what username to create?
In the OAuth Profile above, we defined which claim does carry the required “username”.
In our example, we’ve chosen to use the "unique_name" claim.
And what is contained in the "unique_name" claim?
I've verified it by introspecting the JWT token (see chapter below):
it is the user principal name which we've stored on our scratchpad.
In my example: joe.cool@haugmail.onmicrosoft.com 

So now we go to Broker Manager -> "Messaging" -> "Access Control" -> "Client Usernames"
Create new username "joe.cool@haugmail.onmicrosoft.com".
We "Enable" the user and press "Apply".

aem_createUser.jpg

Note:
If the username is wrong we get an error "403 Client Username Is Shutdown".

2.5. Retrieve Connection details

To view the data that we need to enter in the next chapter, we go to
Cluster Manager -> Select Broker -> Connect
We open any language and choose smf-Protocol -> Get Started
We need the host and the VPN name.
In my example:
Host URI: "tcps://mr-connection-111.messaging.solace.cloud:55443"
Message VPN: "demovpn"

Optional: View Port Config

One optional last check, to be on the safe side:
Cluster Manager -> Broker -> Manage -> Advanced Options -> Port Configuration -> Expand Public Endpoint -> click “Edit”
Expand “Solace Messaging”
Make sure that the “Secured SMF Host” is enabled and the port number matches the above: 55443

port.jpg

 

2.6. Create Queue

If not yet available, we create a queue to which we’ll send events from iFlow.
To do so, we go to
Broker Manager -> Messaging -> Queues
and create a queue with name “testqueue”.

Recap

At AEM, we’ve configured OAuth via these steps:

Broker Service
- optional: enable OAuth Authentication
Broker Manager
- create OAuth Profile
- optional: set default OAuth Profile
- create username 

3. CPI: Configurations for Security and iFlow

At this point, the AEM broker is ready to receive JWT tokens issued for the OAuth client created in chapter 1.
Now we head over to Cloud Integration dashboard where 2 tasks are waiting for us:
- create a Security Artifact for handling the JWT token
- create an iFlow with AEM adapter for sending messages

3.1. Create Security Artifact

We create a security artifact for securely storing the credentials which we received in chapter 1.2.2.
CPI provides a special artifact type for OAuth 2 which is able to automatically fetch a JWT token with “Authorization Code” flow.
We go to Monitor -> Security Material
and click on Create -> OAuth 2 Authorization Code
In the dialog, we enter the following values:

Name
Any name of our choice.
Note that this name will be used in the iFlow.
In my example, I’m entering "aucoEntra".

Provider
Microsoft 365

Authorization URL
This is the endpoint provided by the Authorization Server, to be used for requesting an authorization code and doing the redirect.
We enter the url which we stored in our scratchpad.
The full URL in my example:
https://login.microsoftonline.com/111/oauth2/v2.0/authorize  

Token Service URL
This is the endpoint provided by the Authorization Server, to be used for requesting a JWT token.
We enter the value of the token endpoint from our scratchpad
The full URL in my example:
https://login.microsoftonline.com/111/oauth2/v2.0/token  

Redirect URL
This is the endpoint provided by CPI, which is used as redirect endpoint for the Authorization Code flow.
The implementation will use the received code for fetching a JWT token.
We get this information, because we have to configure the Authorization Server (Entra ID) with it.
We've done it already in chapter 1.2.3.
Now we can verify if it was correct.

Client ID
The client ID from our scratchpad
In my example, I enter 90212675...

Client Secret
The client secret from our scratchpad
In my example, I enter ZCu8Q...

Send As
We choose “Body Parameter”.

User Name
This is optional, we can enter our user "joe.cool@haugmail.onmicrosoft.com" 
It will be prefilled in the dialog.

Scope
Entra ID requires a scope, to be composed in a specific way:
<clientid>/.default
In my example: 90212675/.default

cpi_security.jpg

Note that the credentials (clientid/secret) have to be the same as we’ve configured in the AEM profile.
Finally, we press "Deploy".

Do Login for Authorization Code

One more step is required after deploy:
We have to perform the "Authorization Code" flow, as it requires interactive user login.

If Âzure is open in same browser but different tab, make sure to log out.
Otherwise this (admin) user will be used for the CPI artifact.
But we don't want it, we want the user "JoeCool" to do the login.
After pressing on “Authorize” in CPI Security Material screen, the login dialog of Microsoft must be displayed.
Here we login with the user we created in chapter 1.1.
In my example: joe.cool@haugmail.onmicrosoft.com

cpi_security2.jpg

We enter Joe’s password.
Afterwards we get a popup asking for multi factor authentication with the “Authenticator” app.
We can skip this for now.
Now we get a relevant popup: the consent

cpi_security3.jpg

This is expected for the OAuth flow.
The OAuth client is displayed in the popup, it wants to access resources on behalf of the user (Joe).
Hence, Joe has to confirm that he is ok with the required permission (read profile).
Finally we get a success response as xml.
We close the browser tab.
With this, we’ve enabled CPI to fetch a JWT token for us.
To be more precise: "Authorization Code" flow is done once, afterwards, the "Refresh Token" is used to refresh the JWT token without interactive user login. 

3.2. Create iFlow

Now we can go ahead and create the iFlow.
In this tutorial the iFlow is as minimalistic as possible, as we only want to show the usage of the AEM adapter.

iFlow.jpg

We create a simple iFlow which does really nothing but sending messages to the Event Broker.
We define a hard-coded dummy message text.
We just want to make sure that the OAuth authentication works fine.
Let's quickly go through the steps:

Start Event
The iFlow is triggered once after deploy, by a "Timer" start event.

Content Modifier
In the "Message Body" tab we enter any dummy message text of our choice.

AEM Adapter: Connection tab
"Host":
The value for "host" is copied from AEM and pasted as is, no need to cut or append anything.
We've copied that value in chapter 2.5
In my example: "tcps://mr-connection-abc.messaging.solace.cloud:55443"

"Message VPN":
Same as above, the value of chapter 2.5.
In my example: "demovpn"

"Username":
We can enter our “JoeCool” user.
In our case, the username is not required, as it is contained in the JWT token and AEM will read it from there.
The username will be printed e.g. in the AEM log (see Troubleshooting section)

"Authentication Type":
Select “OAuth2”.

"OAuth2 Credential Type":
Choose "OAuth2 Authorization Code".

"OAuth2 Client Credentials Credential Name":
Here we enter the name of the security artifact created in chapter 3.1.
In my example: "aucoEntra".

AEM Adapter: Processing tab
Here we configure our queue.

"Endpoint Type":
We select "Queue".

"Destination Name":
Here we enter the name of the desired target queue.
In my example: “testqueue”.

cpi_adapter.jpg

That’s it for iFlow creation.
BTW, saving is always a good idea.

4. Run Scenario

Now we can deploy the iFlow and check the result:

CPI : The log at “Monitor Message Processing” should show success message
AEM: In “Broker Manager” we can see the number of “Messages Queued” have increased.

5. Optional: Alternative Configurations

Let's briefly mention alternative configurations.

Values for username claim name:
sub
The value is a GUID which we have to copy from the decoded JWT token
(see chapter below)

oid
This is the object id which we can copy from user details in Entra ID.

upn
This is the user principal name, copy from user details.

unique_name
As used in our tutorial, the user principal name, copy from user details.

Note that the username must be created accordingly

OAuth Profile with issuer and validation

Below screenshot shows how issuer identifier can look like
(I copied it from JWT token)

aemProfile_2.jpg

6. Optional: Configurations via REST Calls

Please refer to chapter 5 of the previous tutorial:

https://community.sap.com/t5/technology-blogs-by-sap/sap-cloud-integration-advanced-event-mesh-adapt...

7. Troubleshooting

See previous tutorials for troubleshooting hints and how to view logs.
Check out how to introspect the JWT token received from Microsoft Entra.

Problem:
AAD doesn’t have introspection endpoint, as such we configure only discovery endpoint.
AEM fails with error:
<local3.warning> SYSTEM: SYSTEM_CLIENT_CONNECT_AUTH_FAIL: - - Message VPN (demovpn) Sol Client username joe@coolmail.com authentication failed from 3.127.200.72:40328 using scheme OAuth - Unauthorized: Introspection is required but no introspection endpoint is configured
Solution:
Enable “Parse Access Token”
As a consequence, the introspection endpoint is not required anymore, the EntraID-JWT can be parsed (remember that IAS token cannot be parsed)

Sample Content of JWT token for Authorization Code with Entra

 

 

{
    "name":"Joe Cool",
    "given_name":"Joe",
    "family_name":"Cool",
    "unique_name":"joe.cool@haugmail.onmicrosoft.com",
    "upn":"joe.cool@haugmail.onmicrosoft.com",
    "oid":"bc6588e2-ac71",
    "sub":"c9wXeFDYapU6D",
    "aud":"90212675-6ba3",
    "iss":"https://sts.windows.net/7d9a2f86-f05c/",
    "scp":"User.Read",
    "aio":"ATQAy/8XAAAAFrW/lS8G2qZUheMe1B7MVNpyD",
    "amr":["pwd"],
    "appid":"90212675-6ba3",
    "appidacr":"1",
    "ipaddr":"193",
    "rh":"0.AXoAhi.",
    "tid":"7d9a2f86-f05c",
    "uti":"zeu9BhZqKE",
    "iat":1725001567,
    "nbf":1725001567,
    "exp":1725006796,
    "acr":"1",
    "ver":"1.0"
}

 

 

Summary

In this blog post we've learned how to use OAuth authentication with "Authorization Code", for sending messages from iFlow via AEM adapter.
These configuration steps are required at AEM:

  • AEM Broker Service: enable OAuth Authentication
  • AEM Broker Manager: create OAuth Profile
  • AEM Broker Manager: define default OAuth Profile
  • AEM Broker Manager: create username

It is important to know which name has to be created as username.
This name is taken from the value of the JWT-token-claim, that is configured in the OAuth Profile (AEM).
The default is the content of the sub claim.

And we've learned how to configure the AEM adapter for an iFlow receiver channel:
CPI Monitoring: Create security artifact for "Authorization Code"
CPI iFlow AEM adapter: use the security artifact for OAuth2 authentication.
CPI iFlow AEM adapter: Connection details are copied from "Connection" tab in AEM.

In this blog post we've used Microsoft Entra ID as Authorization Server.
We've focused on the OAuth flow "Authorization Code".

Links

OAuth spec https://datatracker.ietf.org/doc/html/rfc6749
AEM docu https://help.pubsub.em.services.cloud.sap/Cloud/cloud-lp.htm
Microsoft Entra docu landing page

Blog: AEM Adapter with client credentials with IAS
Blog: AEM Adapter with client credentials with XSUAA
Blog: AEM Adapter with client credentials with Entra ID
Blog: AEM Adapter with authorization code with XSUAA
Blog: AEM Adapter with authorization code with IAS
Blog: AEM Adapter with authorization code with Entra ID: this blog 
Blog: AEM Adapter with client certificate
Blog: Troubleshooting AEM

Appendix 1: Debug JWT token

Below screenshot shows my modified iFlow:

cpi_iflow_debug.jpg

 And this is the content of the Groovy script:
(Make sure to adapt the name of the security artifact)

 

 

import com.sap.gateway.ip.core.customdev.util.Message;
import com.sap.it.api.securestore.SecureStoreService;
import com.sap.it.api.securestore.AccessTokenAndUser;
import com.sap.it.api.securestore.exception.SecureStoreException;
import com.sap.it.api.ITApiFactory;


def Message processData(Message message) {
   def messageLog = messageLogFactory.getMessageLog(message);

   SecureStoreService secureStoreService = ITApiFactory
       .getService(SecureStoreService.class, null);
   AccessTokenAndUser accessTokenAndUser = secureStoreService
       .getAccesTokenForOauth2AuthorizationCodeCredential("aucoEntra"); 
    
   String token = accessTokenAndUser.getAccessToken();
   messageLog.addAttachmentAsString("JWT encoded", token, "text/plain");

   String[] parts = token.split("\\.") 
   byte[] tokenDecoded = Base64.getDecoder().decode(parts[1])
   messageLog.addAttachmentAsString(
        "JWT decoded", new String(tokenDecoded), "text/plain");
    
    return message;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1 Comment