NOTE: this blog post is intended for developers who have previous experience in developing multi-tenant CAP applications using SAP Business Application Studio, SAP BTP destinations, and the destination and XSUAA services.
Introduction
After I published this blog post, many developers reached out to me with the classical question: “does this microservice work in a multi-tenant scenario?”
My first reaction was to provide them a quick and straightforward answer: “yes, as long as you properly handle the on-board and off-board processes for the subscription and the access to the appropriate subscriber XSUAA APIs to manage its users“.
Looks quite simple, right? Well, but, of course, the queries kept coming (having the same quick and straightforward answer). Then, I finally made the decision to take on the challenge and develop the multi-tenant version of the microservice to serve as a definitive reference for those who want to embarc on that adventure.
So, before you continue reading this post, I strongly recommend that you read through the first post (as this one is just its spin-off) to fully understand what’s going to be discussed in the following topics. That post explains in detail the single-tenant version of the microservice – this version just contains some specific modifications to make it multi-tenant.
Therefore, without further due, let’s dive into the service details.
Application Architecture
The business problem is exactly the same of the first post. The scenario in this post is intended to deep dive into a fully working multi-tenant version of the CAP microservice leveraging an SAP Fiori UI for subscribers. The service manages users who are assigned to specific role collections (the ones belonging to the business application that is consuming the service) reading and writing user information from BTP in the subscriber subaccount using its XSUAA service APIs. The microservice is ready to deploy on BTP, Cloud Foundry Runtime.
Here’s a diagram representing the overall architecture of the microservice:
You may have noticed that the contents inside the provider subaccount are exactly the same as in the architecture described in the first post.
In the subscribers subaccounts, there’s the microservice subscription and a specific destination pointing to the XSUAA APIs from the subaccount.
XSUAA manages the BTP user store (namely “Shadow Users”). In the subscriber subaccount the CAP microservice subscription is created and will be responsible for managing the business application’s users in there. Once again, as in the original version, the microservice will “filter” users from BTP based on a set of role collections belonging to the business application.
It interacts with the XSUAA service in the subscriber through a destination to make REST API calls to the services’ user management APIs which are based on the System for Cross-Domain Identity Management (SCIM) standard.
That being said and looking to the architecture diagram, it’s obvious that each subscriber will require its own instance of the XSUAA service with the apiaccess plan (which also requires enabling Cloud Foundry and creating a CF space – no memory quota assignment is needed in this case). This is well detailed in the Git repo branch instructions.
The Fiori Elements HTML5 application will serve as the UI for the microservice’s subscribers.
Prerequisites
As in the first post, that application is already built using SAP Cloud Application Programming Model (CAP) and BTP’s XSUAA APIs. The full code can be found in this branch of the GitHub repo from SAP samples.
As previously mentioned, the intent of this blog post is just to walk through and understand the key-points of the development.
Therefore, as first prerequisite to follow-up with this post (besides reading through the first one), you must clone the repo branch strictly following the instructions from its README.md to setup the project locally.
NOTE: do not miss any single step of the instructions, otherwise you won’t be able to run and deploy the application.
Security Descriptor (xs-security.json)
The only difference in the security descriptor from the first post is that “tenant-mode” is shared instead of dedicated:
We also changed the “xsappname” in case you decide to deploy the microservice in the same subaccount of the single-tenant version, otherwise it’s absolutely not mandatory.
The role collections for the generic application served by the microservice have been prefixed with GenericMtxApp instead of GenericApp also in case you want to deploy this version in the same subaccount as the single-tenant version, thus avoiding to share the same role collections between both versions. And that’s all!
To learn more about the syntax of the XSUAA security descriptor you can read this official document.
Required Services
Same as in the first post. The only exception is that, upon deployment the MTA will create an additional service to manage the on-board and off-board processes of subscriptions to the microservice: the SaaS Provisioning Service (namely saas-registry). That service is bound to the CAP backend service in the mta.yaml:
And is configured as shown below:
I strongly recommend you examine the mta.yaml in detail to look for the differences in relation to the single-tenant version from the first post. You’ll notice that the managed approuter has been replaced by a standalone approuter:
Thus, all references to the HTML5 repo and runtime services and respective configurations have been completely removed. This also leads to changes in the approuter configuration within the xs-app.json file:
Besides the replacement of all routes related to the HTML5 repo and runtime, another route has been added to point to the on-subscription and on-dependencies callbacks required by the SaaS Provisioning Service.
Destination Setup
Same as in the first post.
Package Setup
Few modifications have been made to the projects’ package.json file in relation to the first post.
First, some dependencies have been added to handle the on-board, off-board and get dependencies processes of subscription life-cycle:
The @sap/cds-mtx package is also responsible for managing the different schemas (HDI containers in the case of SAP HANA Cloud) where the data model is deployed for each tenant (subscriber) to provide full data isolation.
Second, some changes have been made to the cds.requires section:
1. Indication of a “mock tenant” for each “mock user“;
2. Multitenancy setup:
3. There’s also an additional API setup which is not part of the original microservice and has been added as a bonus that will be discussed later:
Microservice Configuration
The new GenericMtxApp prefix for the role collections has also been adjusted in the corresponding environment variable in the microservice configuration:
Service Definition
In the service definition, a new action has been bound to the User entity. This has been done to execute the bonus snippet, which will be discussed later in this post:
Annotations for the UI
Like it has been done with the previously defined action, we also annotate the criticality of the newly added action (which is also non-critical), but with no side effect in this case:
Subscription Handling
The subscription handling process is fully implemented in the server.js file into the srv folder. That file has been entirely generated by the SAP HANA Academy CAP SaaS Multi-tenant Application Generator, selecting the options to automatically create routes and return required destination dependency in the respective callbacks, with no further modification (please, refer to the corresponding videos in the playlist from the link to better understand the generator).
Code Analysis
The application code is basically the same with the only exception that, as it’s running in a multi-tenant context, the control flag that was a simple boolean variable in the single-tenant version has been changed to a JSON object like demonstrated in the screenshots below:
Bonus Snippet!
A while ago I also wrote and published a blog posts series focusing on how to get authenticated user information using three different approaches. One of them (which is the most complete) uses the XSUAA API from the application service binding – you can check it here.
And guess what? Same old classical recurring question: “does it work in a multi-tenant context?“. Well, in this case the answer is: “yes, but with a slight modification in the code of the post to consider the authentication made in the subscriber“.
So, once again, I decided to take advantage of the effort to produce the mult-tenant version of this microservice and add the multi-tenant version of the procedure to get authenticated user information.
NOTE: to understand what I’m talking about here, please also read through the blog post, before inspecting the bonus snippet.
OK, so here’s the code executed by the previously mentioned userInfo action:
In the single-tenant version described in the post, the url in the credentials is simply filled with the one gotten from the XSUAA service binding. As this binding is done in the provider subaccount (where the service is actually deployed), when the “/userinfo” endpoint is invoked XSUAA yields error, because the authentication (handled by the approuter) has been done in the subscriber subaccount and not the provider.
Well, the trick here is simple: as subscriptions can be done only in subaccounts located in the same region as the provider we can safely assume the authentication domain is always the same for both provider and subscribers. Therefore, for XSUAA to correctly interpret the authenticated user info, we just need to change the subdomain of the API URL to point to the subscriber subdomain instead of the provider. This is exactly what the highlighted code snippet does.
And this concludes the analysis and explanation of the multi-tenant user management microservice CAP project (with bonus snippet).
Additional Resources
Here’s a list of resources to enhance your learning experience on this topic:
- Deploy Multi-tenant Applications in the Cloud Foundry Environment
- CAP Multitenancy Cookbook
- SAP HANA Academy: SAP Business Technology Platform – Multi-tenant Business Applications
- Develop a Multi-tenant Software as a Service Application in SAP BTP using CAP
Conclusion
After setting up the project from this git repo branch and going through this blog post content, you’ll have learnt and experimented how to build a multi-tenant CAP microservice which will allow your business application to manage its business users autonomously for each application subscriber. Hope you have enjoyed the journey!
Please, do not hesitate to submit your questions in Q&A in SAP Community: https://answers.sap.com/index.html