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.
We explain the use cases for using the Partner Directory in an integration flow and elaborate a step-by-step example which you can configure in your SAP Cloud Integration tenant.
The Partner Directory is used in integration scenarios where you establish a communication network between many communication partners. In such kind of scenarios, you build one or a few integration flows which are parametrized by partner-specific information. The parametrized components in the integration flow read the partner-specific information from the Partner Directory. The Partner Directory contains for each partner parameters, like
the Authorized User which is authorized to call inbound endpoints of the integration flow(s),
the HTTP addresses needed for making outbound calls to the partner systems.
With the Partner Directory, it is possible to add new communication partners without downtime and without changing or redeploying the integration flows. The tenant administrator or Partner Directory configurator can enter entries of a new partner into the Partner Directory via an OData API while the message processing for the existing partners is ongoing.
Figure 1: Partner Directory Usage Scenario
Message Dependent Parameter Lookup
In scenarios where the Partner Directory is involved, the messages sent to the integration flow(s) typically contain information that is needed for looking-up the parameters from the Partner Directory. For example, if the sent message contains the receiver partner ID then the receiver address can be looked-up.
Figure 2: : Message Containing the Partner IDs for Which Parameters Must be Looked-Up in the Partner Directory
Accessing Parameters in a Script Step
The Partner Directory does not predefine which parameters must be specified for a partner. The Integration Developer decides which parameter names (also called IDs) he wants to use. In a script step then the parameter value can be accessed by the partner ID contained in the message and the parameter ID.
Figure 3: Accessing Parameters via Script Using the Partner ID Given in the Message and the Hard Coded Parameter ID
There are length and character restrictions for the partner ID and parameter ID.
Maximum length of the partner ID: 60 characters
Maximum length of the parameter ID: 1500 characters
Allowed characters for the partner ID and parameter ID: ALPHA / DIGIT / ‘-‘ / ‘.‘ / ‘_‘ / ‘~‘ / ‘<‘ / ‘>‘ where ALPHA =(%41-%5A and %61-%7A in ASCII), DIGIT=(%30-%39 in ASCII)
Sometimes the messages contain IDs for the partners which must be mapped to the partner IDs of the Partner Directory. This use case will be treated in a separate blog.
Example Scenario
In our example scenario, we differentiate between sender and receiver communication partners. Sender communication partners make calls to receiver communication partners via the SAP Cloud Integration tenant and receiver partners receive calls from the sender communication partners via the tenant. This makes it easier to understand what you configure for partners making inbound calls to the tenant and for partners which receive outbound calls from the tenant. There may be scenarios where the sender and receiver partner are the same entity; in this case you do not need to have separate partner IDs for the sender and receiver parameters.
We will set-up a scenario where we have the two sender partners with the partner IDs “Sender_BASIC” and “Sender_OAUTH” and the two receiver partners with the partner IDs “Receiver_1” and “Receiver_2”.
The senders will send HTTP messages with the format given in Figure 2 to the Cloud Integration tenant. The tenant will forward the message to the receiver partner specified in the message.
The receiver partners are represented by two simple integration flows which just return in the content element of the message the receiver partner ID with a greeting text. These receiver integration flows will be created in a separate receiver tenant. If you only have one tenant, you can also create the receiver integration flows in the same tenant where the Partner Directory integration flow is located. But we recommend to use two separate tenants; then it is easier to understand what must be configured for the integration flow using the Partner Directory (also called Partner Directory integration flow).
The sender partners are simulated by Google PostMan.
Figure 4: Example Scenario
Prerequisites
To be able to set-up the scenario, you need
two SAP Cloud Integration tenants (one for the Partner Directory integration flow and the other one for the receiver integration flows); it is also possible to use only one tenant; however, then you cannot so easily see what you have configured for the Partner Directory integration flow and what you have configured for the receiver integration flows.
a Tenant Administrator user in both tenants which has Administrator permission in the SAP BTP Cockpit and which has the Role AuthGroup.Adminstrator on the tenant management node (tmn) application of your integration tenants
an Integration Developer user in both tenants which can create and deploy integration flows (Role AuthGroup.IntegrationDeveloper on tmn application of your integration tenant),
a further user which will be used for sending messages to the Partner Directory tenant (you can also use the Integration Developer or Tenant Administrator user instead); in the following sections, we will call this user Communication user
an appropriately configured tenant keystore of the Partner Directory; the keystore must contain a key-pair which is signed by a CA which is accepted by the Loadbalancer of the SAP Cloud Integration (typically SAP pre-installs such kind of key-pair with the alias “sap_cloudintegrationcertificate” or “hcicertificate”)
Google PostMan installed on your local machine for sending messages to the integration tenant
Step 1: Creating Receiver Integration Flows
In the receiver tenant create an integration flow with the sender channel and a Content Modifier step as shown in the following screen shots.
Figure 7: Receiver Integration Flow, SOAP 1.x Sender Channel, Connection Tab (be aware that we use as User Role “receiver_1.send”; for the second receiver integration flow you have to use “receiver_2.send”)
Figure 8: Content Modifier Exchange, Property Tab
Figure 9: Receiver Integration Flow, Content Modifier, Message Body Tab
Deploy the integration flow and test with PostMan whether the integration flow works. Do not forget to create the role “receive_1.send” and assign the Communication User (which can be the Integration Developer user or Tenant Administrator user) in the SAP BTP Cockpit. See the following screen shot.
Figure 10: Assigning the role “receiver_1.send” to the Communication User
You find the endpoint URL you use in PostMan in the SAP Cloud Integration Cockpit in the Operations View > Manage Integration Content > <receiver integration flow name>:
Figure 11: Receiver Endpoint Address is Displayed in the SAP Cloud Integration Cockpit
Figure 12: Test with PostMan the Receiver Integration Flow (do not forget to enter the user and password in the Authorization Tab)
Make sure that you wrap the message body the SOAP envelop.The following figure shows the test message you can use in PostMan:
Create a similar receiver integration flow for the “Receiver_2” partner. Use the endpoint address “/receiver_2” instead of the endpoint address “/receiver_1” and instead of the role “receiver_1.send” use “receiver_2.send”. In the Content Modifier use in the body “Receiver_2” instead of “Receiver_1”.
The following screen shots show how you create an integration flow which makes look-ups into the Partner Directory in a script step to set the receiver partner-dependent receiver address.
Figure 13: Partner Directory Integration Flow
Figure 14: Configuration of the HTTPS Sender Channel
Figure 15: Content Modifier Configuration (the content modifier reads the sender and receiver partner ID contained in the message into the properties SENDER_ID and RECEIVER_ID)
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import com.sap.it.api.pd.PartnerDirectoryService;
import com.sap.it.api.ITApiFactory;
def Message processData(Message message) {
def service = ITApiFactory.getApi(PartnerDirectoryService.class, null);
if (service == null){
throw new IllegalStateException("Partner Directory Service not found");
}
def map = message.getProperties();
def receiverId = map.get("RECEIVER_ID");
if (receiverId == null){
throw new IllegalStateException("Receiver ID is not set in the property 'RECEIVER_ID'")
}
def parameterValue = service.getParameter("ADDRESS", receiverId , String.class);
if (parameterValue == null){
throw new IllegalStateException("ADDRESS parameter not found in the Partner Directory for the partner ID "+receiverId);
}
Groovy Script 1: Fetches the Receiver Partner ID from the Property “RECEIVER_ID”, Reads the Receiver Address from the Partner Directory and Sets the Receiver Address as Property “RECEIVER_ADDRESS”
Figure 16: Configuration of the SOAP 1.x Receiver Channel (the address is dynamically read from the property “RECEIVER_ADDRESS”)
Note: Figure 16 shows that the "Private Key Alias" is not specified. You must only specify the "Private Key Alias", if you have in the tenant keystore several private keys trusted by the receiver system. Trusted here means that the certificate chain assigned to the private key in the keystore is trusted by the receiver system. If you have only one private key which is trusted by the receiver system then the correct private key is automatically selected.
Step 3: Adding Partner Information to the Partner Directory
Now, we are ready to add the parameters for the partners “Sender_BASIC” and “Receiver_1” to the Partner Directory. The tenant administrator or a user with the role AuthGroup.PartnerDirectoryConfigurator can do this via the OData API.
The OData calls must be made to your tmn node which has the format
https://<tenant short name>-tmn.<ssl_host_name>.hana.ondemand.com/api
In the following we will use for this address the abbreviation
Figure 17: Fetching the X-CSRF-Token (be aware that the token is returned in the header “X-CSRF-Token”)
You enter this token into all the following create/change/delete requests for the header “X-CSRF-Token”. The token can be reused for about 30 minutes. When the token is no longer valid you create a new one with the above call.
Step 3.1 Creating/Updating/Deleting a String Parameter Entry
The following screen shot shows how you create a String Parameter entry in the Partner Directory which can be looked up in the script step of the Partner Directory integration flow.
Figure 18: Creating Partner Directory Entry of Type String Parameter (make sure that you enter for “https//<receiver_iflmap>/cxf/receiver_1” the endpoint address of the Receiver_1 partner)
Make sure that you set the headers X-CSRF-Token, Content-Type, and Accept before you make the call:
Figure 19: HTTP Headers for the OData Call
You can also change the value of a StringParameter by executing a PUT call: Use the HTTP address
Another important entity type of the Partner Directory is the Authorized User. An Authorized User entry assigns a communication user to a partner ID. A communication user can only be assigned to exactly one partner ID, but a partner ID can have several communication users. When an Authorized User entry is created, automatically the role ESBMessaging.send is assigned to the user in the (worker node) application (iflmap), so that this communication user can execute inbound calls to an integration flow.
Precondition for Using Authorized User Entity:
The HTTP destination OAuthTokenDestination must exist. The destination is necessary for creating the user-role assigment (ESBMessaging.send). You can create this destination be executing the following steps.
Go to your account in the SAP BTP Cockpit and in the section Security select OAuth.
Click on Platform APIs tab then click on Create API Client button to create the Client credentials.
Choose the Authorization Managementoption and the scopes Read Authorization and Manage Authorization. We recommend that you enter an OAuth client description as well.
Save the client.
Copy the generated client ID and client secret, and save them locally.
Select Applications > Subscriptions tab and select in the table the tmn application
Now select the Destinations tab
Create a destination named OAuthTokenDestinationfrom the account's cockpit with the following properties:
{"Pid":"Sender_BASIC","User":"<your communication user>"}
to create an Authorized User entry for the partner “Sender_BASIC”. As communication user you can either use the Tenant Administrator user, or the Integration Developer user, or a separate user you created in the SAP Cloud Identity Provider.
For updating an Authorized User entry use a HTTP PUT method with address
https://<tmn>/api/v1/AuthorizedUsers('<your communication user>')
and body part
{"Pid":"<your updated partner ID"}
Additionally, for deleting an Authorized User entry use a HTTP DELETE method.
After you created the Authorized User entry, check in the SAP BTP Cockpit that the user-role assignment exists.
Step 4: Exchanging Client Certificate with the Receivers
We use client-certificate authentication for the calls from the Partner Directory integration flow to the receivers. Therefore, we have to exchange the client certificate with the receivers so that a certificate-user mapping can be performed on the receiver tenant.
Go to the SAP Cloud Integration WEBUI of your tenant where the Partner Directory integration flow is running and navigate to Monitor > Keystore
Choose the entry with the alias “hcicertificate” or “sap_cloudintegrationcertificate” and select the button for the entry actions. Choose “Download Certificate”.
This will download the X.509 Certificate for the key-pair.
This certificate is used for creating a certificate-user mapping in the receiver tenant. Now go to the SAP Cloud Integration WEBUI of the receiver tenant and navigate to Monitor > Certificate-To-User Mappings.
Add a certificate-user mapping by uploading the client certificate. As user name use “client_cert_user_pd_test“.
Create the roles “receiver_1.send” and “receiver_2.send” in the SAP BTP Cockpit of the receiver tenant, if they do not yet exist.
Assign the role “receiver_1.send” and “receiver_2.send” to the user “client_cert_user_pd_test” in the SAP BTP Cockpit of the receiver tenant.
Figure 20: Creation and Assignment of the roles “receiver_1.send” and “receiver_2.send” to the user “client_cert_user_pd_test” (which is the user from the certificate-user mapping)
Step 5: Call the Integration Flow
The communication user can now call the integration flow. We use PostMan to make a call to the Partner Directory integration flow using the endpoint URL https://<iflmap>/http/partner_directory_test where <iflmap> is the path of your iflmap node. Use as request body the following message.
Figure 21: Calling the Endpoint of the Partner Directory Integration Flow in PostMan (make sure that you use user-password authorization for the communication user)
If you have also configured in the Partner Directory the String Parameter entries for the “Receiver_2” partner ID (See Figure 12, just exchange “Receiver_1” by “Receiver_2” and use the address of “Receiver_2), then you can also execute a call to Receiver_2. Just use the following request message body:
If you make calls with OAuth using Client Credential Grant to the SAP Cloud Integration tenant, a user with the name “oauth_client_<client ID>” is logged in. In our example the user name is “oauth_client_CLIENT_SENDER_OAUTH”.
Therefore, we create an Authorized User entity with the user property value “oauth_client_CLIENT_SENDER_OAUTH”.
This binds the user “oauth_client_CLIENT_SENDER_OAUTH” to the partner ID "Sender_OAUTH" and creates an assignment of the user to the role ESBMessaging.send in the application iflmap.
You should check in the SAP BTP Cockpit of your tenant whether this assignment was successful.
Step 6.3 Calling the Partner Directory Integration Flow with OAuth Sender
Before we can call the Partner Directory integration flow with OAuth, we have to fetch the OAuth token. For this we need the token URI we looked up in step 6.1 in the Branding tab. We have to enrich the URI with the query part “?grant_type=client_credentials”; so the full URI has the format as follows:
Use PostMan to perform a POST HTTPS call to this URI with basic authentication where the client ID is the user and the secret is the password. This call returns the access token.
Figure 23: Creating the OAuth token (the value of the field access_token contains the OAuth token)
Finally, perform an HTTPS call to the endpoint URI
with the HTTP header with name “Authorization” and value “Bearer <access_token>”.
Figure 24: OAuth Call to Partner Directory Integration Flow
Step 7: Solution to the Security Problem – Sender Partner can Pretend to be Another Sender Partner – Partner Authorization
If more than one sender can call an integration flow endpoint, then you must ensure that a sender cannot pretend to be another sender. With the configuration so far, this is not ensured in our integration flow. For example, you can try to make a OAuth call as specified in Step 6.3 with the following message
Message 4: Message for Pretending to be a Sender Partner with ID “Sender_BASIC”
This call will succeed although we are using the OAuth user “oauth_client_CLIENT_SENDER_OAUTH” which is the user of the partner with ID “Sender_OAUTH”.
The user “oauth_client_CLIENT_SENDER_OAUTH” should only be able sending messages with SenderPartnerId value “Sender_OAUTH” and the basic authentication communication user should only be able sending messages with SenderPartnerId value “Sender_BASIC”. Otherwise we have a security problem.
To overcome this security problem, we must check that users can only sent messages which contain in the SenderPartnerId element the partner ID which is specified in the corresponding AuthorizedUser entry of the Partner Directory. We call this check Partner Authorization.
For the Partner Authorization, we make two changes in the Partner Directory integration flow.
We add the header name “SapAuthenticatedUserName” to the allowed headers, so that the logged-in user will be forwarded to the integration flow in this headerFigure 25: Add to the Runtime Configuration the Allowed Header “SapAuthenticatedUserName"
We enhance the script step with the Partner Authorization:
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import com.sap.it.api.pd.PartnerDirectoryService;
import com.sap.it.api.ITApiFactory;
def Message processData(Message message) {
def service = ITApiFactory.getApi(PartnerDirectoryService.class, null);
if (service == null){
throw new IllegalStateException("Partner Directory Service not found");
}
def map = message.getProperties();
// Partner Authorization
def headers = message.getHeaders();
def user = headers.get("SapAuthenticatedUserName");
if (user == null){
throw new IllegalStateException("User is not set in the header 'SapAuthenticatedUserName'")
}
def senderPid = service.getPartnerIdOfAuthorizedUser(user);
if (senderPid == null){
throw new IllegalStateException("No partner ID found for user "+user);
}
def senderId = map.get("SENDER_ID");
if (senderId == null){
throw new IllegalStateException("Sender ID is not set in the property 'SENDER_ID'")
}
// compare the two sender partner IDs!
if (!senderId.equals(senderPid )){
throw new IllegalStateException("User "+user+" is not authorized to send messages with ID "+senderId);
}
// RECEIVER_ADDRESS determination
def receiverId = map.get("RECEIVER_ID");
if (receiverId == null){
throw new IllegalStateException("Receiver ID is not set in the property 'RECEIVER_ID'")
}
def parameterValue = service.getParameter("ADDRESS", receiverId , String.class);
if (parameterValue == null){
throw new IllegalStateException("ADDRESS parameter not found in the Partner Directory for the partner ID "+receiverId);
}
message.setProperty("RECEIVER_ADDRESS", parameterValue );
return message;
}
Groovy Script 2: Enhanced Script with Partner Authorization
If you now try to send with the user “oauth_client_CLIENT_SENDER_OAUTH” a message with the SenderPartnerId value “Sender_BASIC”, you will get the error
“An internal server error occured: java.lang.IllegalStateException: User oauth_client_CLIENT_SENDER_OAUTH is not authorized to send messages with ID Sender_BASIC”
Further Reading
There are further blogs about the Partner Directory.