Skip to Content
Personal Insights
Author's profile photo Piotr Tesny

User Propagation between SAP BTP and third-party Applications.

This brief is to demonstrate how one could access a backend micro-service deployed on SAP BTP  and protected by an SAP app-router [native] application from a non-BTP [foreign] application.


Actually it seems to be a fairly common scenario. Some business users may be flocking directly into BTP, but some others may have already been authenticated upfront and elsewhere but still need to access backend services hosted on BTP without being forced to re-authenticate.

So the question is how to ensure a seamless user identity propagation for users coming into BTP from a foreign context?

Let’s focus on some basic facts and assumptions:

  • A BTP sub-account is acting as a service provider (SP) to establish trust with identity providers.
  • The most obvious and allegedly simplest way of achieving the above requirement  would be to have one single IDP for both BTP direct and indirect users.
  • Still there may be cases where the direct business users would be flocking into BTP via for instance an AzureAD trusted with BTP (either hooked directly to a BTP sub-account or proxied via SAP IAS) but the indirect business users would be authenticated upfront via another IDP for instance PingIdentity / Okta / Keycloak used for a non-BTP business mobile application.

 


Pre-requisites:

  • access to a sub-account in a BTP Free / BTP Trial account or BTP paid account with Cloud Foundry environment and a BTP HANA Cloud instance up and running.
  • good understanding of concepts behind 2.1.1.1.3.4.2.4  User Propagation between Cloud Foundry Applications as described in the official SAP documentation page 159 onwards…

Good to know:


Disclaimer:

  • The ideas presented in this blog are personal insights thus not necessarily endorsed by SAP.
  • This is a playground only. All deployment examples, code snippets, gists, etc are provided “as is”.
  • Images/data in this blog post is from a SAP internal/trial sandbox and/or demo systems. Any resemblance to real data is purely coincidental.
  • Access to some resources referenced in this blog may be subject to a contractual relationship with SAP and a S-user login may be required. Always refer to T&C.

Putting it all together

The basic build components are as follows:

Please refer to appendix and gists for further details on the application structure and build.

An IDP-initiated flow.

We want to be able to gain access to resources (micro-services) hosted on BTP without being redirected to a BTP login page when calling into these resources from a context of a foreign application.

When it comes to user authentication and user SSO there are two basic flows:

  • the interactive, SP-initiated flow (SAML Web SSO)
  • the unmanned, IDP-initiated flow.

The IDP-initiated authentication (user SSO) and user authorisations between an application and a micro-service is well documented here in the chapter 2.1.1.1.3.4.2.4 User Propagation between Cloud Foundry Applications (page 159 onwards).

Thus the only twist is that our application is a non-BTP one.

To summarise, all we need is an instance of an OAuth2SAMLBearerAssertion destination that combines a user identity propagation [via an IDP-initiated SAML SSO flow] with user scopes (authorisations) checks against an OAuth2 service provider.

In order to create such a destination definition we need to have both a Trusted IDP and an OAuth2 service provider present in the context of the micro-service sub-account.

As aforementioned, our application is not deployed on BTP, thus we can use a destination service from any BTP sub-account including from the same sub-account as the micro-service.

Trusted IDP.

We need to create a trusted IDP on the micro-service BTP sub-account level.

If using a destination service as a trusted IDP we can simply download the IDP metadata and establish a trust with the micro-service BTP sub-account.

For the sake of simplicity we can use the destination service trust from the same sub-account as the micro-service.

Please refer to the following gist for further details.

OAuth2 service provider.

The BTP micro-service (haa-ina-service) endpoints are protected with OAuth.

When attempting to call the endpoints directly the following payload will be yielded:

<oauth>
<script type="text/javascript">window["_gaUserPrefs"] = { ioo : function() { return true; } }</script>
<error_description>An Authentication object was not found in the SecurityContext</error_description>
<error>unauthorized</error>
</oauth>

 

Thus in order to make it work there are two options:

  • either access the micro-service via a suitable route served by the SAP approuter (through a destination).
  • or directly call the destination in the context of the foreign application and provide the obtained bearer access token in the Authorization header in the micro-service endpoint call. A destination service offers a very nice REST API that will come in handy in this scenario. This approach is described in the official SAP help pages, as follows:

The managed application router does not “hide” the back-end microservices in any way; they remain directly accessible when bypassing the application router. So the back-end microservices must protect all their end points by validating the JWT and implementing proper authorization scope checks.

For the sake of simplicity we shall use an instance of the XSUAA service as our OAuth2 service provider.

The instance of the XSUAA service will need to be bound to micro-service application (haa-ina-service) and to the approuter application (haa) as well.

Additionally, with the approuter serving the destination to access the backend micro-service, the approuter application will have to be bound to the destination service.

Quovadis. Building a destination definition.

As aforementioned, a BTP sub-account is acting as a service provider (SP).

In order to build our destination definition we need to download the BTP’s sub-account SP metadata. From BTP’s sub-account SP metadata we shall retrieve two very important saml assertion attributes, namely the audience and the recipient.

The audience attribute designates compatible service providers, in our case this is our BT sub-account and the recipient is the value of the AssertionConsumerService URL which, in turn, will be used by the destination service to retrieve a bearer access token.

The tokenServicePassword is the client secret from the XSUAA service instance service key.

The clientKey and tokenServiceUser are the client id from the XSUAA instance service key.

{
  "Name": "Quovadis",
  "Type": "HTTP",
  "URL": "<backend haa-ina-service service URL>",
  "Authentication": "OAuth2SAMLBearerAssertion",
  "ProxyType": "Internet",
  "tokenServiceURLType": "Dedicated",
  "audience": "<entityID from your BTP subaccount SP metadata>>",
  "Description": "client_id/client_secret must be the backend service app router's xsuaa credentials",
  "authnContextClassRef": "urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession",
  "tokenServiceUser": "<xsuaa client_id>",
  "HTML5.ForwardAuthToken": "false",
  "tokenServiceURL": "<AssertionConsumerService from your BTP subaccount SP metadata>",
  "tokenServicePassword": "<xsuaa client_secret>",
  "HTML5.DynamicDestination": "true",
  "clientKey": "<xsuaa client_id>",
  "nameIdFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
  "scope": "openid",
  "SystemUser": "<email>"
}

This destination definition can be either created upfront or could be added to the mta.yaml deployment file to have it created/ updated automatically…

Good to know:

  • The destination service will accept either a technical SystemUser or a digitally signed user JWT. It will then generate a saml assertion and will pass it to the OAuth2 service provider for validation and will eventually retrieve a bearer access token.
  • SystemUser property comes in handy only for testing/troubleshooting purposes.
  • In a productive scenario one will need to provide a digitally signed user JWT token in the X-user-token header of a destination service find destination call. Please refer to official SAP help pages for further details: User Propagation via SAML 2.0 Bearer Assertion Flow | SAP Help

Conclusion

Last but not least, I hope you enjoyed reading this blog. Please provide your feedback in the comments section below.

Overall I was able to demonstrate how to get access to a BTP micro-service from anywhere using an IDP-initiated flow with a BTP sub-account acting as a Service Provider. Literally by-the-book.

You may also refer to appendix and gists for further details on the application structure and build.


 

Troubleshooting

Please make sure you can call any backend service endpoint directly as follows:

curl -H 'Authorization: Bearer <token>' <backend service URL endpoint>

 

Appendix

HAA (HANA Analytics Adapter)

This project has been scaffolded using the following Yeoman generator.

Please refer to the following gist for further details.

Build MTA

Please refer to the following gist for further details.

$ mbt build -p=cf --mtar=haa-test.mtar

Deploy MTA

Please refer to the following gist for further details.

$ cf deploy mta_archives/haa-test.mtar
Deploying multi-target app archive mta_archives/haa-test.mtar in org <org> / space <space> as <email>...


Process finished.
Use "cf dmol -i ecfae7d3-88e4-11ec-a86b-eeee0a8xxxxx" to download the logs of the process.

 

Additional resources

 

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.