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:
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
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:
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.
To access Microsoft Azure portal, we go to
https://portal.azure.com
and login with an admin user (can be a trial admin).
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.
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.
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.
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”.
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.
We go back to the overview screen of our App Registration.
On the top menu, we press on “Endpoints”.
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:
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
Below configurations enables AEM to validate the incoming JWT token when the iFlow connects to AEM.
These steps are required:
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.
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.
Finally, we can press “Apply” in the right upper corner.
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”.
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".
Note:
If the username is wrong we get an error "403 Client Username Is Shutdown".
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
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”.
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
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
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
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
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
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.
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.
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”.
That’s it for iFlow creation.
BTW, saving is always a good idea.
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.
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)
Please refer to chapter 5 of the previous tutorial:
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"
}
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:
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".
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
Below screenshot shows my modified iFlow:
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;
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
26 | |
24 | |
21 | |
13 | |
11 | |
9 | |
9 | |
9 | |
8 | |
8 |