Skip to Content
Technical Articles
Author's profile photo Carlos Roggan

SAP Event Mesh supports mTLS [1]: manual request with Postman

With other words:

How to configure Postman
to use client certificate
to fetch JWT token
for Event Mesh API

With less words:

let’s try
the mTLS scenario

 

This tutorial is about SAP Event Mesh (aka SAP Enterprise Messaging) running on SAP Business Technology Platform (SAP BTP, aka SAP Cloud Platform) in Cloud Foundry environment.
We use mTLS instead of basic authentication, when connecting to the REST API provided by Event Mesh.

Quicklinks:
Quick Steps
Sample Code

Content

0.   Prerequisites
00. Preparation
1.   Event Mesh
2.   Certificate & Key
3.   Postman
4.   Optional: Try API request
5.   Troubleshooting
6.   Configuration Options
7.   openssl
A    Project Files

Introduction

This blog post is a detailed hands-on description for simple-minded users.
The simple introduction:
In Cloud Foundry, when binding an application to an Event Mesh service instance, we get the credentials of Event Mesh in the binding.
Credentials for what?
Event Mesh provides API for programmatically sending messages or viewing/creating queues, etc
As usual, such an API is protected and requires authentication.
Typically, OAuth 2.0 is used for protection.
So if we want to use that API, we create a service instance and bind it to our app.
Like this, we get the credentials which we need to call the Event Mesh API.
These credentials are used to fetch a JWT token, which we then can use to call the API.
How do these credentials look like?
Usually, the JWT token is fetched by authenticating via user/password, represented by clientid/clientsecret.
And?
Today, we’re learning how to authenticate with certificate instead of user/pwd.

Which Certificate?
We know certificates from https-URLs, where a web page claims to be safe by presenting a certificate to us.
This is called TLS (Transport Layer Security, replacing SSL, Secure Sockets Layer) and ensures secure communication via encryption.
And?
In case of mTLS (mutual TLS), it is us who have to present a certificate to the server (as well).
Why?
Because it is safe.

How does it work?
We, as a client, get the certificate from Event Mesh binding (instead of clientid/secret).
We then use the certificate to fetch a JWT token.
That’s already all.
Then why do we need a blog?
Because we need to learn few steps in order to make Postman do what we want.

Recap
We use certificate instead of basic authentication.
We learn how to get the certificate.
We learn how to configure Postman.

Note:
The next blog post shows how to switch an existing application to mTLS.

0. Prerequisites

We need access to SAP BTP productive landscape.
We need the capability to create a service instance of Event Mesh.
We need postman or a similar REST client tool to fire REST requests.
We don’t need expertise in security-related stuff.
There’s a silly questions’n’answers blog post, recommended only if you aren’t familiar at all with mTLS and credential rotation.
Note:
Security experts are not allowed to continue reading…. (too dummy stuff ahead)

00. Preparation

We create a project folder c:\mtls containing following files:

c:\mtls
config-messaging.json
cert.txt
key.txt

See Appendix for file content.

1. Event Mesh

We need an instance of Event Mesh service.
We want the service instance to support mTLS.
As such, we need to add the special configuration parameter, which tells Event Mesh to not use the default setting, but to use x509 certificate.
So we add the following snippet (on root level):

. . .
"xs-security": {
   "oauth2-configuration": { 
      "credential-types": ["x509"]
   }
}

See Appendix for file content.

We can see that multiple credential types are possible (see docu).
For the purpose of this tutorial, we only want one (certificate, not clientsecret).

To create the service instance:
cf cs enterprise-messaging default mtlsMsg -c config-messaging.json

Today’s tutorial is meant for manual request with Postman, so we don’t deploy any app.
As such, we don’t receive the credentials in the binding.
So we need to create a service key in order to obtain the credentials:
cf csk mtlsMsg sk

Note:
See blelow for more config options.

2. Certificate

Nest step is to obtain the credentials.

2.1. View credentials

We run the command to view the content of the service key:

cf service-key mtlsMsg sk

The output is very lengthy, due to the certificate.
Nevertheless, we need to find the uaa-section which contains the following relevant properties for us:

uaa:{
certificate:”…”,
certurl:”…”,
clientid:”…”,
key:”…”
}

In my example:

We now copy the values of properties certificate and key into our 2 files, cert.txt and key.txt, respectively.

2.2. Convert files

We open the files in any text editor and have a closer look.
Let’s start with key.txt, as it is smaller.
The content is a long string which contains \n for each line break:

Such string can be understood by software, but not by tools like postman.
As such, we need to convert it into the usual format of cert and key files.
Means, we need to replace the \n with real line breaks.

1. Add line breaks.
So now we do the terrible manual work of adding a real line break after each \n.
The result looks like this:

2. Remove \n:
Once we see the proper format, we can go ahead and delete the \n characters at the end of each line:

That’s it.

Note:
Linux users might wish to use this command:
awk ‘{gsub(/\\n/,”\n”)}1’ key.txt | tee key_new.txt

3. Next step:
We do the same procedure with the certificate.
This will be even harder, as the certificate is notably longer.
It contains not only our client certificate, but the whole certificate chain up to the root certificate is required. In our case, there are 3 certificates.
We need the whole chain in our cert file.

Why is this format required?
Because more beautiful…
Haha
Honestly, I don’t know, it is specified in the RFC, see here for instance.

3. Postman

We’re done with the preparation steps, now we can go ahead, open Postman or similar REST client.
How do we configure a request which uses certificate instead of basic auth?

3.1. View values in service key

From the service key
cf service-key mtlsMsg sk
we need the property values of clientid and certurl

Note:
The certurl is slightly different from the url property:
https://subdomain.authentication.cert.eu10.hana.ondemand.com

3.2. Upload certificate to Postman

Other than expected, the certificate is not attached to a request, it is configured on postman itself.
To do so, we open the global settings.
Can be found in the main menu via File->Settings or via the settings icon in the upper toolbar.
In the settings dialog, we switch to the “Certificates” tab and press “Add Certificate”.
Then we enter the host from the certurl, means we remove the https:// part.
E.g.
subdomain.authentication.cert.eu10.hana.ondemand.com
And we upload our cert.txt and key.txt files

After pressing “Add” we can close the dialog.
That’s already almost the last trick of this tutorial.

3.3. Configure Request

Coming to the request itself, one more hint will be helpful.

The URL is composed by adding the segment  /oauth/token to the certurl property of service key
Example:
https:// subdomain.authentication.cert.sap.hana.ondemand.com/oauth/token
Note:
Again, we use the URL containing the .cert. segment.
This is the promised helpful hint.
That’s all?
That’s all.

Now we choose POST as HTTP verb and then configure the request body as follows:
We select “x-www-form-urlencoded” and enter the following params:
client_id: the value copied from service-key
grant_type: client_credentials
response_type: token

Any Headers?
– no
What about Authorization?
– no Auth

Recap:
To configure postman,
we upload cert and key in global settings
POSt request to certurl
request body same as normal client-credentials flow

3.4. Fire Request

Finally we can press “Send” and we should get the desired response containing the JWT token:

If we open the Postman Console (e.g. Menu->View->Show Developer Console), we can see that the request has been configured with Client Certificate:

 

 

 

 

If we expand the node, we can see that postman has found the proper certificate entry by comparing the request URL with the configured certificate host:

 

 

 

 

Note:
For the sake of information, find below the curl command:
curl –cert cert.txt –key key.txt -X POST https://<certurl>/oauth/token -d ‘grant_type=client_credentials&client_id=<client-id>’

4. Optional: API Request

Now that we have the JWT token, we can use it for executing a request to the REST API of SAP Event Mesh.
Let’s choose a simple example:
We fire a request to see the existing queues.
Note:
Since we created a new messaging instance, it is empty, without any queues, and if we want to see a result in our postman, we need to create a queue.
But it is optional, we can enjoy a successful result, even if it is empty.

See documentation about REST API.

To compose the request, we need the base URL which we find in the service key at

{
management [{
uri

In my example:
https://enterprise-messaging-hub-backend.cfapps.eu10.hana.ondemand.com

We need to append the following segments:
/hub/rest/api/v1/management/messaging/queues
(Info taken from docu)

The request is a simple GET request with above URL and Authorization Type as “Bearer Token” with value as the JWT token we fetched above:

The result is an empty array, or an array containing the queues from our messaging client.
Starting from here, we can go through the mentioned docu and continue exploring the REST API to create/delete queues, send/consume messages, etc.
And from time to time, we’ll need to fetch a new JWT token with is now cool – as it is based on mTLS.
Have fun!

5. Troubleshooting

If you get error  X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY that means that the chain of certificates is not complete.
The cert file must contain the full chain up to the root certificate.
Only the client certificate is not enough.

If you get ALERT_HANDSHAKE_FAILURE then this means that the certificate is not valid – or it is not properly configured.
Check in the Postman console if the client certificate has been used:

The screenshot shows that the request has been sent without certificate.
Make sure that you entered the certificate host properly, without copy&paste error.

If the certificate has expired, the error looks as follows:
X509_V_ERR_CERT_HAS_EXPIRED

6. Configuration Options

The following options can be passed when creating a service key:

{
   "xsuaa": {
      "credential-type": "x509", 
      "x509": {
         "key-length": 2048, 
         "validity": 7, 
         "validity-type": "DAYS"
      }   
   }
}

key-length
This parameter allows to set the length in bytes for the private key, which will be generated.
Possible values are 2048 (default) or 4096

validity
Here we can set the number of time units in validity-type,
This is the value which belongs to the next setting.
So if the type is “DAYS” then the validity would be 7 days
Default is 7

validity-type
Value can be DAYS, or MONTHS or YEARS

To create a service key with JSON-params:
cf csk mtlsMsg sk -c config-servicekey.json

7. Optional: decode them

It is useless, but it is easy.
So let’s try to view the content of our 2 files.
To do so, we use the world-famous master command line tool openssl.
You have it already on your system, if you have Git. You can just open Gitbash and run below commands.
There’s also openssl for windows available for download.
If you don’t like command line, you can find tools in the internet (e.g. sslchecker) which might not always be recommended, but will display the content of the certificate in user-friendly way in the browser.

7.1. View content of certificate file

From our project folder, we run the following command:
openssl x509 -noout -text -in cert.txt

The openssl command uses the x509-tool which offers a variety of functions to manage certificate, e.g. sign and display certificates.
Options:
-text
Write the decoded content to the console
-noout
Hide the encoded content.
We can view the encoded content anyways in our cert file or in the service key

The result is the certificate information (which is even less interesting that this blog post):

What we can see is the validity of the certificate and in fact, it is 7 Days (default validity in Event Mesh configuration).
We can see the details about the issuer (the SAP CA)
And we can see the details about our certificate itself, in the subject. Name is generated guid.

About the abbreviations:

C Country
L Locality
O O Organization
OU Organizational Unit
CN Common Name
and
CA Certificate Authority (trusted root)
DN Distinguished Name
Subject Field contains CN, identifying the bearer of the certificate, e.g. domain name of a website

In an extension entry, we can also see where to access the CRL.
CRL stands for Certificate Revocation List.
This is a list of certificates that are not trustworthy. An interesting list.
In my example, at SAP BTP, in my landscape, it looks as follows:

And, in my example, it is empty.
Good 😉

7.2. View content of key file

Coming to the private key file….
But it is secret…?
psssst … yes, so we can continue only if nobody watching our screen
only my cat is watching…. but he is anyways in sleepy mood
We can execute the following command
openssl rsa -noout -text -in key.txt

Result:

Beautiful.
We can see that it displays the key-length 2048 which we learned is the default setting when configuring Event Mesh instance.

The openssl command uses the rsa-function which is used to handle keys.
Again, the -text option is used to print the private key components in plain text and the -noout is used to hide the encoded content

Summary

Today we’ve learned that Event Mesh can be configured to support mTLS for delivering JWT tokens.
And we’ve learned how to use Postman in that scenario.

Links

SAP Event Mesh landing page.
Event Mesh docu about JSON params.
Event Mesh documentation about REST API.
Specification RFC about PEM and representation format in single lines.
Openssl documentation.
Postman documentation for working with certificates.

Quick Steps

To support mTLS, we create service instance with following snippet on root level:

"xs-security": {
   "oauth2-configuration": { 
      "credential-types": ["x509"]

In binding, the certificate and the private key can be found, to be sent when fetching JWT token.
When using Postman for fetching JWT token, we have to change format of cert and key:
Replace all \n with line break.
Certificates are uploaded in Postman via global settings.

Appendix: Project Files

config-messaging.json

{
  "emname": "mtlsxsappname",
  "namespace": "my/mtls/test",
  "version": "1.1.0",
  "options": {
      "management": true,
      "messagingrest": true,
      "messaging": true
  },
  "rules": {
      "queueRules": {
          "publishFilter": [
              "${namespace}/*"
          ],
          "subscribeFilter": [
              "${namespace}/*"
          ]
      },
      "topicRules": {
          "publishFilter": [
              "${namespace}/*"
          ],
          "subscribeFilter": [
              "${namespace}/*"
          ]
      }
  },
    "xs-security": {
        "oauth2-configuration": { 
            "credential-types": [
                "x509"
            ]
        }
    }
}

config-servicekey.json

{
   "xsuaa": {
      "credential-type": "x509", 
      "x509": {
         "key-length": 2048, 
         "validity": 7, 
         "validity-type": "DAYS"
      }   
   }
}

cert.txt

-----BEGIN CERTIFICATE-----
MIIFuzCCA6OgAwIBAgIRAN366loMmUZLoL/eycSJO0gwDQYJKoZIhvcNAQELBQAw
eTELMAkGA1UEBhMCREUxDTALBgNVBAcMBEVVMTAxDzANBgNVBAoMBlNBUCBTRTEj
MCEGA1UECwwaU0FQIENsb3VkIFBsYXRmb3JtIENsaWVudHMxJTAjBgNVBAMMHFNB
CskAWv4edX4cMQDxb1Pto5mDpITSBeksnfOK/mOXsPvd+B2l4fwhG1tHrtKCB4eT
gTolnooxzDTm1UUB6FU/zU38VeibWt/aUhbk6zuoeA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIGYDCCBEigAwIBAgITcAAAAAR7yX5CNr+FlgAAAAAABDANBgkqhkiG9w0BAQsF
ADBNMQswCQYDVQQGEwJERTERMA8GA1UEBwwIV2FsbGRvcmYxDzANBgNVBAoMBlNB
UCBTRTEaMBgGA1UEAwwRU0FQIENsb3VkIFJvb3QgQ0EwHhcNMjAwNjIzMDg0MDQz
1ZXJjSjTJ0Rhia2/ZtZNi/YgcRbYXFH7AOajdcqnpkOUyqd/Eb4MDZWYksZY/0+6
nRvEvg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFZjCCA06gAwIBAgIQGHcPvmUGa79M6pM42bGFYjANBgkqhkiG9w0BAQsFADBN
MQswCQYDVQQGEwJERTERMA8GA1UEBwwIV2FsbGRvcmYxDzANBgNVBAoMBlNBUCBT
RTEaMBgGA1UEAwwRU0FQIENsb3VkIFJvb3QgQ0EwHhcNMTkwMjEzMTExOTM2WhcN
LvHPhNDM3rMsLu06agF4JTbO8ANYtWQTx0PVrZKJu+8fcIaUp7MVBIVZ
-----END CERTIFICATE-----

key.txt

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAwPblNdU2bkG/RJd32pef8KKoaGYEs5yhynO7bzL5BJi6ELf5
UkdBqd2U0oXDLdUwq9nhFRf5gsLucxZBuDkYAuBsUmyGKIZxVsijh+yZOXEWPYmi
8GO934QDAKaLRLSt8eMlhHBIyD158Ms/seE/IQIW1TvavURFqjuDqgLkOtDrv7IP
fWNVAoGARIuG27XjgEm4NXm4L4vsqGS/cIMjZWneFSeTrwLFOCSWNjNurXHpzHgv
H2LfFuDvm0bSMbiFobJMYdNVrtyRO8pBAJJtZw9MBAT52jN8sCFX7vrL54D9X/sk
RaDgWI5ki+Wj5PbzeBJkxNUB9KS8qX7jy37CIYSmwrsB89vCf74=
-----END RSA PRIVATE KEY-----

Assigned Tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Roger Ni
      Roger Ni

      Hi,

       

      I came across the error as follows,

      401 Unauthorized: TLS handshake failed.
      ssl_c_err: X509_V_ERR_CERT_HAS_EXPIRED (10)
      ssl_c_ca_err: X509_V_OK (0)
      ssl_c_verify: X509_V_ERR_CERT_HAS_EXPIRED (10)

      Could you please tell what might be the root cause?

       

      BR, Roger

      Author's profile photo Carlos Roggan
      Carlos Roggan
      Blog Post Author

      Hi Roger Ni ,

      the error message gives a good hint: the certificate has expired.
      You can check the expiration date by decoding the cert
      I've given description somewhere in my blogs.

      To fix it: just generate a new cert by unbind/rebind the service instance

      Kind Regards,
      Carlos