Technical Articles
Application Router | Migrating from the Neo Environment to the Multi-Cloud Foundation
This blog post series is about developing applications in a multi-cloud environment.
For the end-to-end hands-on tutorial example, see
For the step-by-step series, visit
Questions? Post as comment. Useful? Give us a like and share on social media. Thanks! |
Hands-On Tutorials
Application Router
In this blog series, we explore developing secure applications in a multi-cloud Cloud Foundry environment. This blog is about the application router.
In this blog, we
- Create a security descriptor file (xs-security.json) for XSUAA
- Create an XSUAA service instance
- Create an application router (courtesy of SAP)
- Update the application manifest for the approuter
- Validate access to the approuter requires authentication (but not yet for the business app)
Approuter and XSUAA Service
In this fifth video of the series, we show how we can create and configure an instance of the XSUAA service and how to add an approuter to our app to serve as endpoint.
Sample Code
As before, we continue with the (slightly modified) sample code from SAP Cloud Platform documentation:
You can download the sample code from repository
Appendix
For more detailed information about the SAP Cloud Platform trial environment, Cloud Foundry buildpacks, dependencies declarations, attributes, Diego cells and more, see the “appendix” blog
Note: SAP HANA eXtended Application Services, in short XS, was introduced in an early release of the SAP HANA 1.0 platform (SPS 05, 2012) to provide built-in application server services, based on the open-source SpiderMonkey Mozilla JavaScript runtime. This architecture was superseded three years later with another SAP implementation this time of the open-source Cloud Foundry environment (SPS 11, 2015), internally referenced at the time as XS 2 and officially named XS Advanced, or XSA. This Cloud Foundry “/4HANA” implementation is very similar and compatible with the SAP Cloud Platform Cloud Foundry environment except for some branding and functionality specific to the in-memory platform. For example, the CLI is called xs (not cf) but is the same otherwise.
The service broker for SAP HANA was specifically developed for this environment and other services were adapted to the platform like the SAP XSUAA implementation of the Cloud Foundry UAA service, using a file in JSON format named xs-security for its configuration.
Compare
- Set up Authentication for your XS Advanced JavaScript Application, SAP HANA Developer Guide for SAP HANA XS Advanced Model
- Authentication Checks in Node.js Applications, SAP Cloud Platform
The XSUAA Programming Model
The architecture diagram shows the components involved. The first station a browser (UI/User Agent) request arrives at is the Cloud Foundry Router of the SAP Cloud Foundry environment on the SAP Cloud Platform; this is a platform component managed by SAP. The Cloud Foundry Router forwards the request to the Application Router. This is a component we manager ourselves and we will show you how we construct one in this blog. The Application Router interacts with the UAA and Identity Provider for Security and Session Services using Access Tokens. With these tokens the user request then interacts with the business service in a runtime container.
As an analogy, the user arrives at the hotel (router) and is directed to the reception (application router). The receptionist (UAA) verifies the identity using passport (authentication) and credit card (authorisation). The user gets a room key (token). With this token the user can access the room (business service).
The SAP Cloud Platform uses SAP Cloud Identity Services as default Identity Provider (IdP) but any SAML 2.0 IdP can be used as alternative.
As documented
- The XSUAA Programming Model
- Web Access in the Cloud Foundry Environment
- SAP Cloud Identity Services | SAP Community
Authorization Flow
In case you are interested in the flow, see
Cheat Sheet
Confused about the jargon? Here is a refresher.
- SAML 2.0 (2005) – standard to exchange authentication and authorization data between identity and service providers (website). XML-based (and a bit clunky as a result). Dates from early 2000s and works great for web browsers but not with apps and mobile devices
- Oauth 2.0 (2012) – standard for access delegation using tokens. Is an authorization framework with several use cases (the diagram above is just one). It is not a protocol (like SAML)
- OIDC / OpenID Connect (2014) – provides authentication for OAuth authorization framework.
- JWT / JSON Web Tokens (2010) – format to exchange tokens in JavaScript Object Notation which is considerably more lightweight when compared to XML. OAuth flows use both SAML (XML) assertions as JWT.
As a reminder, the concepts were also covered in a previous blog.
XSUAA Service Instance
Security Descriptor | xs-security.json
Creating a service instance for the XSUAA service is similar to creating other services, like we did for SAP HANA Cloud or an HDI Container for example, although it this case we need to provide a security descriptor file in JSON format named xs-security.
This file tat defines the details of the authentication methods and authorization types to use for access to your application.
As documented,
Although we can add specify scopes (display, edit, delete), attributes, and roles in this file, for now we are going to keep things simple and only reference the (business logi) app name. This should make sense, as the XSUAA service instance needs to know which app(s) it needs to manage the security for.
{
"xsappname" : "myapp",
"tenant-mode":"dedicated"
}
Create XSUAA Service Instance
Command Line
We then use the security descriptor file to create a service instance of XSUAA using the same create-service command specifying SERVICE, PLAN, and a service instance NAME plus the parameters:
Valid JSON object containing service-specific configuration parameters, provided either in-line or in a file. For a list of supported configuration parameters, see documentation for the particular service offering.
As documented in the Cloud Foundry CLI Reference Guide
# query the marketplace for the xsuaa service
cf m -s xsuaa
# create an instance using security descriptor file (choose one)
cf create-service xsuaa application myxsuaa -c xs-security.json
cf create-service xsuaa application myxsuaa
-c '{"xsappname":"myapp", "tenant-mode":"dedicated"}'
# query service configuration
cf service myxsuaa
SAP Cloud Platform Cockpit
For one-off situations, we can also use a wizard in the SAP Cloud Platform cockpit to create the instance and either upload the security descriptor file or specify the parameters in JSON format.
This works exactly the same as in this case the web interface calls the cf create-service command.
Parameter tenant-mode=dedicated is the default value and can be omitted.
The SAP Cloud Platform cockpit displays this information at the Cloud Foundry space level: Services > Service Instances
Here we can also find the information about UAA service plans from the Service Marketplace (again, same cf marketplace commands).
Application Router
SAP Application Router Package
To enable authentication for our we app we are going to add an application router.
As documented:
The application router is the single point of entry for an application running in the Cloud Foundry environment on SAP Cloud Platform. The application router is used to serve static content, authenticate users, rewrite URLs, and forward or proxy requests to other micro services while propagating user information.
SAP has made the application router available as Node.js package.
See also
- SAP Application Router by Zvi Zeltser
- SAP Cloud Platform Backend service: Tutorial [24]: Understanding: App Router (1) by Carlos Roggan
- SAPUI5 Applications with Approuter: Sessions and Automatic Logout by Riley Rainey
Sample Home Page
For the app router, create an index.html file in web/resources with a link pointing to /myapp. and to /myapp/hana.
Application Descriptor (package.json)
Initialise Node (i.e. generate a package.json file) in the web directory as in the previous blog.
npm init -y
Add App Router Package
Install the approuter package in web/node_modules/@sap
npm i @sap/approuter
The command adds 248 packages with the usual (deprecated) warnings. Two we caused ourselves by not providing a description and repository field when executing node init.
Besides approuter, three logging-related packages are added plus xsenv and xssec.
Note: Prior to June 2020 we had to specify the SAP NPM Registry (https://npm.sap.com) for packages but this registry is being retired (end of 2020). Contents have been migrated to the public npm registry (https://registry.npmjs.org).
As documented,
In case you get error: Not Found – GET https://registry.nodejs.org/@sap%2fapprouter, your environment may still point to the SAP registry, see SAP NPM packages now on npmjs.org.
|
Add Start Command
The package.json file contains the start command for the application router and a list of package dependencies. Add the command to start the approuter.
"start": "node node_modules/@sap/approuter/approuter.js"
Add Application Router Configuration
The application router is configured in the xs-app.json file. This file is located, like the application descriptor file package.json in the root of the approuter directory.
In this configuration file we configure the approuter for authentication, proxying/routing/rewriting. The configuration below configures the approuter to redirect any request for /myapp to a destination with name myapp. By default, every route requires authentication, so the requests to this path will require an authenticated user.
As documented,
{
"routes": [
{
"source": "^/myapp/(.*)$",
"target": "$1",
"destination": "myapp"
}
]
}
Note: In case you wondered what the ^ and (.*)$ all means, its RegEx. Not very user-friendly but extremely versatile and powerful.
- Learn Regular Expressions, freeCodeCamp free course
App Deployment
App Manifest
As with the service instance for SAP HANA Cloud (or the HDI Container to be precise), we need to bind the myxsuaa service instance to our application router (web) and to our business logic app (myapp).
The destination referenced in the app router configuration file (xs-app.json) is provided here as environment variable. The URL here is set (fixed), so we need to provide a set route as well. Using a random route would not work.
For more information about routes, see the
---
applications:
- name: myapp
path: myapp
buildpacks:
- nodejs_buildpack
routes:
- route: myapp-101520.cfapps.eu10.hana.ondemand.com
memory: 128M
services:
- hdicontainer-1
- myxsuaa
- name: approuter
path: approuter
buildpacks:
- nodejs_buildpack
random-route: true
memory: 128M
env:
destinations: >
[
{
"name":"myapp",
"url":"https://myapp-101520.cfapps.eu10.hana.ondemand.com",
"forwardAuthToken": true
}
]
services:
- myxsuaa
Command Line
When we run the command to deploy both apps are build and bound to the services.
# housekeeping
cf d[elete] myapp -r -f
# deploying
cf push
# running
cf a[pps]
MyApp
When we query the approuter URL (here a random route) a log on page is returned
https://approuter-generous-quoll-vr.cfapps.eu10.hana.ondemand.com
The configured (default) identity provider is SAP ID Services and the Node approuter app redirects to
https://accounts.sap.com/saml2/idp/sso
Should we provide incorrect authorization information, XSUAA displays a (default) error page.
When the log on succeeds we are redirected back to the approuter for the home page (index.html). The business logic was covered in the previous blog:
- The URL /myapp points to the / and function res.send is executed.
- The URL /myapp/hana points to /hana and function req.de.exec is executed
<a href="/myapp/">myapp</a>
<a href="/myapp/hana">myapp/hana</a>
Note that we remain connected to the app router (URL). We are not redirected to the business app.
Note also that as we have not made any changes regarding restrictions, direct access to the myapp URLs also continue to work. We will address this in the next blog.
SAP Cloud Platform Cockpit
The Service Instances menu shows the service instances we created plus their bindings.
When we select the approuter, the destination is listed as user-provided environment variable.
The service bindings provide the information (e.g. clientid, clientsecret, and certificate) for the apps to communicate with each other.
Additional Information
Blogs
Please Proceed
We now have covered the out-of-the-box authentication provided by the (SAP) Application Router. In the next blog we explore how we can adapt our Business Logic App to provide integrated authentication.
Share and Connect
Questions? Please post as comment.
Useful? Give us a like and share on social media.
Thanks!
If you would like to receive updates, connect with me on
- LinkedIn > linkedin.com/in/dvankempen
- Twitter > @dvankempen
For the author page of SAP PRESS, visit
Over the years, for the SAP HANA Academy, SAP’s Partner Innovation Lab, and à titre personnel, I have written a little over 300 posts here for the SAP Community. Some articles only reached a few readers. Others attracted quite a few more.
For your reading pleasure and convenience, here is a curated list of posts which somehow managed to pass the 10k-view mile stone and, as sign of current interest, still tickle the counters each month. |
This is a really detailed body of work, Denys. Thanks for such an epic article. There's a lot you point out in this that I look forward to trying first-hand.
Hi Denys van Kempen,
Is there any way to forward the cookies from the approuter to the backend?
Regards,
Satvindar
Good question, Satvindar,
Have not looked into this topic yet.
Would this help?
See also the FAQ section of
Thanks, Denys, for sharing the links.
The issue is Gorouter is generating a session cookie for 2 app instances but the same cookie is not getting forwarded to Gorouter from the app router which is resulting in a 403 forbidden error for all update/create calls.
Is there any way we can handle such a situation from the app router as the backend is handling the CSRF protection?
Thanks and regards,
Satvindar
Good question, Satvindar, 😉
Maybe Marius Obert knows?
I'm afraid I haven't seen this yet and I don't know the answer. I know that the approuter recently started to forward API Keys, so maybe that's something for a feature request then.