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
2,290

SAP Integration Suite Advanced Event Mesh (aka AEM) offers the Broker Manager for managing queues etc of an Event Broker Service. To access this tool, Basic Authentication is used along with Pre-Authentication. This blog post explains how to configure OAuth Authentication, for accessing the Broker Manager, with users maintained in SAP Identity Authentication Service (aka IAS).
If you want to configure OAuth for calling SEMP, refer to this sibling blog post.
Technologies covered:
🔹SAP Business Technology Platform (BTP), Cloud Foundry
🔹SAP Integration Suite Advanced Event Mesh (AEM)
🔹Identity Authentication Service (IAS)

Content

0. Introduction
1. AEM:
    Create Broker
    Create Token
2. IAS:
    Create Users and Groups
    Create Oauth Client, Configure Attributes and Redirect
3. AEM REST API:
    Create OAuth Profile
    Create Allowed Host
    Create Role Mapping
4. Run Scenario
5. Optional: Disable Basic Authentication
6. Troubleshooting
Appendix: HTTP commands for Linux and Node

Prerequisites

🔹To follow this tutorial, access to  SAP Advanced Event Mesh is required.
🔹Access to an IAS tenant with admin permissions.
🔹I recommend bookmarking the Security Glossary

0. Introduction

Today we’re talking about the Broker Manager.

What is the Broker Manager?
Let's start from the beginning.
After entering AEM, we find ourselves in the Cloud Console.

intro_aem1.jpg

This is not the Broker Manager and this is not a broker.
It is the full AEM cloud universe providing access to everything.
Next, we enter the Cluster Manager.

intro_aem2.jpg

This is a tool which allows to create Event Broker Services.

What is an Event Broker Service?
This is a message broker, but managed in the cloud.
That’s why we can create a broker by just pressing “Create Service”.
The screenshot shows the “DemoBroker” which I’m using in the present tutorial.
After clicking on an Event Broker Service tile, we’re taken to the details screen:

intro_aem3.jpg

It provides lot of useful information and configuration options for the broker.
For instance, I recommend the “Connect” tab, as it shows the URLs and passwords for connecting to the broker for sending messages.
But all of these features, it is still not enough:
Now comes the Broker Manager into the picture!

Pre-Authentication for Broker Manager

The service-details screen provides a link for navigating to the Browser Manager (see screenshot above).
Once accessed the Broker Manager, we can change configurations or create queues and use the messaging test-tool, etc

aem_brokerManager.jpg

Let’s do a quick exercise:
In Broker Manager, we go to Messaging-> Access Control -> Client Authentication -> OAuth Profile
Look at it.
Press the create button, enter a name, we're taken to the settings screen.
Look at it.
Done.

Reason for this exercise:
We should understand:
THIS OAuth Profile management screen: THIS is not made for us.
Not today.
Not in this tutorial.
(it is used in this other tutorial)

The OAuth profiles that are configured inside a Broker instance, are used for “messaging”.
This means, connecting to a broker instance and send messages requires authentication. Such authentication can be configured to use OAuth.
But in our tutorial we don’t send any message, not even one tiny message.
In this tutorial we only want to open a tool.
We want to open the Broker Manager tool without using the Open-button and without Basic Authentication.
As such, we have to configure the OAuth profile at a lower level (not inside broker service).
We may search any lower location for creating OAuth Profiles - we won't find.
We have to use the REST API.
(finished exercise, we can close the Broker Manager).

Let's clarify with a picture:

diagram3.jpg

And some more details: 

diagram5.jpg

Basic Authentication for Broker Manager

Remember, we’ve accessed the Broker Manager via navigation link, from Cloud Console - the so-called “Pre-Authentication”.
But what we want to do is to bookmark the Broker Manager and open it directly, not from Cloud Console.

OK, we store the direct URL.
In my example it looks like this:
https://mr-connection-p4ir12yrw29.messaging.solace.cloud:943

After opening this URL in a browser, we need to enter user and password.
Note:
NOT our real personal user.
The required username and password are copied from the “Management Access” section of the details screen (highlighted in the screenshot of Cloud Console above)

intro_aem4_basicauth.jpg

Note that our tutorial has not started yet.
We’ve understood the easy ways of accessing Broker Manager via Pre-Authentication and Basic Authentication.
Now we want to switch to OAuth.

OAuth Authentication for Broker Manager

Before we start….

What is OAuth?
Let’s try to give a brief summary:
We don’t send user/password to the endpoint.
Instead, we send a token (a string containing some info).
We fetch that token from a so-called “Authorization Server”.
Beforehand, we have registered a “client” at that server.
Upon registration, the client gets an ID and a password, called “secret”.

To fetch a token, one of several “OAuth flows” is used.
Typical flow:
(1) the web application (“client”) requests a token from “Auth Server” (with ID / secret).
(2) The server asks the end user for consent (user enters name/password).
(3) Web app receives token and sends it (4) to the endpoint (“Resource Server”).
(5) The endpoint validates the token (with help from “Auth Server”) and responds to client.
This flow is called “Authorization Code” and requires interaction from end user.

diagram1.jpg

Summarizing, we have 4 participants:
Resource Server, hosting the resources, that are requested by the web app (e.g. photos).
Client, the (web) application.
Authorization Server, the server which issues the access tokens and knows how to validate end users.
End User, human user who uses the web applications and owns the resources (e.g. own photos).

What is a JWT token?
JWT stands for “JSON Web Token” and is defined as a string in JSON format, carrying some information.
The properties of a JWT token are called “claims”.
There are standard claims, but Authorization Servers may use additional claim names.
The JWT token is usually sent as “Bearer” token in a header of a request.
"Bearer" means that anyone who has the token, may be authenticated.
Nevertheless, security is given because the token expires soon.
The JSON string is Base46 encoded, because sent in HTTP requests.
For security reasons, JWT tokens come with a digital signature.
See Troubleshooting section to view an example content of a decoded JWT token. 

What is an OAuth client?
In the OAuth model, a "client" has to register at the Authorization Server, in order to be allowed to request bearer token (usual format is JWT). As such, a "client" is just a piece of paper with some data like credentials.
The web application, usually a browser-based web frontend, uses these credentials for handling user-login.
As such, we may talk of web app and OAuth client as synonyms.

How does it apply to Broker Manager?
As an end user (John), we open the Broker Manager in a browser, which is the web application.
Broker Manager acts as OAuth client which executes the “Authorization  Code” flow.
So the Authorization Server (IAS in our scenario) is contacted for fetching a token and IAS displays the login screen.
John was created as user in IAS, so we go ahead and enter the credentials.
Broker Manager reads the received JWT token, validates it and assigns the suitable access level.
diagram2_alt.jpg

All the details will be explained in this tutorial.
Below diagram gives another view on the OAuth Authentication for Broker access:

diagram4.jpg

The diagram shows:
IAS acts as both Authorization Server and Identity Provider.
As IDP, it stores the user John and the user group “aemeditor”, assigned to the user.
As AS, it contains an “Application” which represents the OAuth-client-registration.
The application provides the clientid + secret, required to fetch a token.
In addition, it has to be configured with the URI of Broker Manager, to allow the redirect.
This is a security mechanism for avoiding malicious redirects.
The Broker Manager stores an "OAuth Profile" (explained later).
This profile knows how to fetch a token from IAS, so it knows the client ID, secret, etc
It also has to know that the IAS-group “aemeditor” should match to the “read-write” role of the message VPN in AEM.
Finally, after John enters valid credentials, the Broker Manager allows admin access to the Broker.

Recap
We want to open the Broker Manager directly from bookmarked URL.
We don’t want to use the technical user and Basic Auth.
We want to use a real user maintained in our IDP - and OAuth.
In such scenario, Broker Manager acts as OAuth Client which handles the OAuth flow with IAS.
As such, we need to configure an "OAuth Profile" in AEM.
This has to be done with REST calls, as there’s no user interface for it.

 So now we can start with the tutorial which will cover the following steps:

  1. Create Event Broker Service for testing
    Create Token for REST API
  2. In IAS, we create a user and group
    Also, create and configure an “Application”
  3. Configure Broker for OAuth authentication
    This involves creating an OAuth Profile and configuring role mapping and redirect.

1. AEM: Create Broker and Token

The first part of the tutorial takes place in the AEM cockpit, where we create a Broker and a Token.
Both steps can be skipped if already available.

1.1. Create Event Broker Service

For this tutorial, we start creating a fresh new Event Broker Service instance, to be used for testing.
Documentation can be found here.

In the AEM Cloud Console, we go to Cluster Manager and press “Create Service”

74a0cd40-72b0-44bc-9a4b-adf0d6f01cb2.jpg

We enter the values of our choice.
In my example:
Service Name: "DemoBroker"
Cloud: AWS
Region: Europe
Release + Version: use default
Service Type: Developer
Message VPN Name: "demovpn"
Cluster Name: "democluster"

Note that I like to give names that might not be meaningful, but that help to understand what we see and what we’re doing. You may just ignore and use better naming.

aem_createbroker_ui2.jpg

We press "Create" at the bottom right corner and need to be patient while the broker service is provisioned.
Finally, we can check the newly created Event Broker Service in the AEM Console Cockpit.

34aff024-0fe5-4544-92f1-6af02139dafd.jpg

We click on the new tile to see the details of the new Event Broker Service.
The interesting information we get here:

aem_createbroker_dmrcluster.jpg

🔸URL
The last segment of the URL in browser is the service ID of the newly created broker instance
In my example:
https://eu10-canary.console.pubsub.em.services.cloud.sap/services/6sba7l0p1hp 
We should take a note of this ID.

🔸Hostname
The URL of the broker. We need it for directly accessing the broker management cockpit.
In my example:
mr-connection-p4ir12yrw29.messaging.solace.cloud

🔸Primary Router Name
It contains the ID of the broker service (serviceid), as prefix
In my example, the ID: 6sba7l0p1hp | primary

🔸Message VPN name
It is required in some REST calls, but in our tutorial we won't need it.

🔸Management Access
Here we can obtain the authentication details for accessing the management cockpit.
The username and password are printed here.

🔸Open Broker Manager
This button allows to navigate to the management cockpit without entering user/pwd.

We need to take a note of the hostname and service ID, as we’ll need it later.
We’re done with creation of Event Broker Service from the AEM console.

Get Broker Management Port

At the end of this tutorial, we want to open the Broker Manager cockpit directly, without taking the detour via the cloud console.
Thus, we need the full URL.
We already have taken a note of the hostname, but we need the port number as well.
We just need to click on the “Open Broker Manager” link on top of the console.
The broker management cockpit opens in a new browser window.
We take a look at the URL and copy the first section of it.
In my example:
https://mr-connection-p4ir12yrw29.messaging.solace.cloud:943

Note:
We can see that the Basic-Authentication user has been used, which we saw in the details screen before.

aem_createbroker_ui3.jpg

We can close the Broker Manager.

1.2. Create Token

In chapter below, we’re going to use the REST API for configuring OAuth in Broker Manager.
To use the API, we need to authenticate, which is done with bearer token.
The good news: the bearer token can be easily created in the cloud console cockpit.
In Cloud Console, we press the “User & Account” icon on the very bottom of the left navigation pane.
In the context menu, we press “Token Management”:

aem_token2.jpg

In the Token Management Screen, we press “Create Token” and enter some name for the new token.
The token can be used for calling many different REST endpoints which require different permissions.
That's why the token has to be configured to carry the required permissions.
To make life easy, we can enable just all of them.
Finally, we press “Create Token” button at the bottom of the page.

Note:
Don’t forget to store the token as it cannot be seen afterwards.
If you’ve lost the token, you can always regenerate it, but be aware that it will be different.

The documentation can be found here.

2. IAS: Configurations for Users and OAuth

In this tutorial we’re using SAP Cloud Identity Services - Identity Authentication (IAS).
If you're not familiar, start with Landing Page for documentation and getting a tenant.

What is IAS?
IAS can be used as Identity Provider (what we’re doing in this tutorial), but it can also used as proxy to connect to a different IDP (see here).
IAS takes the role of “Authorization Server” in an OAuth scenario.

Note:
IAS supports OIDC (and SAML) protocol for identity authentication.
OIDC (OpenID Connect) is a protocol that makes use of OAuth.
So that’s why we're using OAuth flow in this tutorial.

2.1. Create Users and Groups

Remember our goal:
When opening Broker Manager, we don’t want to use the technical user.
Instead,  we want to enable real users.
So first of all, we create 2 “real” users in IAS.
Furthermore, when working with Broker Manager, the user may have different permissions, like administrating or only viewing.
This must be distinguished in IAS by assigning groups.
So very first of really all: we create 2 groups.

2.1.1. Create User Groups

For testing the scenario, we create 2 groups:
One group is meant to identify users who are allowed to create and edit resources in Broker Manager.
The second groups is for users who are allowed to access Broker Manager but only view the content.

We login to our IAS tenant  cockpit,  go to  Users & Authorizations -> Groups -> press “Create”
We create 2 groups with names:
"aemeditorgroup"
"aemviewergroup"

ias_creategroup.jpg

We take a note of these new groups, as we’ll need them later.

2.1.2. Create Users

Next, we create 2 users, one should be allowed to view the content in Broker Manager, the other user can edit.
IAS cockpit -> Users & Authorizations -> User Management -> press “Add”.

Note:
For the sake of comprehensive learning, let’s fill out all the fields.
The “Login Name” is not mandatory, but we enter a name here.
Later, during AEM configuration, we’re going to use the Login Name to configure the visible username in the Broker cockpit.

For test users it is important to enable “Set Initial Password”, to avoid sending an email.
So we can use dummy email.

In my example I’m using these names:
"Joeview"
"Johnedit"

ias_createuser.jpg

2.1.3. Edit Users 

After creation, we step into the user details for each user.

Verify Email
In user details, press “Edit” and enable “Verify Email”.
Then “Save”.
With that, no email has to be sent to the dummy mail address.

Assign Users to Groups
Now we can assign the users to appropriate user groups.
In the details of each user, we can specify group assignment:
"Joeview" will be assigned the "aemviewergroup".
"Johnedit" will be assigned the "aemeditorgroup".

2.1.4. Change Password

The initial password of our test users will have to be changed.
We open a second browser in incognito mode and login to IAS with both users.
We enter the initial password, change it and log out.

2.2. Create OAuth Client

Next step is to create an “Application” in IAS.

What is an Application?
The name “Application” is equivalent to the technical term “OAuth client”.
By creating an “Application” in IAS, we register an OAuth client and get the permissions which are required to request a JWT token from IAS.

2.2.1. Create Application

We login to IAS as admin, go to Applications & Resources -> Applications -> Create
We enter a name of our choice.
In my example: "iasForAemBroker".
We make sure to enable “OpenID Connect”

ias_createApp1.jpg

By this, we’ve created and registered an OAuth Client at the IAS which acts as “Authorization Server” (OAuth) or “OICD Provider” (OpenID Connect).

2.2.2. Define Credentials

As mentioned, an OAuth client needs credentials to request a token.
Credentials can be user/password (id/secret) or a client certificate (mTLS).
To make life easier for this tutorial, we go for the user/password method.

We make sure that our new “Application” is selected on the left list.
We go to the details screen, find the “Trust” tab, go to section “Application APIs” and step into “Client Authentication”.

ias_createApp2.jpg

We can see that a client ID (represents the “username”) has already been generated.
We go to section “Secrets” and “Add” a new secret (means password).
No need to enter anything in the dialog, just “Save”

ias_createApp3.jpg

The new secret is displayed in a popup.
Read the title of the popup.
Read the warning text.
Or just read my tutorial:
For our tutorial, we need to take a note of both, ClientID and Client Secret.
ias_createApp4.jpg

Now we can press OK to close the popup.
Note:
If you lost the secret (because you didn’t read my tutorial), don’t worry, just create a new one.

2.2.3. Configure Attributes

After configuring the credentials that are required to fetch a JWT token, we need to configure the token itself.

Attribute for Groups
The JWT token which is issued by IAS, will carry information about the user.
E.g. his first name, email, user ID, etc
An important step is to make sure that the JWT token, which will be issued by IAS, will carry a claim that contains the group assignment of the user.

What?
At the end, when the user Johnedit opens Broker Manager, he will enter his credentials, then a JWT token will be issued by IAS.
Broker Manager will validate the token and check if it contains the "aemeditorgroup".
If yes, then Johnedit will be allowed to perform creation activities, etc.

In the details screen of our “Application”, we go to Trust -> Single Sign-On -> Attributes -> click “Add”
We enter:
Name: “member_of_groups”
Source: choose “Identity Directory” from the drop-down
Value: from the drop-down we choose “Groups”

This means:
At runtime, the JWT will contain a  claim (property) with name “member_of_groups”.
It will be filled with the value of the field in IAS which has name “Groups”.
Example value at runtime: "aemeditorgroup".
So it is a kind of necessary mapping:
cockpit-field <-> JWT-claim.
See Troubleshooting section to view an example content of a decoded JWT token. 

Note:
Usually, we would name the new attribute as “groups” which is a common name in JWT tokens.
However, for this tutorial and for more comprehensiveness, let’s give an unusual name ("member_of_groups"), which makes things more clear.

Attribute for user display
Now let’s create a second attribute.
It is not mandatory, but we use it again for better understanding of the AEM-OAuth-configuration below.
We create an attribute to carry a human-readable username.
This will be displayed later in the Broker Manager.

We press “Add” again and enter:

Name: “user_display_name”
Source: Identity Directory
Value: Login Name

ias_attributes_altern.jpg

Note:
If we use this claim for username, then we have the precondition that in IAS every user must have the “Login Name” field filled.
Otherwise the user gets an error when logging in to the AEM Broker Manager.
Alternatively, we could use “Email” as value. This field is mandatory in IAS, hence always available in JWT tokens.

2.2.4. Configure Redirect

While we’re still in the details pane of our new IAS-Application, we must configure the following important setting: The “Redirect URI”.
To understand this setting - see introduction for Authorization code flow.

What does it mean?
The Broker Manager is the client web application that requests a JWT token from IAS (with end user login).
IAS will send the "authorization code" (a short guid-string) to the "redirect URL" specified in the request.
The Broker Manager provides an own redirect-endpoint to receive the code.
But before IAS sends the code to that endpoint, it checks the config, to see if the URL is allowed.
As such, it has to be white-listed in IAS.

We go to Application Details -> Trust -> Single Sig-On -> OpenID Connect Configuration.
Here we enter any name of our choice, e.g.  "iasForAemBroker".
We need to enter the URL of the AEM-Broker-Manager, which we noted above.
In my example:
https://mr-connection-p4ir12yrw29.messaging.solace.cloud:943/oauth/complete 

We can enter the exact full URL:
https://mr-connection-p4ir12yrw29.messaging.solace.cloud:943/oauth/complete  
or we can use wildcards
https://mr-connection-p4ir12yrw29.messaging.solace.cloud:943/** 

ias_redirect.jpg

Little Recap
At IAS, we’ve done the following tasks:
🔸Create and configure users and groups
🔸Create Application and configure
    Credentials
    Attribute
    Redirect

3. AEM REST API: Configurations for OAuth

Now we’re coming to the interesting part of the tutorial: the configuration at AEM.
In IAS, we defined the OAuth client, now we need the web application that uses it.
The Broker Manager is the web application, but how can it be configured to use IAS for OAuth authentication?
There’s no configuration user interface, but there’s a configuration REST API.

Note:
In this chapter, we’re going to fire a bunch of HTTP requests.
You may use any REST client of your choice.
In the appendix, I’m providing you with convenience scripts for LINUX / cURL and Node.js

Introduction

AEM offers a broad and powerful range of REST APIs that can be used for various purposes like administering AEM or sending messages.
In our tutorial, we’re not sending any message, we’re focusing on administering the access to Broker Manager.
To do so, we’re using 2 REST APIs
🔹General REST API
🔹SEMP REST API

The documentation is quite extended and should be bookmarked in any case, for further clarification and examples and reference.
Start from here: https://help.pubsub.em.services.cloud.sap/Cloud/gqs_building_apps.htm

General REST API
This API provides endpoints to manage artifacts from outside perspective.
For instance activities around Mission Control or Event Portal, etc

Documentation: https://help.pubsub.em.services.cloud.sap/Cloud/cloud_rest_api.htm
Reference: https://api.solace.dev
Base URL: https://api.solace.cloud

SEMP REST API
SEMP stands for “Solace Element Management Protocol”.
This API is used for configurations underneath one broker instance.
So once we have created one broker service instance, we can use this API to configure it.

Documentation: https://help.pubsub.em.services.cloud.sap/Admin/SEMP/Using-SEMP.htm
Reference main: https://docs.solace.com/Admin/SEMP/SEMP-API-Ref.htm
Reference for "config" API: https://docs.solace.com/API-Developer-Online-Ref-Documentation/swagger-ui/software-broker/config/
Base Path:   ...<broker>/SEMP/v2/config

We will use the SEMP API in conjunction with the general API base path.
Example:
https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/<id>/broker/SEMP/v2/config/oauthProfiles

Preparation

We should prepare the data that we’ll need for below REST calls.

🔸IAS client ID:
from chapter above
🔸IAS client secret:
from chapter above
🔸IAS URL for discovery endpoint:
https://<ias>.accounts400.ondemand.com/.well-known/openid-configuration 
🔸AEM Token:
from chapter above
🔸AEM broker service id:
from chapter above
🔸AEM API URLs:
https://api.solace.cloud/api/v2/missionControl/eventBrokerServices 
https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/<id>/broker/SEMP/v2/config/oauthProfiles 

3.0. Optional: view existing brokers

We fire a HTTP request to get a list of existing brokers:

Request
URL
      https://api.solace.cloud/api/v2/missionControl/eventBrokerServices
Method
      GET
Headers
   name:   Authorization
   value:  Bearer eyJhbciOJzI1NsIpZI6...m1Xc
Response
    In the response we can see some info about each existing broker. Interesting for us: the service ID.

Note:
Make sure to replace the sample token value by your token.

Note:
Alternatively, we can use a filter by broker name
The broker name was given in chapter 1, when creating a new broker.
In my example: "DemoBroker"
The URL with filter:
https://api.solace.cloud/api/v2/missionControl/eventBrokerServices?customAttributes=name==DemoBroker  

Note:
In the following requests, make sure to replace the <id> with your service ID.

3.1. Create OAuth Profile

Now we’re really coming to the interesting part: creating OAuth profile.
But before we start creating a mess, we should try the URL with a GET request.

View all OAuth Profiles for management

The URL is specific for our new Event Broker Service, and it uses the /config API of SEMP

Request
URL
      https://api.solace.cloud/api/v2/
         missionControl/eventBrokerServices/<id>/broker/SEMP/v2/config/oauthProfiles
Method
      GET
Headers
   name:   Authorization
   value:  Bearer eyJhbciOJzI1NsIpZI6...m1Xc
Response
   The response is a JSON structure with lot of metadata.
   Interesting for us is the "data" not
   At this moment, it is an empty JSON array,
   The new broker doesn't contain any OAuth profile yet

I apologize for the line break in the URL.
See here the full URL in one line:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/<yourServiceId>/broker/SEMP/v2/config/oauthProfiles

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Create a new OAuth Profile

Now we’re really coming to the interesting part.
Note:
Important to keep in mind that we can create only a maximum of three OAuth profiles per event broker service.

Before we send the request, we need to prepare the request payload for creation.
Request payload for creating OAuth profile in my example:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

{
   "accessLevelGroupsClaimName":"member_of_groups",
   "clientId":"8310b1aa-9a0e-92fbbe",
   "clientRequiredType":"JWT",
   "clientScope":"openid",
   "clientSecret":"k2=E7tG-:G5E@1@n7a=3",
   "clientValidateTypeEnabled":false,
   "displayName":"SAP IdentityProvider (IAS)",
   "enabled":true,    
   "endpointDiscovery":https://ias.accounts400.ondemand.com/.well-known/openid-configuration,
   "endpointIntrospectionTimeout":10,
   "endpointTokenTimeout":10,
   "endpointUserinfoTimeout":10, "interactiveEnabled":true,
   "interactivePromptForNewSession":"select_account", 
   "oauthProfileName":"ias_for_broker",
   "oauthRole": "client",
   "usernameClaimName":"user_display_name"
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Note:
I’ve chosen to use the minimum amount of properties required for the request.
Other properties can live with default values.
As such, making the request payload smaller and easier.
Check docu link above for the full payload.

Make sure to adapt parts of the payload to your data.

Explanation

🔸accessLevelGroupsClaimName
The value of this property should be the name of the claim in the JWT, which carries the group assigned to the user.
In our tutorial, we’ve created the attribute in chapter 2.2.3.
In my example: "member_of_groups"
At runtime, the Broker Manager receives the JWT token, looks for the claim "member_of_groups" and reads the value.
It remembers the groups contained there, to find a mapping to an AEM role.
We will create the mapping later.

🔸clientId
Here we enter the client ID which we stored in chapter 2.2.2
In my example: 8310b1aa-9a0e-9504d032fbbe

🔸clientRequiredType
Here we enter :"JWT".
This means that the Broker Manager acts as client and requires a token of type JWT.

🔸clientScope
In case of IAS, we need to enter a scope name here.
IAS requires the scope parameter to be sent to the /authorize endpoint, as described in the docu.
Supported values are: "openid", "email", "profile", "groups", "offline_access"
Multiple values are separated by blank.
For our example, we enter "openid".

🔸clientSecret
Here we enter the client ID which we stored in chapter 2.2.2
In my example: kb2=EvmSxulf7tG-:G5E@1@navIsF7a=3Fb

🔸clientValidateTypeEnabled
Let’s turn off the validation, so we enter "false".

🔸displayName
This is just a label that will be displayed in the login screen of Broker Manager. See screenshot later on.
It identifies the Authorization Server to which the user will be redirected for login.
It should have a human-readable name which helps the end user to understand where he is logging in.
If multiple OAuth profiles are created, this display name helps to distinguish.
In my example I'm using: "SAP IdentityProvider (IAS)"

🔸Enabled
This refers to the profile itself.
Sure, we want it to be enabled.
We set to "true" because the default would have been "false".

🔸endpointDiscovery
This property expects the so-called “Discovery Endpoint”.
Usually OIDC providers and Authorization Servers provide this endpoint with suffix
/.well-known/openid-configuration
At this URL, all useful endpoints are collected, such that the Broker Manager can find all what he needs.
Examples are token endpoint, userinfo enpoint, etc
In my example:
https://ias.accounts400.ondemand.com/.well-known/openid-configuration 

🔸endpointIntrospectionTimeout
When the Broker Manager receives the token for user login, he needs to validate it.
To do so, it calls the introspection endpoint which can be found in the “Discovery”.
The default timeout is set to 1 which turned out to be too short in my testing.
I’m setting it to 10, you may check on your side what suits best.

🔸endpointTokenTimeout
Same as above but for the token endpoint.
For the "Authorization Code" flow, 2 endpoints are used:
First, the /authorize endpoint is called to get a "code".
Then, the /token endpoint is called to get a JWT token in exchange for the code.
Note that the error message is self-explaining in case of timeout.
The error message even tells, for which endpoint-request the timeout occurred

🔸endpointUserinfoTimeout
Again, this time the user info endpoint requires a bit more time.

🔸interactiveEnabled
In our scenario we do have user interaction.

🔸interactivePromptForNewSession
Here we enter "select_account".

🔸oauthProfileName
Here we enter a name for the OAuth Profile  that we’re just creating.
It won’t appear in the user interface, because we’ve specified the display name above.
So this profile name is a technical name which appears in the REST calls.
It must be unique and it also has constraints with respect to the allowed characters.
Note:
I found the docu incomplete and the error messages not specific, so my advice: be careful here
In my example: "ias_for_broker".

🔸oauthRole
This is an important property and I keep it visible in the body, although the default value is same.
This setting defines the role of the current Profile in the OAuth flow.
As described above, the Broker Manager acts as web app, as oauth client.
This is specific for the “Authorization Code” flow, where the web app wants to access some resources on behalf of the user.
In a different OAuth flow, the AEM-component would act as “Resource Server”, for example, if an app would want to consume messages.
OK?
We enter "client".

🔸usernameClaimName
Finally we have to specify a claim which is contained in the incoming JWT token.
It should be a claim that identifies the user who is logging into Broker Manager.
Such claim can be
“sub” = subject, usually clientid, or an internal userID
“email” this is a mandatory unique attribute for a user in an IDP
“user_uuid” an internal GUID
In our tutorial, we enter the attribute name which we configured in chapter 2.2.3: "user_display_name".
At runtime it will be filled with the value of "Login Name" of IAS.

Now we can go ahead and execute the request:

Request
URL
      https://api.solace.cloud/api/v2/
         missionControl/eventBrokerServices/<id>/broker/SEMP/v2/config/oauthProfiles
Method
      POST
Headers
   name:   Authorization
   value:  Bearer eyJhbciOJzI1NsIpZI6...m1Xc
      name:     content-type 
      value:  application/json
Body
      The adapted JSON payload from above
Response

      If we’re lucky, we get a success code and the created profile is contained in the response body.
      If not………
      Well, it might take time to figure out the reason, because the error messages are not helpful.
      My recommendation would be to inspect and adapt the JSON.

Optional: Test
After creating an OAuth profile, we can already test the outcome.
We open the URL which we noted in chapter 2.3.
In my example: https://mr-connection-dtkk09hm2m6.messaging.solace.cloud:943 
We use a different browser with incognito mode
We see that the login screen has changed:

run1_newLoginDialog.jpg

The name of the OAuth profile is displayed.
After pressing on our OAuth profile, we get an error: invalid host.
The host is the current URL, the web application which is attempting to trigger the OAuth flow.
More precise: this host: mr-connection-dtkk09hm2m6.messaging.solace.cloud:943
It needs to be white-listed in AEM as well (not only IAS).

3.2. Create allowed host

To do so, we add this host to the list of allowed hosts.
The list of allowed hosts can be retrieved from the endpoint /clientAllowedHosts
The endpoint is specific to a broker and to a profile.
As such, the URL is composed as follows:
<api>/missionControl/eventBrokerServices/<id>/<semp>/oauthProfiles/<profile>/clientAllowedHosts 

Full URL with placeholders:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/<id>/broker/SEMP/v2/config/oauthProfiles/<profile>/clientAllowedHosts

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

In my example:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/6sba7l0p1hp/broker/SEMP/v2/config/oauthProfiles/ias_for_broker/clientAllowedHosts

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The docu can be found here.

View list of existing allowed hosts

Again, let’s first try a GET request:

<id>/broker/SEMP/v2/config/oauthProfiles/ias_for_broker/clientAllowedHosts

Request
URL
      https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/
            <id>/broker/SEMP/v2/config/oauthProfiles/ias_for_broker/clientAllowedHosts
Method
      GET
Headers
   name:   Authorization
   value:  Bearer eyJhbciOJzI1NsIpZI6...m1Xc
Response
   Empty list as expected.

Create new allowed host

To create a white-list entry for our host, we need the exact host name which we want to enable.
It is the hostname which we copied in chapter 1.1.
But we need to append the port.
We know the port because we copied the full URL in chapter 1.1

Note:
We must not enter the full URL starting with https://

So the host name which should be allowed is in my example:
mr-connection-dtkk09hm2m6.messaging.solace.cloud:943

Now we can compose the request body for the POST request as follows:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

{
   "allowedHost": "mr-connection-dtkk09hm2m6.messaging.solace.cloud:943",
   "oauthProfileName": "ias_for_broker "
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Explanation

🔸allowedHost
As described above.
Make sure to adapt it to your environment.

🔸oauthProfileName
This must be exactly the same as the profile name specified in the POST request in chapter 3.1.
Furthermore, it must be the same as the segment in the URL.

We can execute the POST request for creating an entry in the list of allowed hosts:

Request
URL
      https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/
            <id>/broker/SEMP/v2/config/oauthProfiles/ias_for_broker/clientAllowedHosts
Method
      POST
Headers
   name:   Authorization
   value:  Bearer eyJhbciOJzI1NsIpZI6...m1Xc
      name:     content-type 
      value:  application/json
Body
      The adapted JSON payload from above
Response
      The response body contains the created entry.

3.3. Create role mapping

The last configuration which we need to do:
What about the permission of the user?
How can the Broker Manager know, what the  user is allowed to do?
The Broker Manager knows only about the AEM-roles (access-levels).
But the user is an IAS-user with IAS-group.

The solution:
We have to let Broker Manager know, which IAS-group corresponds to what AEM-role.

To do so, not surprisingly, we have a REST endpoint: the  /accessLevelGroups

Full URL with placeholders:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/<id>/broker/SEMP/v2/config/oauthProfiles/<profile>/accessLevelGroups

 

 

 

 

 

 

 

 

 

 

 

 

 

 

In my example:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/6sba7l0p1hp/broker/SEMP/v2/config/oauthProfiles/ias_for_broker/accessLevelGroups

 

 

 

 

 

 

 

 

 

 

 

 

 

 

View existing access level groups for this profile

Let's skip it this time.

1. Create new access level group for editor role

Now we can to ahead and create an entry in the list.
This entry is supposed to map an IAS-group to an AEM-role
Docu can be found here.

Compose request body:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

{
   "globalAccessLevel": "read-only",
   "groupName": "aemeditorgroup",
   "msgVpnAccessLevel": "read-write",
   "oauthProfileName": "ias_for_broker"
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 Explanation

🔸globalAccessLevel
Here we enter the permission for dealing with global data.
We set it to "read-only", as we’re not going to change anything global.
All possible values in ascending order:
   "none"
   "read-only"
   "read-write"
   "admin"

🔸groupName
Here we enter the name of the IAS group.
It must be spelled exactly.
In my example: "aemeditorgroup" (without quotes)

🔸msgVpnAccessLevel
This is the interesting property.
It defines permissions required to create queues, for instance.
Possible values:
   "none"
   "read-only"
   "read-write"
As the previous property was filled with the “editor” group of IAS, here we enter the “editor” role of AEM.
We enter "read-write"

🔸oauthProfileName
Here we enter the name of the OAuth Profile which we created above.
It must match also the profile name in the URL
In my example: "ias_for_broker"

The POST request:

Request
URL
      https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/
            <id>/broker/SEMP/v2/config/oauthProfiles/ias_for_broker/accessLevelGroups
Method
      POST
Headers
   name:   Authorization
   value:  Bearer eyJhbciOJzI1NsIpZI6...m1Xc
      name:     content-type 
      value:  application/json
Body
      The adapted JSON payload from above
Response
      The response body contains the created entry.

2. Create new access level group for viewer role

For a comprehensive learning experience, we need 2 mappings in our tutorial.
The second one is meant for the viewer, who is only allowed to view all content, but may not modify anything.
For this mapping, the request body looks almost same, but the group and role are different:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

{
   "globalAccessLevel": "read-only",
   "groupName": "aemviewergroup",
   "msgVpnAccessLevel": "read-only",
   "oauthProfileName": "ias_for_broker"
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

We’re mapping the aemviewergroup to the read-only role.

Note:
There’s one more optional property which I’ve removed: “description”.

The POST request is the same as above, with new request payload.

Little Recap

We’re done with configuration on AEM-side.
Basically, we had to execute 3 POST requests, for creating an OAuth profile and add some configuration to it.
Please refer to the Appendix to copy scripts which I’ve put together for you.

However, we cannot lean back, as we’re not done yet.
Let’s see if our configurations have all been correct…..

4. Run

We open a different browser, incognito mode and paste the URL which we stored above.
Reminder: it can be found in the Cloud Console, in the Details page of the Broker Service
In my example, the direct URL of the new Broker:
https://mr-connection-p4ir12yrw29.messaging.solace.cloud:943 

After requesting the URL, we’re redirected to the login screen, which contains now the login option with the display name of our new OAuth Profile:

run1_newLoginDialog.jpg

After clicking on our OAuth button, we’re taken to the login screen of IAS, where we can see the name of the “Application” we’ve created before:

run2_iasDialog.jpg

We enter Login Name and password of our editor_user. 
In my example: Johnedit
(alternatively, can use email)

As a result, we’re taken to the landing page of the broker manager.
In the upper right corner we can see the user display name as we configured in our OAuth Profile:

result3.jpg

After login, we can test the permissions.
User Johnedit is able to create a queue, while Joeview can only see the disabled “Create” button.

Optional: test without roles

To see the negative scenario working, we can create a third user at IAS, but this user doesn’t have any group assignment.
Hence, he won’t have any AEM-roles mapped.
Hence, he might be able to login to the Broker Manager dashboard, but no permission to do anything, not create and not even view anything.
This is how the Broker Manager for such user:  run_negative.jpg

Looks frustrating…

5. Optional: Disable

We're now briefly discuss 2 safety measures that can be now taken, after we have the OAuth authentication in place.

5.1. Disable Basic Authentication

For security reasons, it makes sense to disable the possibility to login with Basic Authentication.
As a consequence, only users that are maintained in IAS (in our example) and with proper group assignment are allowed to access the Broker Manager.

Note:
Before disabling Basic Authentication, we should make sure that OAuth Authentication is feasible for all required users.

To disable Basic Authentication, we just need to execute one last REST call.
Documentation can be found here.

Note:
This endpoint supports only PUT operation, we cannot fire a GET request to find out the current state.

Compose request body:

 

 

 

 

 

 

 

 

 

 

 

{
   "enabled":"false"
}

 

 

 

 

 

 

 

 

 

 

 

The PUT request:

Request
URL
      https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/<id>/sempBasicAuth
Method
      PUT
Headers
   name:   Authorization
   value:  Bearer eyJhbciOJzI1NsIpZI6...m1Xc
      name:     content-type 
      value:  application/json
Body
      The JSON payload from above

Note:
To re-enable basic authentication, just re-send the request with adapted payload

Negative Test for Basic Authentication

We open the Broker Manager again at https://mr-connection-p4ir12yrw29.messaging.solace.cloud:943 
But this time we enter the credentials of the technical user directly in the login page
The credentials can be found in the Cloud Console, Details page, “Management Access” section.
As a result, we get an error page

result4_BA_disabled.jpg

5.2. Optional: Disable Pre-Authentication

It makes sense to disable the Pre-Authentication, as described in the docu

6. Troubleshooting

I faced multiple errors while working on this tutorial, I try to support my dear readers by sharing few findings I remember.

🔷General Status 400 error while executing REST requests.
HTTP status 400 are thrown always for any kind of endpoint-dissatisfaction.
But no useful error messages in the response.
What we can do in case of POST requests:
- Check the name and try to remove any special characters
- Check if you’re creating a duplicate, if the entry already exists

🔷I faced problems when working with 3 OAuth profiles
As of docu, 3 should be fine, as it is the maximum.
However, after creating third profile, subsequent REST calls did fail.
In my case, everything went fine when working with 2 profiles only.

🔷A weird issue in IAS
Be careful when copy&pasting attribute names in IAS.
There might be a  blank at the end which is not visible.
It seems that the trailing blank is trimmed in the UI, but not trimmed in the backend of IAS.
Hence, the issued JWT contains an attribute with blank  - and it doesn’t match the configured property in the OAuth profile.
Leading to an error on login.
This has to be checked by viewing the JWT in the IAS logs.
But need to really thoroughly view the JWT.

🔷Default Attributes in IAS
It makes a difference when creating an "Application" in IAS with the dashboard, or via service instance in Cloud Foundry:
The set of default attributes is different.
As such, make sure to have a look at the attributes section in IAS cockpit.

Checking the issued JWT token

Crucial for troubleshooting is to view the content of the JWT that is sent to AEM.
To do so, IAS offers the possibility to view the issued tokens in the Logs.
The logs are crowded, so you might find below description useful:

Go to IAS-cockpit -> Monitoring & Reporting -> Troubleshooting Logs
Open a different browser and login to AEM Broker Manager, such that a JWT token is issued.

Now, in IAS, we need to adjust few filters, to find the JWT token in the tremendous amount of logs.
First, we adjust the time span to make it short.
Afterwards. press “Go”.
Additionally, in the search filter field we enter “issueJWT”.
Press enter.
We get the log entries that are relevant for us.
IAS also provides the convenience to decode the token for us.
To view the JWT content, we click on “Log Details”.
troubleshoot1.jpg

We might need to make sure that the JWT token corresponds to the desired user, otherwise choose a different entry or extend the time span.

Example Content of JWT token

See below the shortened content of a JWT token in my example:

 

 

 

 

 

 

 

 

{
   "first_name":"Johnedit"
   "last_name":"Aemeditor",
   "user_display_name":"Johnedit",
   "member_of_groups":"aemeditorgroup",
   "mail":"johnedit@aem.com",
   "sub":"P000026",
   "user_uuid":"8b60baa9-eeed-411a-bbe5",
   "aud":"8310b1aa-9a0e-462f-8f47",
   "iss":"ias.accounts400.ondemand.com"
}

 

 

 

 

 

 

 

 

Note the claims that we defined manually in IAS.
See the other default claims that can be used when configuring the OAuth profile. 

Summary

This blog post was about accessing the “Broker Manager” tool with OAuth instead of Basic Authentication.
We’ve described the scenario using IAS as “Authorization Server” and Identity Provider.
The desired outcome:
🔹Login:
When a user opens the “Broker Manager” in a browser, then the user is redirected to IAS, which displays a login screen and executes the OAuth flow.
🔹Roles:
Different users may be allowed to edit or only view the content of Broker Manager. Such AEM-roles are mapped to IAS-groups to which the users are assigned in IAS.

The required steps:
🔷Configuration in IAS:
🔹In IAS, users and groups are maintained.
🔹In addition, we need to create an OAuth client, called “Application”.
   The application needs to be configured:
      🔹Redirect URL
      🔹Attributes
      🔹OAuth Client Secret
🔷In AEM, the configuration for OAuth access to Broker Manager can be done only with REST API.
🔹Create OAuth profile
🔹Define allowed host
🔹Define role mapping
🔹Optionally disable Basic Authentication

Links

SAP Help Center:
OAuth configuration for Broker 
REST API main entry 

Solace:
SEMP main page https://docs.solace.com/Admin/SEMP/SEMP-API-Ref.htm
SEMP Reference 
Using SEMP 
SEMP tutorials 
API main entry: https://api.solace.dev/
API reference : https://api.solace.dev/cloud/reference
Solace Developer Codelabs https://codelabs.solace.dev/
Solace at YouTube: https://www.youtube.com/@Solacedotcom

SAP Cloud Identity Services - Identity Authentication (IAS):
Entry in Discovery Center
IAS Landing Page
IAS: getting a tenant
OAuth flows in IAS main page
Authorization Code flow in IAS

Appendix 1: cURL commands

For your convenience, I've put together the cURL commands required for above described steps.
Make sure to adapt the values of the variables.

 

 

 

 

 

 

 

 

JWT="eyJhbGciOiJIw.eyJvcmciJuaXE1MjIyOX0.Jx89017uauA7jI2_sNEWUGQ"
API="https://api.solace.cloud/api/v2"
SERVICES="${API}/missionControl/eventBrokerServices"

# GET all broker services
curl --url "${SERVICES}" -H "Authorization: Bearer ${JWT}"

# GET existing broker with filter by name
BROKER="DemoBroker" # the name was given when creating a new Event Broker Service in the AEM Cloud Console
SERVICESFILTER="${SERVICES}?customAttributes=name==${BROKER}"
SERVICEID=$(curl -s --url "${SERVICESFILTER}" -H "Authorization: Bearer ${JWT}" | jq -r .data[0].id)     
echo "Found Broker Service with ID: '${SERVICEID}'"


# view OAuth profiles
curl --url "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles" -H "Authorization: Bearer ${JWT}" -s | jq -r .data
# count OAuth profiles:
curl --url "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles" -H "Authorization: Bearer ${JWT}" -s | jq '.data | length'


# === #
# Create OAuth profile #
# === #

#constants for request payloads
OAUTH_PROFILE_NAME='ias_for_broker'
OAUTH_DISPLAY_NAME='SAP IdentityProvider (IAS)'
OAUTH_GROUPS="member_of_groups"
OAUTH_USER="user_display_name"
IAS_ID="8310b1aa-9a0e-462f-8f47-9504d032fbbe"
IAS_SECRET="kb2=EvmSxulf7tG-:G5E@1@navIsF7a=3Fb"


#compose the request body 
BODY_PROFILE='{
    "accessLevelGroupsClaimName":"'${OAUTH_GROUPS}'",
    "clientId":"'${IAS_ID}'",
    "clientRequiredType":"JWT",
    "clientScope":"openid",
    "clientSecret":"'${IAS_SECRET}'",
    "clientValidateTypeEnabled":false,
    "displayName":"'${OAUTH_DISPLAY_NAME}'",
    "enabled":true,
    "endpointDiscovery":"https://fmiid.accounts400.ondemand.com/.well-known/openid-configuration",
    "endpointIntrospectionTimeout":10,
    "endpointTokenTimeout":10,
    "endpointUserinfoTimeout":10,
    "interactiveEnabled":true,
    "interactivePromptForNewSession":"select_account",
    "oauthProfileName":"'${OAUTH_PROFILE_NAME}'",
    "oauthRole": "client",
    "usernameClaimName":"'${OAUTH_USER}'"
}'

# create
curl --url "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles" -H "Authorization: Bearer ${JWT}" -H 'content-type: application/json' -s -X POST -d "${BODY_PROFILE}"

# === #
# get allowed hosts
curl "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles/${OAUTH_PROFILE_NAME}/clientAllowedHosts" -H "Authorization: Bearer ${JWT}" -s

# get Broker Host URI
HOST=$(curl --url "${SERVICES}/${SERVICEID}?expand=serviceConnectionEndpoints" -H "Authorization: Bearer ${JWT}" -s | jq -r .data.serviceConnectionEndpoints[0].hostNames[0])
echo "The Broker host URI: '${HOST}'"

# Create allowedHost 
BODY_HOST='{"allowedHost":"'${HOST}':943","oauthProfileName":"'${OAUTH_PROFILE_NAME}'"}'
curl "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles/${OAUTH_PROFILE_NAME}/clientAllowedHosts" -X POST -d "${BODY_HOST}" -H "Authorization: Bearer ${JWT}" -H 'content-type: application/json' -s

# === #
# View accessLevelGroups
curl "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles/${OAUTH_PROFILE_NAME}/accessLevelGroups" -H "Authorization: Bearer ${JWT}" -s

# Create accessLevelGroup (without description property)
BODY_GROUP='{"globalAccessLevel":"read-only","groupName":"aemeditorgroup","msgVpnAccessLevel":"read-write","oauthProfileName":"'${OAUTH_PROFILE_NAME}'"}'
curl "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles/${OAUTH_PROFILE_NAME}/accessLevelGroups" -X POST -d "${BODY_GROUP}" -H "Authorization: Bearer ${JWT}" -H 'content-type: application/json' -s

# viewer with no gloabal permission at all
BODY_GROUP='{"globalAccessLevel":"none","groupName":"aemviewergroup","msgVpnAccessLevel":"read-only","oauthProfileName":"'${OAUTH_PROFILE_NAME}'"}'
curl "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles/${OAUTH_PROFILE_NAME}/accessLevelGroups" -X POST -d "${BODY_GROUP}" -H "Authorization: Bearer ${JWT}" -H 'content-type: application/json' -s

# === #
# disable Basic Auth / Update on BasicAuthEnabled
BODY_BA='{"enabled":"false"}'
curl "${SERVICES}/${SERVICEID}/sempBasicAuth" -X PUT -d "${BODY_BA}" -H "Authorization: Bearer ${JWT}" -H 'content-type: application/json' -s

# === #
# delete OAuth Profile
#curl "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles/${OAUTH_PROFILE_NAME}" -X DELETE -H "Authorization: Bearer ${JWT}" -H 'content-type: application/json' -s
curl "${SERVICES}/${SERVICEID}/broker/SEMP/v2/config/oauthProfiles/${OAUTH_PROFILE_NAME}" -X DELETE -H "Authorization: Bearer ${JWT}" -s

 

 

 

 

 

 

Appendix 2: Node.js sample code

Please find below some Node.js code that I've used to execute the tutorial.
It is not meant to run as script.
Make sure to adapt the values.

 

 

 

 

 

 

const axios = require('axios')

const TOKEN = 'eyJhbGciOiJIw.eyJvcmciJuaXE1MjIyOX0.Jx89017uauA7jI2_sNEWUGQ'
const API = "https://api.solace.cloud/api/v2"
const SERVICES = API + '/missionControl/eventBrokerServices'

// constants for request payloads
const OAUTH_PROFILE_NAME = 'ias_for_broker'
const OAUTH_DISPLAY_NAME = 'SAP IdentityProvider (IAS)'
const OAUTH_GROUPS = "member_of_groups"
const OAUTH_USER = "user_display_name"
const IAS_ID = "8310b1aa-9a0e-462f-8f47-9504d032fbbe"
const IAS_SECRET = "kb2=EvmSxulf7tG-:G5E@1@navIsF7a=3Fb"

const BODY_PROFILE = {
    "accessLevelGroupsClaimName": OAUTH_GROUPS,
    "clientId": IAS_ID,
    "clientRequiredType": "JWT",
    "clientScope": "openid",
    "clientSecret": IAS_SECRET ,
    "clientValidateTypeEnabled": false,
    "displayName": OAUTH_DISPLAY_NAME,
    "enabled": true,
    "endpointDiscovery": "https://fmiid.accounts400.ondemand.com/.well-known/openid-configuration",
    "endpointIntrospectionTimeout": 10,
    "endpointTokenTimeout": 10,
    "endpointUserinfoTimeout": 10,
    "interactiveEnabled": true,
    "interactivePromptForNewSession": "select_account",
    "oauthProfileName": OAUTH_PROFILE_NAME,
    "oauthRole": "client",
    "usernameClaimName": OAUTH_USER
}

const BODY_EDITOR = {
    "description": "SolaceAdmin Group",
    "globalAccessLevel": "read-only",
    "groupName": "aemeditorgroup",
    "msgVpnAccessLevel": "read-write",
    "oauthProfileName": OAUTH_PROFILE_NAME
}
const BODY_VIEWER = {
    "description": "SolaceAdmin Group",
    "globalAccessLevel": "read-only",
    "groupName": "aemviewergroup",
    "msgVpnAccessLevel": "read-only",
    "oauthProfileName": OAUTH_PROFILE_NAME
}




/* Helpers */

async function getBrokers(token){
    return callAxios('GET', null, SERVICES, token)
}

async function getServiceID(brokerName, token){
    const brokers = await getBrokers(token)  
    const theBroker = brokers.data.find(({name}) => name === brokerName)  //using destructuring, instead of .find(broker => broker.name === brokerName) 
    return theBroker.id
}

async function createOAuthProfile(payload, serviceid, token){
    return callAxios('POST', payload, 
        `${SERVICES}/${serviceid}/broker/SEMP/v2/config/oauthProfiles`, 
        token)
}

async function createAllowedHost(payload, profileName, serviceid, token){
    return callAxios('POST', payload, 
        `${SERVICES}/${serviceid}/broker/SEMP/v2/config/oauthProfiles/${profileName}/clientAllowedHosts`, 
        token)
}

async function createAccessLevelGroup(payload, profileName, serviceid, token){
    return callAxios('POST', payload, 
        `${SERVICES}/${serviceid}/broker/SEMP/v2/config/oauthProfiles/${profileName}/accessLevelGroups`, 
        token)
}

// Disable basic authentication
async function updateBasicAuthEnabled(payload, serviceid, token){
    return callAxios('PUT', payload, 
        `${SERVICES}/${serviceid}/sempBasicAuth`, 
        token)
}

// required for configuring "allowedHost"
async function getBrokerHostUri(serviceid, token){
    const options = {
        url : `${SERVICES}/${serviceid}?expand=serviceConnectionEndpoints`,
        headers: {'Authorization': 'Bearer ' + token}
    }
    const response = await axios(options)
    const hostName = response.data.data.serviceConnectionEndpoints[0].hostNames[0]
    return {"data": hostName}
}

async function getOAuthProfilesForBroker(serviceid, token){
    return callAxios('GET', null,  `${SERVICES}/${serviceid}/broker/SEMP/v2/config/oauthProfiles`, token)
}

async function deleteOAuthProfileForBroker(profileName, serviceid, token){
    return callAxios('DELETE', null, `${SERVICES}/${serviceid}/broker/SEMP/v2/config/oauthProfiles/${profileName}`, token)
}


/* Generic */

async function callAxios(method, payload, url, token){
    const options = {
        url: url,
        headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + token        
        },
        method: method
    }
    if(payload){
        options.data = payload
    }

    let response = undefined
    try {
        response = await axios(options)
        return response.data
    } catch (error) {
        if (error.response) {
            console.log("===> ERROR : message: " + error.message)
            console.log("===> ERROR : status: " + error.response.status)
            console.log("===> ERROR : headers: " + JSON.stringify(error.response.headers))
            console.log("===> ERROR : internal error:" + error.response.data.error)
            console.log("===> ERROR : internal message:: " + error.response.data.message)            
        }else{
            console.log({...error}) 
        }
    }
}


/* SCRIPT */

async function run(){
    var response

    /* retrieve the serviceID of the manually created broker */
    const serviceID = await getServiceID("DemoBroker", TOKEN)
    console.log(`Found my broker, the ID: ${serviceID}`)

    /* OAuth Profiles */
    response = await createOAuthProfile(BODY_PROFILE, serviceID, TOKEN)
    response = await getOAuthProfilesForBroker(serviceID, TOKEN)  
    console.log(response.data)

    // /* Allowed hosts */
    response = await getBrokerHostUri(serviceID, TOKEN)
    const brokerHostname = response.data + ':943'
    response = await createAllowedHost({"allowedHost": brokerHostname,"oauthProfileName": OAUTH_PROFILE_NAME}, OAUTH_PROFILE_NAME, serviceID,TOKEN) 
    console.log(response.data)

    // /* Role mapping */
    response = await createAccessLevelGroup(BODY_EDITOR, OAUTH_PROFILE_NAME, serviceID, TOKEN)
    console.log(response.data)
    response = await createAccessLevelGroup(BODY_VIEWER, OAUTH_PROFILE_NAME, serviceID, TOKEN)
    console.log(response.data)

    /* disable Basic Authentication */
    response = await updateBasicAuthEnabled ('{"enabled":false}', serviceID, TOKEN)
    console.log(response.data)

    // optionally: delete the created OAuth profile
    response = await deleteOAuthProfileForBroker(OAUTH_PROFILE_NAME, serviceID, TOKEN) 
    console.log(response.data)

}

// run script
run()

 

 

 

 

 

Appendix 3: Create Broker via API

Please find below some Node.js code that I've used to create a Broker with REST call instead of UI

URL: https://api.solace.cloud/api/v2/missionControl/eventBrokerServices

 

 

 

 

 

    const payload = {
        "name": "DemoBroker",
        "msgVpnName" : "DemoVPN",
        "datacenterId": "eks-ap-south-1a",
        "serviceClassId":'DEVELOPER',
        "adminState": "start"
     }

 

 

 

 

 

 

Response:
The property carrying the ID of the new broker is called "id".

 

Using the v0 API:

 

 

 

 

 

        url : 'https://api.solace.cloud/api/v0/services',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + token        
        },

        data: {
            "name": "DemoBroker",
            "msgVpnName" : "DemoVPN",
            "datacenterId": "eks-ap-south-1a",
            "serviceClassId":'developer',
            "serviceTypeId": 'developer',
            "adminState": "start"
         }

 

 

 

 

 

Response:
When using the v0 API, the property carrying the ID of the new broker is called "serviceid".

 

 

 

1 Comment
arturka
Explorer
0 Kudos

Great blog, thx.

Thanks to this blog we were able to establish Entra ID authentication. Official documentation isn't clear and has some mistakes.

Eg. 

https://${ENDPOINT}/SEMP/v2/config/oauthProfiles/${PROFILE_NAME}

This doesn't work with POST because profile name is not needed for creation, (same for role mapping)

arturka_0-1734384938310.png

 

and better way is to use https://api.solace.cloud/api/v2/missionControl/eventBrokerServices/xxxxx/broker/SEMP/v2/config/oauth... instead of ENDPOINT - ${CLOUD_HOST}/api/v2/missionControl/eventBrokerServices/${SERVICE_ID}/broker

Next thing OIDC well known URL is wrong 

correct one for IAS is as described in IAS guide https://help.sap.com/docs/cloud-identity-services/cloud-identity-services/call-identity-authenticati... 

A.