In this tutorial we configure trust (SAML) between 2 Cloud Foundry subaccounts located in different regions in SAP Business Technology Platform (SAP BTP).
This allows us to call a protected application across subaccounts, across regions.
Used technologies: XSUAA, SAML2, OAuth2, Destination, OAuth2SAMLBearerAsertion, Node.js,
This tutorial is not a recommendation for architecture setup, it just attempts to explain how to achieve the desired scenario, so you can learn, try it out and adapt to your requirements.
Reason for the disclaimer: typically, SAML and OAuth2SAMLBearerAssertion are used to access SAP BTP Cloud Foundry from outside BTP.
Nevertheless, I hope below description might be helpful for you.
This tutorial is meant to be executed by newbies, so pls don’t hesitate to start it and pls don’t hesitate to provide (positive) feedback.
If any step is unclear or explanation missing, pls contact me via personal message.
Part 2: Practice-Party (next blog)
1. Create Backend Application
2. Create frontend Application
3. Configure Trust
3.1. Frontend Subaccount
3.2. Backend Subaccount
4. Create Destination
5. Run Scenario
Appendix 1: Backend App
Appendix 2: Frontend App
Appendix 3: Destination Configuration
We have an application running in SAP BTP, Cloud Foundry environment.
This app offers an endpoint which is protected with OAuth.
We want to call it from a frontend application.
Both apps are deployed in different subaccounts, even in different regions (data centers).
How can authentication be accomplished?
We configure trust between both subaccounts (based on SAML2).
And we use a Destination of type Oauth2SAMLBearerAssertion for the calling the endpoint.
This solution works only in user centric scenario.
Out of scope: granting authorization across borders.
What is SAML?
SAML stands for Security Assertion Markup Language.
SAML is typically used for scenarios where users in big companies have to use multiple applications.
Instead of entering users/passwords for each application, they login only once, and the login is reused for each application.
That’s known as Single Sign-On (SSO) login standard.
We use SAML as well for Principal Propagation.
In this context, we talk as well about Identity Federation.
SAML is used in browser-based scenarios.
There are a few terms which we should learn in SAML language:
The user authentication is handled by a central Identity Provider (IdP)
The IdP issues a little document which contains the user-info (identity) and which is passed to each application.
The involved systems are called “Entities”: Identity Provider and Service Provider (SP).
When login is required, the user has to do the authentication request at IdP.
The IdP creates a little xml document, which is the authentication response and contains the user’s identity.
This little xml document is also called SAML Bearer Assertion (because it is carried around, from app to app) or just token.
The token is stored in the user’s browser session and is sent to each application the user wants to access.
It is signed with X509 certificate.
The receiving Service Provider is able to verify the signature, because a trust relationship has been established between IdP and SP.
To establish the trust relationship, SAML supports metadata documents on both sides (IdP and SP)
Metadata contain e.g. the info about endpoints used for redirects etc.
The SP metadata contains the Assertion Consumer Service URL (ACS Endpoint).
SAML assertions are sent to this endpoint.
Below diagram tries to illustrate the basic relation between entities and the flows:
The diagram shows:
The end user wants to access an app, hosted in SP.
To do so, he needs to do authentication request to IdP (SP does redirect, if necessary).
The authentication response contains the xml doc, the SAML Bearer Assertion, which is accepted by the SP, because there’s a configured trust between IdP and SP.
Advantage of SAML
Security is handled centrally, applications don’t need to store uses and passwords, users don’t need to enter pwd for each app.
SAML is open standard and provides flexibility.
The little xml document is quite big and causes network overhead.
Main focus is authentication.
Authorization capabilities are rather poor.
Difference to OAuth
SAML2 can be used for both authentication and (limited) authorization.
OAuth2 is an authorization framework. Authentication is not in scope.
However, OAuth2 can be enhanced (with openID) and used for SSO as well.
OAuth2 uses JWT tokens which are smaller than the xml-based SAML assertions.
Different terms for similar concepts
Service Provider (SAML) corresponds to Resource Server (OAuth).
Identity Provider (SAML) corresponds to “Authorization Server” (OAuth).
Client: browser (SAML) corresponds to (mostly) web app clients in OAuth.
This point is more interesting for us, as we’re typically working in Cloud Foundry with OAuth2 and not SAML2.
As we know, OAuth provides several mechanisms for issuing access tokens.
client-credentials flow: used for app-2-app communication, where the client authenticates with clientId/secret to get a token.
authorization-Code flow: used for people-centric scenarios. Human user does login, a code is generated which in turn is used to fetch a token along with id/secret.
This flow is used when we add an approuter in front of our frontend application.
SAML2 Bearer Assertion flow: used for people-centric scenarios, where user login is done outside of Cloud Foundry. Once the remote application has the SAML assertion, it can be used to fetch an OAuth2 JWT token for the Cloud Foundry application.
This last flow is the one which we’re focusing on:
Our remote application (frontend) is running on a remote subaccount and uses this flow to access a serviceprovider application (backend) in our home subaccount.
Maybe we’re misusing this flow a little bit, because the remote app is running in Cloud Foundry too.
But anyways, the tutorial is meant to help you to setup your own scenario.
In our tutorial, to represent cross-border scenario, we’re using 2 trial accounts located in 2 different regions (data centers).
To enable authentication, we configure trust between both subaccounts.
Configuration is done on subaccount-level.
More precisely: How exactly is the trust configured?
Which subaccount has to trust or do whatever?
Our backend subaccount hosts a backend app.
Backend app stands for: it is meant to be called by others.
But not just anybody can call it:
Only trusted callers can call it.
As such: the backend subaccount has to trust the frontend subaccount.
As such: trust configuration has to be done in the backend subaccount.
As such: the trusted entity is the Identity Provider (IdP) of the frontend subaccount.
As such: the SAML metadata of the trusted IdP has to be copied over to the backend subaccount.
Below diagram shows that the trust configuration is configured in backend subaccount:
How to do the call?
We use a destination of type OAuth2SAMLBearerAssertion.
Using this destination will make our life easier, as it completely hides the SAML request and the OAuth flow, which are required to fetch a JWT token.
Remember that our backend app is protected with OAuth and requires a valid JWT token.
Where to create the destination?
All this trust and config stuff is confusing with respect to what and where we need to do.
Even when doing the hands-on part we will get confused about who we are and where we are and what we’re doing.
So don’t hesitate to ask your questions….
Where to create the destination?
Sorry: The destination is created in the frontend subaccount.
This is the place where the destination is used.
The frontend app calls the backend app with the help of the destination.
The frontend app is bound to the destination service.
Hence, the destination configuration is created in the frontend subaccount.
How to configure the destination?
When choosing destination type OAuth2SAMLBearerAssertion, we’re overwhelmed with so many fields to be filled in.
We’ll explain the details later, in the hands-on part, but at this point in time we can illustrate, from where we need to get the required data.
Basically, we need some SAML metadata, taken from the trust configuration.
And we need some OAuth data, which are taken from the credentials, as usual.
More precisely, the backend app is protected with OAuth and hence is bound to an instance of XSUAA service.
This binding contains the required credentials information.
What’s the benefit of calling the Backend App?
Our backend app represents a kind of service-provider application which is meant for common usage.
In your scenario, your backend app might be used by UI-apps that are deployed together, but also other apps that are deployed outside.
In our example, we keep the code as minimalistic as possible.
So we only perform the security check and return a useless response.
Is the Frontend App similarly useless?
It does nothing than calling the useless backend app.
Again, we’re keeping the code minimalistic.
The frontend app uses an approuter for handling user login.
The app shows how to call the destination service.
In addition, for our learning experience, it writes the content of the JWT tokens to the browser.
We take the role of an end user, we invoke the endpoint of the frontend application and enter our user credentials in the login screen.
The app will use our user-JWT-token, call the destination service, call the backend application.
If everything is working as expected, we will see a success message, sent by the backend app.
In addition, we see some interesting details of the content of the JWT tokens.
The interesting part is to try it out and experience the first steps with SAML and trust.
Prerequisites are simple, so everybody should be able to get it done.
Access to SAP BTP, with enough permissions, is required.
This tutorial is based on 2 trial accounts, in 2 different regions, with 2 different users.
Basic knowledge of Node.js, OAuth, Cloud Foundry is an advantage.
This tutorial uses the Cloud Foundry CLI. Cockpit can be used as well, but is not explained.
To follow this tutorial, we create a project “crossapp” which contains our 2 applications:
Or see this screenshot:
Each app folder contains a few files required for little node server apps.
We create the required files in the folders and copy the content from the appendix
Looks confusing, right?
Here’s an additional screenshot, for your convenience:
After going through this blog post, we’ve learned some basics about SAML and trust and the OAuth support for SAML assertions.
We have a basic understanding of an architecture setup that allows to call a protected application from outside its subaccount border.
We’ve learned how to use these technologies to implement a silly sample application.
In the next blog post we’ll go through every step required to run the described scenario.
We’ll create and deploy the 2 mini apps.
We configure trust and create the destination.
We’ll have some closer look into some details.
SAP Help Portal
Cloud Foundry reference for SAML2 Bearer Grant
SAML Bearer Grant spec RFC7522
JWT: JSON Web Token spec RFC 7519
JWS JSON Web Signature is specified in RFC 7515
JWK JSON Web Key is specified in RFC 7517
JWT introspect tool: https://jwt.io/ -> debugger
IANA page for registered claims
Difference between JWt and SAML tokens is stated in the spec here
How to call protected app from external app with scope
How to call protected app from external app across subaccount.
Understanding Token Exchange
How to grand scope to myself
Understanding the JWT content
How to add custom properties to JWT
Cloud foundry UAA docu for scopes