Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
vanessadayanc
Explorer
Hello SAP Community,

in the context of a migration project from SAP CPI Neo to SAP IS Cloud Foundry (CF) Environment, I was searching for a solution to generate a notification for administrators about expiring Service Keys (Certificates) in SAP BTP CF via E-Mail. I did find some solutions for certificates in keystore, but no solution for the Service Keys - so I created one in form of an iFlow.

Background


When proceeding a migration from SAP CPI in Neo Environment to SAP Integration Suite in Cloud Foundry, you will find several differences between the two systems. There are already a lot of Blogs and Guides with detailed information about the differences and best practices for Migrating from the Neo Environment to the Multi-Cloud Foundation (Cloud Foundry and Kyma), but I would like to focus on mainly one point:

For SettingUp Inbound HTTP Connections for Integration Flow Processing in SAP Cloud Foundry Environment it is necessary to create a Service Instance and Service Key for Inbound Authentication (SAP Help). Depending on your use case you can create three different types of Service Keys:

  1. ClientId/Secret

  2. Certificate

  3. External Certificate


For further information please check out help.sap

If your use case requires External Certificate e.g. for Inbound Authentication from SAP ERP-Systems to SAP Integration Suite, you can add a sender client certificate (provided by sender administrator) to service key and maintain the validity date (validuntil).


In order to guarantee a constant communication, it is important to renew the certificates before the expire.

 

Getting Started:


First of all I searched for a possibility to retrieve the Service Key information by calling CF-API endpoint. Depending on your landscape you can find the Endpoint of your Cloud Foundry API in one of your SubAccounts.

 


To get the Service Key information it is necessary to use the cloud_controller API, the documentation for V3 can be found here (V2 ist already deprecated).

Authentication:


The Cloud Foundry V3 API is secured using OAuth 2. Clients are expected to present a valid bearer token via HTTP header, that can be obtained from the Cloud Foundry UUA server or via CF CLI.

The only solution that worked in my testings were based on the following post:


 

I tried different versions to get a valid Authorization token for the CF-API but the solution below was the only one that worked for me using Postman.

SAP Integration Suite provides three Options vor OAuth2 Security Materials: OAuth2 Client Credentials, OAuth2 SAML Bearer Assertion, OAuth2 Authoriation Code. None of them will work with the grant_type password. One way to get a token is to create the necessary Authorization data for a GET-Request via groovyscript in CPI:

  1. Create two different Client Credentials as Security Material:

    1. CF_API_Username : Contains Username and Password of a SAP BTP User (Only use technical Users here!)

    2. CF_API_ClientID: User = cf and leave the password empty



  2. Create a iFlow with a Start Timer and a Content Modifier

    1. Message Header: Content-Type = application/x-www-form-urlencoded

    2. Exchange Property: ApiUserCredentials = {{CF_API_Username}} for external configuration



  3. Create Script Step:


import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import com.sap.it.api.ITApiFactory;
import com.sap.it.api.securestore.SecureStoreService;
import com.sap.it.api.securestore.UserCredential;

def Message processData(Message message) {

//get User from Configuration
def map = message.getProperties();
String user = map.get("ApiUserCredentials");

//service to get the credentials
def service = ITApiFactory.getApi(SecureStoreService.class, null);

//get user credential
def userCred = service.getUserCredential(user);
if (userCred == null){
throw new IllegalStateException("No User credential found for alias" + user);}

//HTTP Parameters value
String grant_type = "password";
String username = userCred.getUsername();
String password = new String(userCred.getPassword());

//Query
def query = "grant_type=" + grant_type + "&username=" + username + "&password=" + password;

message.setBody(query);

return message;

}

(Based on post)

4. User HTTP-Adapter to get a Token


You will get back a response in the following format:



{
"access_token": "<Token>",
"token_type": "bearer",
"id_token": "<id_toke>",
"refresh_token": "<refresh_token<",
"expires_in": 1199,
"scope": "openid uaa.user cloud_controller.read password.write cloud_controller.write",
"jti": "<jti>"
}

5. Use a further script to extract the token from the response body and set it as Authorization header



import com.sap.gateway.ip.core.customdev.util.Message;
import groovy.json.*

def Message processData(Message message) {

def json = new JsonSlurper().parseText(message.getBody(String));
message.setHeader("Authorization", json.token_type + " " + json.access_token)
message.setBody()

return message;
}

 

Get Service-Key-Details form API


The necessary objects can be found in the entity "service_credential_bindings". To List all service_credential_bindings you have to use the following definition and Parameters:

GET  /v3/service_credential_bindings

Query parameters






















Name Type Description
service_instance_guids list of strings Comma-delimited list of service instance guids to filter by
type list of strings Type of credential binding to filter by. Valid values are: app or key

You will find the service_instance_guids in the details of your service_instances.

  1. Use HTTP-Adapter to get a list of service_credential_bindings



You will receive a list of resources from the type "key". As they do not contain the field "validuntil" it is necessary to check the details of each Service Key. The URL to check the details is already provided for each resource in the body
[..]
"links": {
"self": {
"href": "https://host/v3/service_credential_bindings/<guid>"
},
"details": {
"href": "https://host/v3/service_credential_bindings/<guid>/details"
},

7. Convert and Split the messages on XPath "//resources"


8. For each generated message Call a local Integration Process that extracts the URL of the Endpoint for the Service Key-Details and send a HTTP-Request


As the Authorization Token has a very long validity it is not necessary to generate a new Token and add them to the headers, so you can reuse the token, that was already set as Authorization header. If you run into issues here you may have to retrieve new Authorization Token.



You will receive all necessary informations for each Service Key



"certificatedetails": {
"issuerdn": "CN=DigiCert TLS RSA SHA256 2020 CA1,O=DigiCert Inc,C=US",
"subjectdn": "<subjectdn>",
"validuntil": "2023-05-03T23:59:59.000Z",
"serialnumber": "<serialnumber>"
}

9. Extract the "validuntil"-Value in a Content Modifier


10. Use a script the check the days-to-Expiry and set them as property


11. Create a Router with a configurable days-to-Expiry



12. Use a Content Modifier to create a Mail-Body and user Mail-Adapter to send information Mail to Administrators


 

So the result could look like this:

 


 

Resume


In this post I tried to provide a short explanation to create an iFlow to generate e-mail notifications for expiring Service Keys in different Service Instances. This is just one way that worked for me but if anyone has a better solution - especially how to get a Token for CF-API I'm openminded for improvements. Many thanks!

 

 

 

 

 
12 Comments
Labels in this area