Skip to Content

Secure a Basic Node.js App with the Authorization and Trust Management Service (XSUAA)

test
0 %
Secure a Basic Node.js App with the Authorization and Trust Management Service (XSUAA)
Details

Secure a Basic Node.js App with the Authorization and Trust Management Service (XSUAA)

2020-02-07
Secure a basic single-tenant Node.js application with the Authorization and Trust Management Service (XSUAA).

You will learn

  • How to secure a basic Node.js application with user authentication
  • How to secure a certain part of your application with user authorization
  • How to assign authorizations (in the form of a role collection) to a user

Prerequisites

The goal of this tutorial is to secure and deploy a product list application with authentication and authorization, so only authenticated users with the correct authorizations are able to see the products within the application. Users without the necessary authorizations are able to log in to the application, but do not see the products.

The base for this tutorial is a Node.js application that uses the express framework and SAPUI5 to display a list of products (see screenshot).

ui5 product list application

XSUAA and the Application Router

To secure this product list application, two components are used. One is called the XSUAA service and the other one is called application router. The application router is used in combination with the XSUAA service to authenticate a user and route the user to the secured application.

The XSUAA plays the role of an OAuth authorization service whereas the application router plays the role of an OAuth client. Furthermore, the application router works as a central entry point to the application. For more information, check the links at the end of this tutorial.


Step 1: Prepare the application files

Prepare the index.js file

To prevent a direct call to your application without authentication, it is necessary to add some code to your application. In our example, you use the Node.js passport authentication middleware and configure it with the XSUAA JWT strategy.

  1. Go to the product-list/myapp folder.

  2. Open the index.js file.

  3. To use additional libraries, add the following lines of code below the line // secure the direct call to the application

    const passport = require('passport');
    const { JWTStrategy } = require('@sap/xssec');
    const xsenv = require('@sap/xsenv');
    
    // XSUAA Middleware
    passport.use(new JWTStrategy(xsenv.getServices({uaa:{tag:'xsuaa'}}).uaa));
    
    app.use(passport.initialize());
    app.use(passport.authenticate('JWT', { session: false }));
    

    This code prevents direct calls to the product list application without a valid JWT.

  4. To secure the product list with authorization checks, replace the line app.get('/products', getProducts); in the index.js file with the following code:

    app.get('/products', checkReadScope, getProducts);
    
    // Scope check
    function checkReadScope(req, res, next) {
    	if (req.authInfo.checkLocalScope('read')) {
    		return next();
    	} else {
        	console.log('Missing the expected scope');
        	res.status(403).end('Forbidden');
    	}
    }
    

    The checkReadScope function ensures that only a user with the correct authorizations can look at the products.

  5. Save the file.

Prepare the package.json file

Since there are now more modules used beside the express module, you have to add the relevant dependencies to your package.json file. In this case the dependencies for the modules passport, @sap/xsenv and @sap/xssec have to be added.

If you want to use SAP modules locally, you need to add the npm configuration: npm config set @sap:registry https://npm.sap.com

  1. Open the package.json file.

  2. Add the following dependencies:

    "dependencies": {
      "express": "^4.17.1",
      "@sap/xsenv": "^2.2.0",
      "@sap/xssec": "^2.2.4",
      "passport": "^0.4.1"    
    }
    
  3. Save the file.
Log on to answer question
Step 2: Prepare the application security descriptor

To use the XSUAA service, a file named xs-security.json is necessary. The file can define properties of the XSUAA service instance as well as different roles and authorizations. In this example the file contains a role template and a role collection with a Product List Viewer role, that enables the user later to view the products.

  1. Add a folder named security to your product-list folder.

  2. Within the folder, create a file named xs-security.json.

  3. Add the following content:

    {
    	"xsappname": "product-list",
    	"tenant-mode": "dedicated",
    	"scopes": [
    		{
    			"name": "$XSAPPNAME.read",
    			"description": "With this scope, USER can read products."
    		}
    	],
    
    	"role-templates": [
    		{
    			"name": "Viewer",
    			"description": "Role to get the list of products",
    			"scope-references": [
    				"$XSAPPNAME.read"
    			]
    		}
    	],
    	"role-collections": [
    		{
    			"name": "ProductListViewer",
    			"description": "Product List Viewer",
    			"role-template-references": [
    				"$XSAPPNAME.Viewer"
    			]
    		}
    	]
    }
    

    This creates a role collection with a role template, and a role with a reading scope, so a user with this role can view the products.

  4. Save the file

To learn more about the xs-security.json file, check the links at the end of this tutorial.

What scope does the user get with this role collection?
×
Step 3: Prepare the approuter files

The approuter will enable you to create a secure route to your application.

  1. Add a folder named approuter to your product-list folder.

  2. Within that folder create a file named package.json.

  3. Add the following content:

    {
        "name": "approuter",
        "dependencies": {
            "@sap/approuter": "^6.7.1"
        },
        "scripts": {
            "start": "node node_modules/@sap/approuter/approuter.js"
        }
    }
    
  4. Save the file.
  5. In the same folder, create a file named xs-app.json.

  6. Add the following content to that file:

    {
      "routes": [{
        "source": "^/products",
        "target": "/",
        "destination": "products-destination"
      }]
    }
    

    This will create a destination called products-destination. The destination is later referenced in the manifest.yml.

  7. Save the file.

    To learn more about the xs-app.json file, check the links at the end of this tutorial.

Log on to answer question
Step 4: Move static content to the application router

For performance reasons it is better to put the images of the application into a static resources folder with the application router.

  1. Navigate to the approuter folder.

  2. Add a folder named resources.

  3. Move the images folder from myapp/static/ into the approuter/resources folder.

By the end of these steps, your folder structure should look like this:

product-list
├── approuter
  ├──ressources
    ├── images
      ├── HT-1000.jpg
      ├── HT-1010.jpg
      ├── HT-1030.jpg
  ├── package.json
  ├──  xs-app.json
├── myapp
    ├── lib
        ├── repository.js
        ├── products.json
    ├── static
        ├── index.html
    ├── index.js  
    ├── package.json
├── security
    ├── xs-security.json
├── manifest.yaml
Log on to answer question
Step 5: Update the manifest file

In the manifest file you have to define a hostname for your application and add a destination. The manifest file is used to bind the XSUAA service instance to your application.

The steps show incrementally what parameters and values have to be added. To avoid indentation errors, you can just copy the whole code at the end.

  1. Navigate to the product-list folder.

  2. Open the file manifest.yaml.

  3. Give your application a specific host name with the parameter route. The route has to be unique in the whole Cloud Foundry landscape, so make sure to add a random part to the route, for example your initials and your day of birth, like product-list-ap25 and approuter-product-list-ap25. You also need the route to configure a destination later.

    applications:
    # Product List Application
    - name: product-list
      instances: 1
      memory: 128M
      routes:
        - route: product-list-ap25.cf.eu10.hana.ondemand.com
      path: myapp
      buildpacks:
        - nodejs_buildpack  
      timeout: 180
    
  4. Add the binding for the XSUAA service to your application.

      ...
      services:
        - xsuaa-service-tutorial
    
  5. Add the configuration data for the approuter:

    applications:
    ...
    
    # Application Router
    - name: approuter
      routes:
        - route: approuter-product-list-ap25.cfapps.eu10.hana.ondemand.com
      path: approuter
      buildpacks:
        - nodejs_buildpack
      memory: 128M
    
  6. Add a destination to the approuter.

    # Application Router
    ...
      env:
        destinations: >
          [
            {"name":"products-destination",
             "url":"https://product-list-ap25.cfapps.eu10.hana.ondemand.com",
             "forwardAuthToken": true}
          ]
    

    The name parameter is the same as previously defined in the file xs-app.json. the url parameter is the result of the host name of your application and the region of your Cloud Foundry landscape (https://<hostname>.cfapps.<region>.hana.ondemand.com). The forwardAuthToken parameter set to true ensures that the approuter forwards the JWT token to the destination.

  7. Add the bindings for the XSUAA service to the approuter.

    ...
      services:
        - xsuaa-service-tutorial
    
  8. Save the file.

When you completed the steps, your manifest.yml file should look like this:

applications:
# Application
- name: product-list
  instances: 1
  memory: 128M
  routes:
    - route: product-list-ap25.cfapps.eu10.hana.ondemand.com
  path: myapp
  buildpacks:
    - nodejs_buildpack  
  timeout: 180
  services:
    - xsuaa-service-tutorial

# Application Router
- name: approuter
  routes:
    - route: approuter-product-list-ap25.cfapps.eu10.hana.ondemand.com
  path: approuter
  buildpacks:
    - nodejs_buildpack
  memory: 128M
  services:
    - xsuaa-service-tutorial
  env:
    destinations: >
      [
        {"name":"products-destination",
         "url":"https://product-list-ap25.cfapps.eu10.hana.ondemand.com",
         "forwardAuthToken": true}
      ]
Log on to answer question
Step 6: Update the index.html file

Because your are calling the product list over the approuter with /products you need to make a small change within the index.html file.

  1. Navigate to the product-list/myapp/static folder.

  2. Replace line 24 in the index.html file with the following code.

    var productsUrl = "/products/products"; //  contains path mapping which is specified in xs-app.json
    
  3. Save the file.
Log on to answer question
Step 7: Create the XSUAA service instance

Before you can deploy your application, you need to create the service instance for the XSUAA.

  1. Log in to your Cloud Foundry account with the Cloud Foundry CLI.

  2. Navigate to the product-list folder.

  3. Create the XSUAA service instance with the xs-security.json security descriptor file.

    cf create-service xsuaa application xsuaa-service-tutorial -c security/xs-security.json
    
  4. Deploy the application.

    cf push
    
Log on to answer question
Step 8: Call your application from its secure route

Your application has two routes that are defined in the manifest.yml. The direct route to the application should return an error message saying unauthorized (because you don’t have a valid JWT yet). The secure route through the approuter redirects to a login screen. After logging in, the application opens but shows the message no data. To see the product data, you need to assign your user the role collection with the necessary authorizations.

  1. First make sure that your application can’t be reached on its direct URL:

    https://product-list-ap25.cfapps.eu10.hana.ondemand.com

    If everything is working correctly, this will result in an error message reading unauthorized.

  2. Navigate to your application with the secure route of your application router:

    https://approuter-product-list-ap25.cfapps.eu10.hana.ondemand.com/products

  3. Enter the e-mail and password of your trial account.

    You should see the no data message. This is because you don’t have the role assigned yet to view the products. You will do this in the next step.

Log on to answer question
Step 9: Assign the role collection

Assign your user the role collection that contains the necessary role to view the products in the product list.

  1. Open the SAP Cloud Platform Cockpit.

  2. Navigate to your subaccount.

  3. Choose the Security tab and choose Trust Configuration.

  4. Choose SAP ID Service.

  5. Enter your e-mail address and choose Show Assignments.

  6. Choose Assign Role Collection.

  7. Choose the ProductListViewer role collection.

  8. Call the URL of the approuter again (you might have to delete your cookies/cache before).

    https://approuter-product-list-ap25.cfapps.eu10.hana.ondemand.com/products

    The application will now show you the products.

Log on to answer question

Troubleshooting

Error message: the hostname of your application is already taken

To resolve this error, please edit the manifest.yml file and change the route parameter of the product list application or the route parameter of the approuter (depending on which hostname is already taken). If you change the parameter of the product list application, make sure to change the url parameter under destinations as well.

Resources


Next Steps

Back to top