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: 
ale_biagi
Product and Topic Expert
Product and Topic Expert
NOTE: this blog post is intended for developers who have previous experience in developing CAP applications using SAP Business Application Studio, SAP BTP destinations, and the destination and XSUAA services.

Introduction


Secure cloud software should always rely on some sort of authentication and authorization mechanism to let users benefit from its functionality and protect it from attackers and/or malicious usage.

Based on such mechanism, users must first authenticate using login and password (safer systems even use two-factor authentication with some extra identity check technique, such as security tokens), so they can prove their identity, and, then, the application checks whether they are authorized to use its functionality and, if yes, which functionality - from the whole application - they are allowed to use: this is basically the definition of authentication (first part) and authorization (second part).

Authorizations are provided through some role-based mechanism through which a set of "roles" are assigned to users, granting them authorization to perform operations in the system (i.e. create, read, and/or update some data). So, a user with a role of, let's say, "Viewer" would be allowed to access data in "read-only mode", whilst a user with a role of "Admin" would also be allowed to write data to the system.

Therefore, secure cloud business applications must have the ability to let their administrators manage their business users, defining who can authenticate to the application and what access level each one has (which functionality can be used by each user)..

The Business Problem


In BTP, users are authenticated through some Identity Provider (IdP) that has a trust relationship with each subaccount. This grants access to the platform landscape, but is usually not enough to authorize them to use the hosted business applications as most of them will have their own set of "authorizations" to control who can do what within the software.

Such authorizations are granted via the so-called "role collections" - a set of roles containing "scopes" that allow users to execute specific tasks in the application. To assign those role collections to the users in the platform, BTP requires to have such users kind of "replicated" in its own "user store" (instead of the one from the IdP) as the role collections are also stored in BTP - those "replicated" users are called "shadow users".

But, then, what is the problem with that? Well, all of that stuff is managed either via BTP cockpit or CLI and not actually by the business application itself, meaning that a BTP subaccount administrator has to do it (create and/or update shadow users - if not done automatically upon authentication by the IdP - assign and/or remove role collections, etc.). Also, the BTP user store can have lots of shadow users accessing different business applications which makes it even more difficult to the subaccount administrator to manage.

So, why not let the business application itself manage its own users by "filtering" from the BTP user store only those assigned to specific role collections - the ones belonging to the application? That's the recurring question which's been raised in most of the technical advisory sessions I've been providing to developers at SAP partners and is exactly the motivation for this blog post.

In this blog post, we will understand the key-points of a CAP microservice which's been developed to provide user management functionality to any generic business application.

Application Architecture


The scenario in this post is intended to deep dive into a fully working CAP microservice leveraging an SAP Fiori UI for testing. 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 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:


Figure 1 - Application Architecture


Now, let’s analyze this architecture: first we have SAP Business Technology Platform with the Cloud Foundry Environment and the Authorization and Trust Management Service (XSUAA).

XSUAA manages the BTP user store (namely “Shadow Users”). In Cloud Foundry we deploy the CAP microservice which will be responsible for managing the business application’s users. This microservice will “filter” users from BTP based on a set of role collections belonging to the business application.

It interacts with the XSUAA service 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.

A simple Fiori Elements HTML5 application has been built to serve as a UI for the microservice and the resulting application could be optionally published to a Launchpad Service site.

Prerequisites


Actually, 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 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, you must clone the repo 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.

Additionally, before going deeper into the contents of this post, please read through these three blog posts:

Security Descriptor (xs-security.json)


The security descriptor (xs-security.json) is the file which defines the details of the authentication methods and authorization types to use for access to your application.

The xs-security.json file uses JSON notation to define the security options for an application. The information in this file is used at application-deployment time, for example, to create required roles for your application.

In the descriptor, we define the application name, tenant mode (dedicated = single-tenant) and description.


Figure 2 - Application info


Next we define a collection of application scopes (each single task that a user can execute in the application) and reference them in a list of role templates. The granularity level of the scopes is defined by the application developer. In this simple example, we are working with higher granularity: just administrative tasks, user management tasks and regular user  tasks.


Figure 3 - Scopes and Role Templates


The first scope and corresponding role template are used in the OAuth flow executed by the application’s router (namely AppRouter). They are just added to the JWT (JSON Web Token) to signal that the user is authenticated and authorized to access the application. The other scopes are really the ones which define what each user can do.

Next, we group the role templates into role collections which are actually assigned to the business users.


Figure 4 - Role Collections


Finally, we configure the allowed URIs for the OAuth flow when it's redirecting the user after authentication, and the JWT has been properly issued (basically the BTP and Business Application Studio domains).


Figure 5 - OAuth 2.0 configuration


To learn more about the syntax of the XSUAA security descriptor you can read this official document.

Required Services


The reference to determine which services will be required by a certain application is always its defined architecture. So, looking at the architecture we can immediately infer that:

  1. The microservice will access the XSUAA APIs using a destination, hence an instance of the destination service must be created and bound to it (via some service key).

  2. To secure the application itself, the security configuration from the descriptor must be applied and managed by XSUAA. So, an instance of the authorization and trust management service for the application (application plan) must be created and bound to it (via some service key).

  3. Finally, the microservice must call the user management API from XSUAA. Therefore, another instance of the authorization and trust management service to access APIs (apiaccess plan) must also be created. But this one, is not bound to the application: we just create a service key and use it to configure the destination in BTP.


The binding of the first two service instances to the CAP project is done via emulation of the VCAP_SERVICES in the default-env.json file as instructed in the git repo. The binding is also done when deploying to BTP Cloud Foundry as per the definitions in the mta.yaml file.

Destination Setup


We look into the XSUAA apiaccess service key and use some relevant information from it to configure the destination like demonstrated below:


Figure 6 - Destination setup



Package Setup


For this development, some adjustments are required to the projects’ package.json file.

As the microservice itself do not require persistence, because the users are actually persisted in BTP’s user store, we will use the SQLite in-memory database in production to replicate the users' information in the microservice’s memory. By doing so, we hand over all the OData v4 handling stuff to the CAP framework. Therefore, SQLite must be moved from devDependencies to Dependencies.


Figure 7 - Adjust dependencies


To avoid deployment issues with the Cloud Foundry NodeJS Buildpack, we explicitly define the node and npm engines versions.


Figure 8 - Set Node and NPM versions


Next, we create the cds.requires section containing:

  1. An authentication block with a mock user for the development profile, making sure it has the “UserAdmin” role assigned;

  2. A DB block defining the usage of a SQLite in-memory database;

  3. An external service block pointing to the XSUAA REST API via the previously created destination;

  4. And, finally, a UAA block to specify that XSUAA will be used to secure the microservice;



Figure 9 - Create cds.requires section


The last section to add is “features”, where we explicitly specify that an in-memory database will be used in production.


Figure 10 - Features setup



Microservice Configuration


To make the service totally flexible and decoupled from the rest of the business application, we use two environment variables to configure it:

  1. APP_AUTHS: a list of JSON objects separated by a “|” (pipe) character – each object represents an authorization (namely role collection) for the business application user.

  2. DEFAULT_AUTH: the ID of the authorization object that’s used as default when no authorization is assigned to a user.


During development those variables are provided in the project's .env configuration file. In production, after the service is deployed, they are set with cf set-env followed by a cf restage.

Data Model


Here are the details of the data model entities, defined under the user.mngr.db namespace:


Figure 11 - Data Model




  1. The User entity with some selected properties from the BTP user store. Each user is associated to an origin IdP and is composed by one or several authorizations (assigned role collections).

  2. Such composition is defined into the UserAuthorization entity whose parent is the User.

  3. The BTP subaccount trusted IdPs are also retrieved using the XSUAA REST API

  4. And the authorizations (role collections) are populated using the APP_AUTHS environment variable set in the .env file (and later in production).


Service Definition


Here we write the service definition under the user.mngr.srv namespace, referencing user.mngr.db as the model. We name the service UserMngrService defining the endpoint as ‘user-mngr’ and granting access only to users with the UserAdmin role (scope).

Then we expose the User entity as a projection from the model and attach a collection action (meaning it operates over an entire entity collection) which will be used to reload the data from BTP.

This serves to keep the service synchronized with BTP’s user store in the case of changes done directly in BTP via cockpit. 


Figure 12 - Service Definition



Annotations for the UI


To get the service prepared for being used in a Fiori UI, we annotate its entities with UI annotations.

Please, feel free to explore the service-ui.cds annotations file by yourself. This git repo from SAP samples has a really nice reference and showcase of annotations to help you understand the full content.

In this post, we'll focus only on the most relevant annotations for the best UI behavior.

When the “refresh” action is executed, as a side effect, the corresponding list report table must be reloaded:


Figure 13 - Refresh side effect


In the same way, when first and last names are filled, the “display name” (conjunction of first and last names) must be updated in the UI:


Figure 14 - Display name side effect


The “origin” property from the User entity must be filled from a list of trusted IdPs:


Figure 15 - Origin IdP value help


And the key of such IdP, which is used in the association, must display the IdP name instead of the key value itself:


Figure 16 - IdP key text arrangement


The "authorization" property of the UserAuthorization composition must also be filled from a list of authorizations:


Figure 17 - Authorization value help


Whenever an authorization is selected to fill the property, the Authorization entity is affected and, as a side effect, the "authorization description" must be updated in the UI:


Figure 18 - Authorization selection side effect


Finally, the "authorization ID" must also display the authorization name, instead of the ID value itself:


Figure 19 - Authorization ID text arrangement



Code Analysis


The microservice logic goes into the service handlers. In this project the code is organized into a module (/srv/lib/handlers.js) for better maintainability.

The code logic can be easily understood by reading the comments spread all around it - which are pretty much self-explanatory. Therefore, in this post we'll focus exclusively on the key parts responsible for interacting with the XSUAA APIs.

Upon module load, we connect to the XSUAA service destination to retrieve an HTTP client called “xsuaa”:


Figure 20 - HTTP client creation


And this is how the client is used:

1. Read users from BTP:


Figure 21 - Read BTP users


2. Create a user in BTP:


Figure 22 - Create user in BTP


3. Assign role collections to a user:


Figure 23 - Assign role collections


4. Remove role collections from a user:


Figure 24 - Remove role collections


5. Update user information:



Figure 25 - Update user info


6. Read the list of trusted IdPs:


Figure 26 - Read trusted IdPs list


The handler functions in the module are used by the service module (/srv/service.js) to attach them to their respective events (after, before, on, etc.).

And this concludes the analysis and explanation of the user management microservice CAP project.

Additional Resources


Here's a list of resources to enhance your learning experience on this topic:

Conclusion


User management is a key topic to secure cloud native applications. After setting up the project from this git repo and going through this blog post content, you'll have learnt and experimented how to build a CAP microservice which will allow your business application to manage its business users autonomously. Hope you have enjoyed the journey!

UPDATE: if you want to implement a multi-tenant version of this microservice, please read through this blog post.

Please, do not hesitate to submit your questions in Q&A in SAP Community: https://answers.sap.com/index.html
5 Comments
MustafaBensan
Active Contributor
0 Kudos

Hi alessandro.biagi

What an excellent coverage of a very important topic for BTP application development.  Thank you!

To maintain context, I would like to ask the following questions in this comment, if I may?

1)  If the Identity Provider is SAP IAS, there is an option to Create Shadow Users During Logon as shown in the SAP BTP Cockpit Subaccount Trust Configuration screenshot below.  Would it be accurate to say that the User Management Microservice is a more robust approach that allows the application to programatically maintain Shadow Users instead of relying on automatic creation during logon?

Automatic IAS Shadow User Creation

2)  Does the User Management Microservice support deletion of shadow users?

3)  From the code snippets above, if I understand correctly, shadow users are added to Groups (Role Collections).  How do these Groups relate to the Groups that are maintained in IAS?

4)  How would the User Management Microservice be implemented for CAP multi-tenant applications in the case where the IdP is IAS?

Any guidance you can provide on the above would be greatly appreciated.

Regards,

Mustafa.

 

ale_biagi
Product and Topic Expert
Product and Topic Expert

Hi mbensan,

Thanks for reaching out and for your feedback.

Here are your answers:

1) The microservice is capable of creating shadow users in BTP regardless of the trust configuration of the IdP. It means that if the trust configuration is set to automatically create the shadow users at first logon, then the microservice will use such previously created shadow user (when you add it to your application), otherwise it will create it on its own. Think of this service as the user management functionality of your application: you specify the users authorized to use your app (whether they are already stored in BTP or not) and give them their corresponding authorizations (role collections).

2) "Deletion" of shadow users might be a "dangerous zone". Why is that so? Because, your application may be one of a dozen that the user could have access to. This is determined by the other role collections (from other apps) assigned to them. So, if you simply "delete" a shadow user you could be removing its access to other applications in BTP. Therefore, the service has been developed to simply remove your applications' role collections from the user. As it "filters" the users having such role collections, by doing so the user will no longer have access to your application (and won't be listed with your other users), but its shadow user will still remain in BTP. Of course, you can modify it to do something like: "if there are no other role collections assigned (apart from those of your app), then delete the shadow user, otherwise, just remove my role collections".

3) Role collections are just called "groups" in this context by a convention from the System for Cross-Domain Identity Management (SCIM) standard. As IAS uses the same standard it also calls them groups, but there's no relation between them.

4) To use the microservice in a multi-tenant CAP app you would need to create the XSUAA services in the provider subaccount setting the tenant mode of the security descriptor to "shared". Please, keep in mind that, after the SaaS subscription, the users will be maintained in the "consumer" subaccount, meaning each subscriber tenant will have a different set of users. UPDATE: you can find the multi-tenant version of this microservice in this blog post.

Regards,

Alessandro

MustafaBensan
Active Contributor
Thank you so much for the prompt and detailed responses.  That certainly helped fill in the blanks.

Regards,

Mustafa.
aman_khanna
Employee
Employee
0 Kudos
Thank you for your blog, alessandro.biagi

A question please - For #4 above, in the case of multi-tenant CAP app, is there anything to be done to identify a specific subscriber (consumer) sub-account users, roles and role collections when running the app from provider sub-account OR will xsuaa api present in provider sub-account automatically give back users, roles and role collections based on the subscriber URL opened in the browser? For eg: let's say there are 2 subscribers and 1 provider. URL opened in browser is subscriber1.hana.ondemand.com. The application code runs on provider. XSUAA API gets triggered from within provider app but we need to view users, roles and role collections for subscriber1
ale_biagi
Product and Topic Expert
Product and Topic Expert
0 Kudos

HI aman.khanna,

According to the official docs, the XSUAA service is multi-tenant aware as well as the destination service (which in this case is the key for such accomplishment). So, I assume it is possible to achieve what you describe as long as you create a destination in the subscriber with exact the same name as in the provider pointing to the XSUAA API in subscriber subaccount.

UPDATE: you can find the multi-tenant version of this microservice in this blog post.

BR,

Alessandro