Skip to Content
Product Information
Author's profile photo Kumar Amar

SAP Cloud Integration – Automated Notification of Keystore Entries Reaching Expiry

Introduction

Cloud Integration Keystore Monitor allows a tenant administrator to manage the tenant keystore and its entries. A keystore contains entries uniquely identified by an alias where each entry has its own lifecycle. Renewal of an entry is important task to be done before expiry, else it will lead to message failure for productive scenarios using specific certificates/key-pairs entries. The tenant administrator can be notified for those entries which are about to expire, so that he can take in-time actions for renewal of the same.

Within keystore monitor, expired keys and certificates are highlighted showing expiration date. In addition, an Integration Flow can be modeled to get notifications via mail for entries reaching their expiry. This document provides steps to model a scenario triggered via scheduler which looks across all entries of the tenant keystore and sends a mail with information about those entries reaching their expiry.

Scenario Description

Cloud Integration provides various REST APIs with technical protocol as Open Data Protocol (OData) with which you can access data. These APIs can be consumed via https://<tmnUrl>/api/v1 where <tmn> is the address of the tenant management node. Here we will use API for accessing keystore entries via https://<tmnUrl>/api/v1/KeystoreEntries .Overall scenario looks as below:

Create an integration flow with Start Timer Event. Using Request-Reply step call OData APIs to fetch details of the tenant keystore entries via OData receiver channel. Fetch Alias Name and ValidNotAfter for entity KeystoreEntries. Below find the configuration of OData Receiver channel:

Make sure the Page Size field value is null since entries in a keystore are not so many in numbers.

The response of the OData call will be a file containing all keystore entries with their Alias & Validity date. Now add a General Splitter step to split using XPath /KeystoreEntries/KeystoreEntry and pass split entries to a Local Integration Process.

In Local Integration Process, define a Content Modifier and store the values of keystore entry Alias and Validity Time in a header.

Additionally, add a message containing Alias & Validity Time information about keystore entry in body of Content Modifier. This message will be send via mail notification. You can choose to customize this information as per your need.

Now add a script to fetch Validity Time from header and compare with current date. Output of script shall be number of days left for Keystore entry to expire. You can find a sample code below:

     def map = message.getHeaders();

     String getCertExpirydate = map.get(“CertExpiryDate”);

     Date CertExpirydate = new SimpleDateFormat(“yyyy-MM-dd“).parse(getCertExpirydate);

     Date dateNow = new Date(System.currentTimeMillis());

     long dateDiff = CertExpirydate.getTime() – dateNow.getTime();

     def daysToExpire = TimeUnit.DAYS.convert(dateDiff, TimeUnit.MILLISECONDS);

     message.setHeader(“daysToExpire”, daysToExpire);

Add a router step to route those entries whose expiry is in less than defined number of days (e.g. daysToExpire < 4) and send an email to specific participants informing them about the expiry.

For the example explained above, here is router configuration screenshot:

Screenshot%20of%20Router%20Step

Note: This might differ depending on the condition defined for your use-case or the variable defined either as Header/Property.

Assigned Tags

      47 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Toni Cunill
      Toni Cunill

      Hello
      Thanks a lot for your blog. it's perfect.
      I have created the package, deploy.. and everything is green.. But I don't receive any email with the alert...
      How can I verify in which part is not working properly?

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Toni

      Good to know that you were able to build and deploy the iflow. I hope you have understood that Alert mail will be generated only if there is any keystore entry reaching expiry (As per condition set) or already expired.

      Can you activate tracing referring to https://blogs.sap.com/2018/03/13/troubleshooting-message-processing-in-the-cpi-web-application/ and check if there are entries for the expiry condition.

       

      Thanks

      Amar

      Author's profile photo Toni Cunill
      Toni Cunill

      Hello Amar

      Thanks for you helping.
      I have obtained the error in Content Modifier

      Error Details
      org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[ID-vsa5107462-40927-1541369381630-22-5], cause: org.apache.camel.language.simple.types.SimpleParserException: expected symbol functionEnd but was eol

      What does it mean?. any idea?
      Thanks

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

       

      Hello Toni

      Seems some issue with conversion. Can you recheck Header configuration in Content Modifier step and you are using right Type for Header defined as well as body is correct.

       

      Thanks

      Amar

      Author's profile photo Toni Cunill
      Toni Cunill

      Hello Amar,

      Now, I have problems with script:

      Error Details
      javax.script.ScriptException: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: script__Script.groovy: 5: unable to resolve class SimpleDateFormat @ line 5, column 28. Date CertExpirydate = new SimpleDateFormat(���yyyy-MM-dd���).parse(getCertExpirydate)
      Somehting is wrong
      Thanks
      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Toni

      Kindly confirm if you copied the script code from above blog and pasted it. If this is the case, copy/paste sometime changes format for special characters and they are no more recognized during runtime when corresponding jars are created.

      Kindly write that specific line of code and recheck.

       

      Thanks

      Amar

       

      Author's profile photo Toni Cunill
      Toni Cunill

      Hello Amar,

       

      No I have obtained an other error, in my script:

      javax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: message for class: new__Script, cause: groovy.lang.MissingPropertyException: No such property: message for class: new__Script

       

      What does it means?

      Thanks

      Best regards

      Author's profile photo Hilmar Falkenberg
      Hilmar Falkenberg

      Hi Amar,

      any idea how to identify the certificates actually being used? Is there property/header available which tells you this?

      Thanks,
      Hilmar

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

       

      Hello Hilmar

      Do you mean any Where-Used list for certificates/Keystore entires from the entire set. In case yes, this is not possible as of now.

      Feel free to file your request to Mandy Krimmel regarding the same.

       

      Warm Regards

      Amar

      Author's profile photo Deepak Oturkar
      Deepak Oturkar

      Hi Amar,

       

      I am unable to open below document link you have provided,

       

      https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/DEV/en-US/a617d6f37ddc43db8eeb1279662ed5c2.html

      Please review & help.

       

      Regards,

      Deepak

      Author's profile photo Deepak Oturkar
      Deepak Oturkar

      Hi Amar,

      The error is 403:You don't have rights to view this page.

       

      Regards,

      Deepak

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

       

      Hello Deepak

      Sorry for wrong link. Here is the correct one: https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/a617d6f37ddc43db8eeb1279662ed5c2.html. Can you recheck.

       

      Thanks

      Amar

      Author's profile photo Hilmar Falkenberg
      Hilmar Falkenberg

      similar thing for the CertificateUserMappings

      Author's profile photo Swati Kaushal
      Swati Kaushal

      Hi Amar,

      Can you please add more information on last content modifier which you used in local integration process.

      Regards,

      Swati

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Swati

      The Content Modifier used in Local integration process is to read each Certificate/Keypair and store the same in header/property. In addition use this to create body of the mail being sent to Administrator so that Administrator easily know which entry is reaching expiry and accordingly take appropriate actions for renewal of the same.

       

      Amar

      Author's profile photo Anil Yakkali
      Anil Yakkali

      Hello Amar,

       

      While calling this Entity, I am receiving 403 Forbidden error. Do I need any additional roles to access this entity?

      Regards,

      Anil

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Anil

      You would need AuthGroup.Administrator role on the tenant to call the APIs or deploy a credential with a user having this role and then use this credential in your flow.

       

      Thanks

      Amar

      Author's profile photo Swati Kaushal
      Swati Kaushal

      Hi Amar,

      Thank you for your helpful blog, everything working fine for me. Right now with the above approach i am getting four mails if there are four items expires in same date. I am looking to send only one mail for all four expire items. Can i achieve this with help of Gather with splitter ? or can you suggest what would better approach.

      Thanks,

      Swati

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Swati

      Straight forward using Gather & Join would not be enough since Gather is meant for collecting data coming from multiple routes.

      Easiest would be store/append certificate in SFTP and then have another flow which pulls data from SFTP and send it collectively to mail receiver.

       

      Thanks

      Amar

      Author's profile photo Lukasz Pieczara
      Lukasz Pieczara

      Works like a charm!

      Author's profile photo Shubham Srivastava
      Shubham Srivastava

      Hi Kumar Amar ,

       

      While running the script , i got the below error.

      My Groovy script is as below

       

      Details from Content Modifier is as below:

      Could you please have a look and help me in this.

       

      Thanks & Regards

      Shubham

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hi Shubham

      Actually in my blog description, I write as:

      In Local Integration Process, define a Content Modifier and store the values of keystore entry Alias and Validity Time in a header.

      However you have defined Property in Content Modifier and hence you need to change your script code instead of def map = message.getHeaders(); 

      to

      def propertiesMap=message.getProperties();
      Hope it helps !
      Thanks
      Amar
      Author's profile photo Shubham Srivastava
      Shubham Srivastava

      Hi Kumar Amar ,

       

      Thanks for your response.

      I am again receiving the below error :

      Error Details
      java.lang.NoSuchMethodException: No signature of method: java.lang.Long.–() is applicable for argument types: (java.lang.Long) values: [1601041902697] Possible solutions: is(java.lang.Object), or(java.lang.Number), abs(), abs(), any(), wait(long)
      Could you please now help me in this.
      Groovy script is not at all working.
      Thanks
      Shubham
      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Shubam

      Kindly check someone at your end for Groovy script code. I used the below code and it works for me.

      import com.sap.gateway.ip.core.customdev.util.Message;
      import java.util.HashMap;
      import java.text.SimpleDateFormat;
      import java.util.Date;
      import java.util.concurrent.TimeUnit;
      import groovy.json.JsonSlurper;
      import java.util.HashMap;
      import java.io.IOException;
      import java.io.InputStream;
      import java.nio.file.Files;
      import java.nio.file.Paths;
      import java.nio.file.StandardOpenOption;
      import java.util.Map;
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      import java.util.concurrent.Callable;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import groovy.json.JsonOutput

      def Message processData(Message message) {

      //Headers
      def map = message.getHeaders();
      String getCertExpirydate = map.get("CertExpiryDate");
      Date CertExpirydate = new SimpleDateFormat("yyyy-MM-dd").parse(getCertExpirydate);
      Date dateNow = new Date(System.currentTimeMillis());
      long dateDiff = CertExpirydate.getTime() - dateNow.getTime();
      def daysToExpire = TimeUnit.DAYS.convert(dateDiff, TimeUnit.MILLISECONDS);

      message.setHeader("daysToExpire", daysToExpire);

      return message;
      }

       

      Thanks

      Amar

      Author's profile photo Shubham Srivastava
      Shubham Srivastava

      i am getting issues with handling of long in the groovy script.

       

      is there any way to resolve this??

       

      Thanks
      Shubham

      Author's profile photo Poushali Bhandari
      Poushali Bhandari

      Hi Shubham Srivastava,

      Sometimes, It might occurs due to copy paste of the code, try to delete the minus(-) sign from this line and type again.

      long dateDiff = CertExpirydate.getTime() – dateNow.getTime();

      It will solve your issue.

      Thanks,

      Poushali Bhandari

      Author's profile photo Shubham Srivastava
      Shubham Srivastava

      Hi ,

       

      Could you please provide me with the Router conditions to be put in the router steps.

       

      Thanks

      Shubham

      Author's profile photo Patrick Schaaf
      Patrick Schaaf

      Hi,

       

      I would be also intrested in the Router Conditions!

      Maybe you could also add them to the blog via screenshot

       

      Thanks

      Patrick

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hi Patrick

      I added it today.

       

      Thanks

      Amar

       

      Author's profile photo Patrick Schaaf
      Patrick Schaaf

      Thanks Kumar Amar I have already found an example in Mandys Blog 😉

      Author's profile photo Poushali Bhandari
      Poushali Bhandari

      Hi Kumar Amar,

      It's a great blog.

      Similarly, Is it possible to trigger the public key expiry notification from the pubring deployed as security Material in the CPI Tenant? Pubring contains around 20 public keys, We have a requirement to notify if any of the key is going to expire.

      Thanks in advance,

      Poushali Bhandari

       

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hi Poushali

      Thanks for your inputs. Unfortunately this is not possible. I will inform about your requirement to my development team.

       

      Thanks

      Amar

      Author's profile photo Harish Desai
      Harish Desai

      Is this solution valid for cloud foundry as well. As there is no certifiacte to user mapping for cloud foundry, is there any way we can use this solution in cloud foundry tenants.

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Harish

      Yes this is valid for getting notification for Certificates reaching expiry within the Keystore.

      As anyways there is no concept of Certificate to User Mapping in Cloud Foundry, this is not a valid query as such.

      Author's profile photo Debtirtha Das
      Debtirtha Das

      Hello Kumar Amar,

       

      does this solution work for certificates, directly deployed in iFlow? I tried CertificateUserMappings and KeystoreEntries APIs, none of them seems return certificate details, which directly deployed in iflow.

      Thanks in advance.

      Regards,

      Deb

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Debtirtha Das 

      I didn't get what you meant by certificates directly deployed in Integration Flows.

      Certificates from CertificateUserMappings and KeystoreEntries are used in IFlow but actually deployed on the tenant and not in IFlow.

      In case you are looking for solution to get notification of expired CertificateUserMappings, you can refer https://blogs.sap.com/2019/03/01/sap-cloud-platform-integration-automated-notification-for-client-certificates-reaching-expiry/ and for Keystore Entries, this blog suffice.

       

      Thanks

      Amar

      Author's profile photo Debtirtha Das
      Debtirtha Das

      Hi Amar,

      For example, if we add a client certificate in an inbound SOAP channel, I do not see that certificate added to keystore. Though I read that this is not SAP recommened process for client certificates.

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Debtirtha Das

      When you do inbound authentication via Client Certificates, you add certificate in the Sender Channel and this doesn't need to be part of the CPI Keystore as such.

      Only when you do outbound authentication using Client Certificates, you need to add respective Key-pair in Keystore and refer it via the alias name in the receiver channel.

      Also I am not sure how does your query relates to this blog but anyways hope its clarified.

      For inbound and outbound authentication, refer below blogs:

      https://blogs.sap.com/2017/06/05/cloud-integration-how-to-setup-secure-http-inbound-connection-with-client-certificates/

      https://blogs.sap.com/2017/06/19/cloud-integration-how-to-setup-secure-outbound-http-connection-using-keystore-monitor/

      Thanks

      Amar

      Author's profile photo Xavier San Sebastián
      Xavier San Sebastián

      Hi people!

      Nice entry Kumar. The governance from outside SAP BTP Integration Suite is a little weird. By the way, I have the doubt if this connection to the oData service consumes one of the pool of the licensed connections.

      I supose that no, but I've havent any information about it. Do you know it? Have you ever had any trouble?

       

      Thank you so much

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hi Xavier

      Sorry I missed to see your query and only saw today. All connection here mentioned are within Cloud Integration and nothing outside BTP.

      Or may be I didn't get your question. Can you give more details ?

       

      Warm Regards

      Amar

      Author's profile photo Hiko Watanabe
      Hiko Watanabe

      Hello Kumar,

      I am trying to enable the notifications of expiring certificates in the Cloud Platform Integration (CPI).

      I read through your blog.   When you go to create an iFLOW with "Start Timer Event", is there a particular Package or a Base Package I need to select?

      Your first screen shot with the "Adapter Specific" configuration looks like it's a General OData package.   Where do I find this to get started?

       

      Thanks for your help.

      Hiko Watanabe

       

       

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Hiko

      As this is custom flows you can create the integration flow in any of your package created in your Cloud Integration tenant. And yes it uses Standard OData adapter which is part of Cloud integration feature.

      To get started create an Integration Package in your design workspace of cloud integration tenant and then create an integration flow to get started.

       

      Warm Regards

      Amar

       

      Author's profile photo Dominik Lange
      Dominik Lange

      Hi Kumar Amar

       

      first of all thanks for this helpfull blog post. Is it also possible to call this API for keystore credentials with OAuth authentification which can be provided by process integration? Then I do not have the dependencies to any user / assigned roles in this tenant.

      Thanks

      Best regards

      DL

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Hello Dominik

      Yes of course instead of using Basic Auth, you can use OAuth Credential and call the APIs. Refer https://help.sap.com/docs/CLOUD_INTEGRATION/368c481cd6954bdfa5d0435479fd4eaf/20e26a837a8449c4b8b934b07f71cb76.html for more information.

       

       

      Thanks

      Amar

       

      Author's profile photo Dominik Lange
      Dominik Lange

      Hi Kumar Amar

       

      thanks for the hint. Access via OAuth to CPI is working fine. For me better option because we have no dependencies now between user and CPI access / roles.

       

      Thanks

       

      best regards

      Dominik

      Author's profile photo Kumar Amar
      Kumar Amar
      Blog Post Author

      Perfect, glad that it works for you and I could help you.

      Author's profile photo Sudhir Yesu
      Sudhir Yesu

      Hi Kumar Amar

      I have consumed the OData service via "https://<tmnUrl>/api/v1/KeystoreEntries". It was working fine a week before. But now getting the below error. Please assist me to resolve this.

      Error Details
      com.sap.gateway.core.ip.component.odata.exception.OsciException: Attempted read from closed stream., cause: java.io.IOException: Attempted read from closed stream.
      Thanks,
      Sudhir Yesu