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: 
former_member273171
Participant
0 Kudos

Disclaimer: This blog post is only applicable for the SAP Cloud SDK version of at most 2.19.2. We plan to continuously migrate these blog posts into our List of Tutorials. Feel free to check out our updated Tutorials on the SAP Cloud SDK.



Note: This post is part of a series. For a complete overview visit the SAP Cloud SDK Overview.

When you build a microservices based application in the cloud, you need to make sure that the information regarding the user context, as well as the tenant context (in case of the multi-tenant application) is preserved when setting up the communication between microservices.

In this blog post, we will take a look at the synchronous microservices communication via REST APIs in SAP Cloud Platform, Cloud Foundry. We will discuss the components of the SAP Cloud SDK that can be used in this case. Beware that the feature described in this blog post is available since the SDK version 1.9.2. Please, refer to the corresponding release blog for the release overview and how you can upgrade in case you are using the older SDK version.

You can find the source code that will be used as a demo example in this blog post on GitHub.

In case you have questions or suggestions, reach out to us on Stackoverflow with the sap-cloud-sdk tag. Our development team is actively monitoring this tag and is making sure that the questions and requests are addressed properly. You can use this opportunity to share your experiences and to get advice from a broader Stackoverflow community. Of course, we are happy to receive your questions and suggestions in the comments to our blog posts, as well.


Goal of This Blogpost


Microservices based architecture is widely used in cloud development projects. There are a lot of available sources  that explain in what cases this architecture pattern should be applied. Pivotal explains microservices as "an architectural approach to developing an application as a collection of small services; each service implements business capabilities, runs in its own process and communicates via HTTP APIs or messaging". The main motivation factors for building microservice based solutions are the increase of teams agility, quick responsiveness to customer needs, and support of necessary cloud qualities, such as scalability and resilience.

This articles by Martin Fowler gives a good introduction into the topics, as well as "Dos" and "Donts".

This blog post highlights how you can set up a tenant- and user-aware synchronous communication between microservices that run in the same or in separate accounts in SAP Cloud Platform.

Using the project example, we guide you through the required steps for setting up a communication between microservices using the SAP Cloud SDK. We will also cover some aspects of user authorization in this context. With this knowledge, you can then build more complex architectures extending your solution with several connected microservices.

Out of Scope


The goal of this blog post is not to advocate or to criticize the concepts of the microservice-based architectural approach, but rather to focus on the technical aspects in particular covering the SAP Cloud SDK capabilities with this regard.

As per the description given by Pivotal, communication between microservices can be synchronous (via HTTP APIs) or asynchronous (using messaging). In this blog, we focus solely on synchronous communication.

Security aspects in SAP Cloud Platform, Cloud Foundry play an essential role in this blog post. We will not go deep into the implementation details regarding this. We recommend, however, that you familiarize yourself with these aspects, as it will help to understand the concepts better (see the list of resources in the section Prerequisites).

We briefly cover the authorization topic in this blog post as well. However, as this aspect is not directly related to the SDK functionality, we recommend you to check additional resources for more insights and configuration capabilities. Please refer to the links in the section Further Information and Related Readings.

Prerequisites


To be able to run the example, explained in this blog post, it is required to set up the local development infrastructure as described in the following SDK tutorial: Step 1 with SAP Cloud SDK: Set up.

The next prerequisite steps are recommended, but not required.

To follow the explanation in this blog post, we recommend you to familiarize yourself with the few initial steps of how to get started with the SAP Cloud SDK, described in the following "Hello World" tutorial: Step 3 with SAP Cloud SDK: HelloWorld on SCP CloudFoundry.

It is important to understand the concepts of securing of applications running in SAP Cloud Platform, Cloud Foundry. The good explanation can be found here: Step 7 with SAP Cloud SDK: Secure your Application on SAP Cloud Platform, CloudFoundry.

Overview of the Coding Example


As a demo example, we have chosen a project consisting of two microservices communicating via HTTP APIs. You can find the full source code of this example in GitHub.

The first service provides an exchange rate service, which returns a list of currency pairs and corresponding exchange rates for these pairs. For simplicity of the logic, we are mocking the values for exchange rates.

The second service is a currency converter that reads the rates from the exchange rate service and uses these rates to convert the sum provided in the HTTP request from the given currency to the target currency.

As we described in Step 7 with SAP Cloud SDK: Secure your Application on SAP Cloud Platform, CloudFoundry information regarding the current user and tenant can be accessed from the corresponding Json Web Token (JWT) in the header of an HTTP request. To ensure that the valid JWT are provided to our services, we will secure both microservices in SAP Cloud Platform, Cloud Foundry and add respective app routers that will take care of a retrieval of a valid JWT from Authorization and Trust Management service instance.

The final high-level block diagram of the example application is shown below.



 

Users can call the exchange rate service directly via HTTP to get the list of all maintained exchange rates.

If a user calls a converter service, this service retrieves exchange rates required for the conversion from the corresponding service via HTTP. This is where the SAP Cloud SDK comes into play. If the HttpClientAccessor class of the SDK is used to retrieve HttpClient and to send a request to a destination (exchange rate service in this case), the SAP Cloud SDK will take care of the tenant- and user-awareness by forwarding a corresponding JWT in the HTTP request header.

Now, let us take a look at what steps are required to set up this example and to experiment with it.

Setting up the Example


For your convenience, we have published the source code in GitHub, so that you can easily get started. However, there are few additional steps required to be able to run this example end to end. Below, we describe these steps in more details:

  • Get the example project from GitHub

  • Configure destination

  • Secure microservices

  • Deploy and bind services

  • Run and analyse logs


Get the Example Project from Github


After you have cloned the SDK example repository from GitHub, you will find the files related to this example in the folder App2App. The table below explains the files and folders that you can find in this project, as well as some additional steps and changes that need to be performed before you deploy these microservices.






































converter The folder containing the converter microservice. This microservice was generated from the SDK scp-cf-tomee archetype, as described in the HelloWorld blog post. In addition to the HelloWorldServlet, the project contains ConverterSerlet, which is explained below.
exchangerate The folder containing the exchange rate microservice. This microservice was generated from the SDK scp-cf-tomee archetype, as described in the HelloWorld blog post. In addition to the HelloWorldServlet, the project contains ExchangeRateSerlet, which is explained below.
manifest-approuter-converter.yml The pre-configured deployment descriptor for the approuter that will be used to secure the converter microservice. Please, make sure to substitute the account id in the example (p2000211447trial) in "host" and in "destinations" with your own value before executing the deployment.
manifest-approuter-exchangerate.yml The pre-configured deployment descriptor for the approuter that will be used to secure the exchange rate microservice. Please, make sure to substitute the account id in the example (p2000211073trial) in "host" and in "destinations" with your own value before executing the deployment.
manifest-converter.yml The deployment descriptor for the converter microservice. Please, make sure to substitute the account id in the example (p2000211447trial) in "host" configuration with your own value before executing the deployment.
manifest-exchangerate.yml

The deployment descriptor for the exchange rate microservice. Please, make sure to substitute the account id in the example (p2000211073trial) in "host" configuration with your own one before executing the deployment.

Notice the set value of the environment variable:

SAP_JWT_TRUST_ACL: '[{"clientid" : "*", "identityzone" : "*"}]'

By using this, we customize that the exchange rate service allows the access to all OAuth clients and identity zones. You can specify a concrete client id or concrete identity zone here instead of using "*".
xs-security-converter.json Application security descriptor for the converter service. Refer to the official SAP documentation on more details regarding the syntax. Please, make sure to substitute the account id in the example (p2000211447trial) in "xsappname" with the value of your account where converter service will be running and identity zone "6b3dc481-3ebb-4f28-854e-b6ff0beac7d8" in "role-templates" with the identity zone of the called application (exchange rate).
xs-security-exchangerate.json Application security descriptor for the converter service. Refer to the official SAP documentation on more details regarding the syntax. Please, make sure to substitute the account id in the example (p2000211073trial) in "xsappname" with the value of your account where exchange rate service will be running and identity zone "0df4dc96-606c-458c-9acc-94a5ff4152ea" in "granted-apps" with the identity zone of the caller application (converter).


Now, let us take a look at the structure of the two microservices represented in this project: currency converter and exchange rate services.

The structure of the converter application is shown in the screenshot below. As we can observe, this is the standard SAP Cloud SDK project structure based on the Tomee archetype.



Notice, that Rate and CoverterServlet classes are added to the project that was generated from the SDK scp-cf-tomee archetype (see the details regarding the archetype structure in Step 3 with SAP Cloud SDK: HelloWorld on SCP CloudFoundry). The Rate class is a simple POJO that represents the exchange rate information:
@Data
@AllArgsConstructor
@ToString
public class Rate {
private String currencyFrom;
private String currencyTo;
private Double rate;
}

The class ConverterServlet contains the currency conversion logic, including the HTTP call to the exchange rate service. The code snippet below demonstrates how the HTTP call can be implemented using the HttpClientAccessor for the configured destination. Notice, that when the HTTP call is executed using this SDK component, the JWT forwarding, as shown in the block diagram of the example application, is handled by the SDK automatically behind the scenes. That means that the communication between microservices is user and tenant isolated.
final HttpClient httpClient = HttpClientAccessor.getHttpClient(DestinationAccessor.getDestination("app"));

final HttpResponse exchangeRateResponse = httpClient.execute(new HttpGet("/exchange-rate"));

The structure of the exchange rate service is shown in the screenshot below. This project uses the standard SDK scp-cf-tomee archetype, as well.



An additional class that we see in the screenshot is ExchangeRateServlet. This class simply exposes a few mocked exchange rates as a JSON response in the HTTP GET method:
List<Rate> rates = mockRates();
response.getWriter().write(new Gson().toJson(rates));

Notice that both ConverterServlet, as well as ExchangeRateServlet output the information regarding the current tenant and user. We will use this data later to evaluate that the microservice communication happens in a tenant- and user- isolated manner.
final Tenant currentTenant = TenantAccessor.getCurrentTenant();
final User currentUser = UserAccessor.getCurrentUser();
System.out.println("Exchange rate - called application: \n");
System.out.printf("Current tenant: %s \n", currentTenant);
System.out.printf("Current user: %s \n", currentUser);

Configure Destination


Before moving forward with the securing the microservices with app routers, let us do some necessary customizing in SAP Cloud Platform. We will require a special destination configuration with the name "app" that was already referred in our example code in the ConverterServlet above. The screenshot below shows the configuration that is done in the account, where the converter service runs. You can find the configuration of destination in your subaccount level under "Connectivity -> Destination (Beta)".



As you have seen in the code snipped from the ConverterServlet above, you can refer to this destination in your code by name.

Secure Microservices


As described in the introduction to this blog post, we will not cover in-depth aspects of security in SAP Cloud Platform, Cloud Foundry in this blog post. However, we highly recommend to read and to experiment with the materials, provided in the blog post Step 7 with SAP Cloud SDK: Secure your Application on SAP Cloud Platform, CloudFoundry.

We will now add application routers as described in this blog post. Notice, however, that we have already added the corresponding deployment descriptors and application security descriptors for the application routers for the converter and exchange rate services. Make sure that you substitute the used account ids with your own ones that are used for the deployment. We will elaborate on the content of xs-security-* files in the section Authorization Options.

Download and install this approuter as described in the Tutorial Step 7 and just place the approuter folder together with other files and folders in the folder App2App in your project. 


Deploy and Bind Services


Now, we are ready to deploy our own microservices (Converter and Exchange Rate) and bind them to the required cloud platform services.

For that purpose, we will use CLI of Cloud Foundry and execute the deployment and service binding in one command. You can perform the same steps using the SAP Cloud Platform Cockpit.

Deploy the exchange rate service (copy and paste the following command). You can use the same or two different accounts in SAP Cloud Platform for the converter and exchange rate services.
mvn clean package -f exchangerate/application && cf delete approuter-exchangerate -r -f && cf delete exchangerate -r -f && cf delete-service xsuaa-exchangerate -f && cf create-service xsuaa application xsuaa-exchangerate -c xs-security-exchangerate.json && cf push -f manifest-approuter-exchangerate.yml && cf push -f manifest-exchangerate.yml

Deploy the converter service (copy and paste the following command):
mvn clean package -f converter/application && cf delete approuter-converter -r -f && cf delete converter -r -f && cf delete-service xsuaa-converter -f && cf delete-service destination-converter -f && cf create-service destination lite destination-converter && cf create-service xsuaa application xsuaa-converter -c xs-security-converter.json && cf push -f manifest-approuter-converter.yml && cf push -f manifest-converter.yml

The following is executed when you run the commands above:

  • Build a deployable .war archive

  • Remove the running application router, microservices, and service instances (xsUAA and destination - for the converter service)

  • Create the destination service instance for the converter service

  • Create the xsUAA service instance using corresponding security descriptor

  • Deploy applications and application routers using corresponding deployment descriptors


Notice, that deployment descriptors added to the example application already contain necessary service bindings. Here is the example for the converter service, which binds the destination and Authorization and Trust Management (xsUAA).
---
applications:

- name: converter
memory: 768M
host: converter-p2000211447trial
path: converter/application/target/converter-application.war
buildpack: sap_java_buildpack
env:
TARGET_RUNTIME: tomee
JBP_CONFIG_SAPJVM_MEMORY_SIZES: 'metaspace:96m..'
SAP_JWT_TRUST_ACL: '[{"clientid" : "*", "identityzone" : "*"}]'
services:
- xsuaa-converter
- destination-converter

Run and Analyse Logs


After the applications have been deployed and bound to the needed services in SAP Cloud Platform, we can execute some queries and check the result.

Calling Exchange Rate Service


Firstly, let us call the exchange rate service directly. After you have deployed the exchange rate service and its application router, you should be able to locate these application in your account in the SAP Cloud Platform cockpit:



As we have secured the application, you are not able to access the exchange rate service directly:



Calling the application via application router <exchange rate application router URL>/exchange-rate will return you the list of exchange rates:
[{"currencyFrom":"EUR","currencyTo":"USD","rate":1.23},{"currencyFrom":"USD","currencyTo":"EUR","rate":0.81},{"currencyFrom":"EUR","currencyTo":"RUB","rate":69.73},{"currencyFrom":"EUR","currencyTo":"GBP","rate":0.89}]

Now, we will go back to the exchange rate service and check the logged tenant and user information:



The log shows the current user and current tenant that correspond to your account where the exchange rate service is running (also see the block diagram of this example above):
OUT Exchange rate - called application: 
OUT Current tenant: ScpCfTenant(tenantId=<tenant id from JWT2>)
Current user: ScpCfUser(name=<user id from JWT2>, scopes=[], attributes={})

Calling Converter Service (App to App SSO)


Now, let us access the converter service that will execute the application to application call to the exchange rate service to retrieve exchange rates behind the scenes.



The converter is secured with the application router, as well, so you can only call it via the corresponding converter application router URL. For example, to convert 100 EUR to USD, you would need to call the following URL:

<exchange rate application router URL>/converter?sum=100&from=EUR&to=USD

After you have called the URL and got the response (it should be 123.0), let us check the logs in both converter and exchange rate services to verify the current tenant and user information. You will notice that in both logs you now can find the user and tenant information that corresponds to your account where the converter application is running (calling application):

Log records in the caller application:
OUT Converter - caller application: 
OUT Current tenant: ScpCfTenant(tenantId=<tenant id from JWT1>)
OUT Current user: ScpCfUser(name=<user id from JWT1>, scopes=[], attributes={})

Log records in the called application:
OUT Exchange rate - called application: 
OUT Current tenant: ScpCfTenant(tenantId=<tenant id from JWT1>)
Current user: ScpCfUser(name=<user id from JWT1>, scopes=[], attributes={})

From these log records we can see that the tenant and user information is propagated automatically by the SAP Cloud SDK, meaning that the communication between our microservices is tenant- and user-aware.

Authorization Options


So far, we have discussed the microservices communication without covering authorization aspects. But what if the endpoints of the exchange rate service are protected with scopes? For example, in the exchange rate service, we have a Display scope and we want to grant this scope to the caller currency converter service. Please, follow Step 7 of the SAP Cloud SDK blogs section Use OAuth scope to authorize users to learn how checks of OAuth scopes can be activated for your services.

Using the configuration in your security descriptor for the caller and called applications, you can set up what is allowed to be accessed by other microservices.

Configuration of the Called Application (Exchange Rate)


Let us take a look at the security descriptor of the exchange rate service (called application) first. The content of this file is almost the same, as described in the Authorization section in Step 7 of the SAP Cloud SDK blogs. We can see one additional property in scopes: "granted-apps". In this property, we specify that the Display scope of the called application is granted to the caller converter service, referencing it using the format $XSAPPNAME(<plan>,<identity zone id of caller app>,<xsappname of caller app>).

For your setup, you would need to adapt the values in "xsappname" and "granted-apps".
{
"xsappname": "exchangerate-p2000211073trial",
"tenant-mode": "shared",
"scopes": [
{
"name": "$XSAPPNAME.Display",
"description": "display",
"granted-apps": ["$XSAPPNAME(application,0df4dc96-606c-458c-9acc-94a5ff4152ea,converter)"]
}
],
"role-templates": [
{
"name": "Viewer",
"description": "Required to view things in our solution",
"scope-references" : [
"$XSAPPNAME.Display"
]
}
]
}

Configuration of the Caller Application (Converter)


Now, let us take a look at the configuration of the security of the caller service:
{
"xsappname": "converter-p2000211447trial",
"tenant-mode": "shared",
"scopes": [
{
"name": "$XSAPPNAME.Display",
"description": "display"
}
],
"role-templates": [
{
"name": "Viewer",
"description": "Required to view things in our solution",
"scope-references" : [
"$XSAPPNAME.Display",
"$XSAPPNAME(application,6b3dc481-3ebb-4f28-854e-b6ff0beac7d8,exchangerate).Display"
]
}
]
}

As the display scope of the exchange rate service is now grated to the caller converter service, we can reference its scope directly in the security descriptor of the converter using the format $XSAPPNAME(<plan>,<identity zone id of called app>,<xsappname of called app>).Display. Again, do not forget to adapt the "xsappname" and "scope-references" to put parameters of your environment.

When the corresponding Viewer role is assigned to the user, it can access the exchange rate service protected with the Display scope.

There are additional configuration options, e.g. using the property "foreign-scope-references" or using the xsUAA brocker plan. Covering all the options and their advantages and disadvantages is out of scope of this blog post. Please, see the official SAP documentation for the latest updates on the security configuration.

Further Information and Related Reading


If you would like to get more insight into the microservice architecture in general, there are many available resources on that topic. The introduction into the Cloud Native and Microservices can be a good starting point. We also recommend the Martin Fowler article covering this topic.

In this blog post, we briefly touched on security aspects in SAP Cloud Platform, Cloud Foundry while securing the microservices with application routers and discussing authorization options. To learn more about further aspects of the configuration of security, refer to the official SAP documentation.

Conclusion


In this blog post, we have discussed how you can set up communication between your microservices via REST APIs using a dedicated GitHub example. We have shown, how you can use SAP Cloud SDK components to make this communication tenant- and user- aware. We have also briefly discuss how to extend this set up with checks of authorization scopes.

Stay tuned for further tutorials and deep dives for the SAP Cloud SDK, also covering the topics of multi-tenancy and microservice architecture.
8 Comments