How grant-types keep your application secure – lab setup

In this post I layout the lab setup for the exercises mentioned in my article “How grant-types keep your application secure?“. The lab exercises are for examining the influence of configuration parameter grant-type. You may use this as a setup for further exploration. I would be curious to know what you explored. Please share your own experiments in the comments.

Pre-requisite:

  1. Access to a space in SAP BTP Cloud Foundry runtime with 1 GB memory with developer role. If you have completed Get Ready to Develop on SAP BTP | Tutorials for SAP Developers, you are ready.
  2. Terminal (Power Shell/Bash Shell) with following in PATH. Instructions for installation of these are in Configure Essential Local Development Tools | Tutorials for SAP Developers

Lab Setup

Create a new directory and create files with names and content from Appendix 1.

Install the tools. Open a terminal with the directory you created in the previous step as the current directory and execute the commands given below:

> npm init -y
> npm install -D open jwt-decode > npm install -g httpyac 

Login to your Cloud Foundry space. See step 3, 4 of Install the Cloud Foundry Command Line Interface (CLI). These steps are outlined below:

# get the api url for your SAP BTP, Cloud Foundry environment
> cf api <SAP BTP, Cloud Foundry API Endpoint> # Login using SSO (or skip -sso to use password)
> cf login --sso

Login to SAP BTP command line interface (btp CLI). See step 6 of Get Started with the SAP BTP command line interface (btp CLI) for how to login to SAP BTP command line interface (btp CLI). These are shown below:

> btp login --sso
...
...
OK
...

Build and deploy the application with commands shown below:

> npx mbt build -t .
...
INFO the MTA archive generated at: cf-application_1.0.0.mtar
INFO cleaning temporary files... > cf deploy cf-application_1.0.0.mtar -f --no-start
...
Process finished.
...

This creates 2 XSUAA service instances. These stand for 2 applications in SAP BTP, Cloud Foundry environment.

  • cf-application-uaa is the XSUAA service instance bound to Business Logic Application
  • cf-approuter-uaa is the XSUAA service instance bound to Application Router.

Typically when deploying a standalone Application Router and a Business Logic Application, they bind to the same XSUAA service instance. In this exercise the Application Router is considered to bind to an independent XSUAA service instance. This is to illustrate the scenario using managed Application Router or another independently developed application.

We need to create keys for these and copy credentials to a file for the tool we use (httpyac) in the exercises.

> cf create-service-key cf-application-uaa key1
..
> cf service-key cf-application-uaa key1
..{ "apiurl": "https://api.authentication.us10.hana.ondemand.com", "clientid": "sb-cf-approuter!t53187", "clientsecret": "045c6fe0-4df2-4ff7-BwhlOAVUxlXCqDvUHYW4lSKJyhNLjfXjpTuo=", "credential-type": "binding-secret", "identityzone": "provider-2022", "identityzoneid": "3caxxxxe-4c10-488e-xxxx-2877xxxxf6a6", "sburl": "https://internal-xsuaa.authentication.us10.hana.ondemand.com", "subaccountid": "33caxxxxe-4c10-488e-xxxx-2877xxxxf6a6", "tenantid": "3caxxxxe-4c10-488e-xxxx-2877xxxxf6a6", "tenantmode": "shared", "uaadomain": "authentication.us10.hana.ondemand.com", "url": "https://provider-2022.authentication.us10.hana.ondemand.com", "verificationkey": "-----BEGIN PUBLIC KEY-----....----END PUBLIC KEY-----", "xsappname": "cf-approuter!t53187", "zoneid": "3ca405fe-4c10-488e-a634-2877bdebf6a6"
}

Modify the file .env with content as follows with values obtained in command above. This is for configuring the tool httpYac we use in exercises.

  • blApp_xsappname as xsappname
  • blApp_clientId as clientid
  • blApp_clientSecret as clientsecret
  • blApp_url as url

Sample for values in the file with values from the command above above is:

# file: .env
blApp_xsappname=cf-application!t53187
blApp_clientId=sb-cf-application!t53187
blApp_clientSecret=045c6fe0-4df2-4ff7-BwhlOAVUxlXCqDvUHYW4lSKJyhNLjfXjpTuo=
blApp_url=https://xxx.authentication.xxNN.hana.ondemand.com blApp_tokenEndpoint={{blApp_url}}/oauth/token
blApp_authorizationEndpoint={{blApp_url}}/oauth/authorize
blApp_scope=" " 

Set a shell variable subaccount to value of subaccountid.

#in Powershell
> $subaccount="3caxxxxe-4c10-488e-xxxx-2877xxxxf6a6"
#in bash
> subaccount="3caxxxxe-4c10-488e-xxxx-2877xxxxf6a6"

Repeat the above steps for the second xsuaa instance and update the file .env

> cf create-service-key cf-approuter-uaa key1
..
> cf service-key cf-approuter-uaa key1
..

Update the file .env with the content modified as follows with values for key1 from command above.

  • approuter_xsappname as xsappname
  • approuter_clientId as clientid
  • approuter_clientSecret as clientsecret
  • approuter_url as url

Sample for values in the file with values for key1 above is:

approuter_xsappname=cf-approuter!t53187
approuter_clientId=sb-cf-approuter!t53187
approuter_clientSecret=4e494f95-428a-4829-9a5d-f958gc6fx1Pg_3Hgi9kB3_RvtGsSKQsrs=
approuter_url=https://provider-2022.authentication.xxNN.hana.ondemand.com approuter_tokenEndpoint={{approuter_url}}/oauth/token
approuter_authorizationEndpoint={{approuter_url}}/oauth/authorize
approuter_scope=" "
approuter_redirectUri=http://localhost:3030/callback

Examine the lab setup

Copy the value of xsappname from the key of cf-application and execute the command shown below.

> btp get security/app cf-application!t53187 --subaccount $subaccount
appid: cf-application!t53187
xsappname: cf-application
planName: application
description: <null>
orgId: f2abe5d1-6906-4087-b088-70a886afc711
spaceId: <null>
userName: <null>
planId: ThGdx5loQ6XhvcdY6dLlEXcTgQD7641pDKXJfzwYGLg=
serviceinstanceid: e42921a1-f21d-4720-b1e4-57afa192cc70
masterAppId: <null>
tenant-mode: shared
scopes:
- description: Change grant type Excercise - Scope 1 name: cf-application!t53187.Excercise_User_Scope_1
- description: Change grant type Excercise - Scope 1 name: cf-application!t53187.Excercise_System_Scope_1
foreign-scope-references:
authorities:
- cf-application!t53187.Excercise_System_Scope_1
attributes:
role-templates:
- name: Excercise_Role_1 description: Change grant type Excercise - Role 1 version: JJBej3UQSHJKD7r+IkSTcsQncvwWwMSroxUvLJFrSSM= scope-references: - cf-application!t53187.Excercise_User_Scope_1 attribute-references: appId: cf-application!t53187
capability-types:
instance-authorization:
oauth2-configuration: token-validity: 0 refresh-token-validity: 0 autoapprove: true grant-types: - client_credentials system-attributes: allowedproviders: <null> redirect-uris: credential-types: - binding-secret - x509

Note there are two scopes, one of which is assigned to a role template. The other scope is assigned to authorities. Compare this to the configuration in the file xs-security.json.

Note that only client-credentials is listed for grant-types. Compare this with the entry for cf-application in the file mta.yaml.

Use the tool httpYac to get a token.

> npx httpyac oauth2 --prefix blApp
eyJh.......
....

The output looks like gibberish. But it is not. Lets examine the output.

> npx httpyac oauth2 --prefix blApp | node decode-jwt.js
{ "jti": "5d0c373fd5954b4abce2fe1317d56bb7", "ext_attr": { "enhancer": "XSUAA", "subaccountid": "3caxxxxe-4c10-488e-xxxx-2877xxxxf6a6", "zdn": "provider-2022" }, "sub": "sb-cf-application!t53187", "authorities": [ "uaa.resource", "cf-application!t53187.Excercise_System_Scope_1" ], "scope": [ "uaa.resource", "cf-application!t53187.Excercise_System_Scope_1" ], "client_id": "sb-cf-application!t53187", "cid": "sb-cf-application!t53187", "azp": "sb-cf-application!t53187", "grant_type": "client_credentials", "rev_sig": "cccggg", "iat": 9999999999, "exp": 9999999999, "iss": "https://provider-2022.authentication.us10.hana.ondemand.com/oauth/token", "zid": "3caxxxxe-4c10-488e-xxxx-2877xxxxf6a6", "aud": [ "uaa", "cf-application!t53187", "sb-cf-application!t53187" ]
}

Conclusion

  1. you have setup the lab for exercises
  2. you learnt to examine application configuration using SAP BTP command line interface (btp CLI)
  3. you know how to get tokens using httpyac
  4. you know how to decode and examine JWT with the script in the setup

Next Steps

Proceed with the lab exercises to examine further:

  1. Exercise 1 – grant types for basic user propagation
  2. Exercise 2 – grant types for basic user propagation (to be published)
  3. Exercise 3 – grant types for external user propagation (to be published)

Appendix 1 – Files for Exercises

Make a new directory and copy the content to the files.

Folder Structure

mta.yamlxs-security.json.env decode-jwt.js
│
└───srv/ package.json

mta.yaml

---
_schema-version: '3.1'
ID: cf-application
version: 1.0.0 modules: - name: cf-application-srv type: nodejs path: srv parameters: buildpack: nodejs_buildpack command: npx http-server instances: 0 #dont-start the app memory: 16M disk-quota: 50M no-route: true build-parameters: builder: custom commands: [] include: ["package.json"] requires: - name: cf-application-uaa resources: # this represents a Business Logic Application - name: cf-application-uaa type: org.cloudfoundry.managed-service parameters: service: xsuaa service-plan: application path: ./xs-security.json config: xsappname: cf-application oauth2-configuration: credential-types: - binding-secret - x509 system-attributes: [] grant-types: - client_credentials # this represents a managed Application Router - name: cf-approuter-uaa type: org.cloudfoundry.managed-service parameters: service: xsuaa service-plan: application config: xsappname: cf-approuter role-templates: - name: Token_Exchange description: for User Token exchange scope-references: - uaa.user oauth2-configuration: credential-types: - binding-secret - x509 system-attributes: [] autoapprove: true grant-types: - authorization_code 

srv/package.json

{ "name": "cf-application-srv", "version": "1.0.0", "description": "Change grant-types Exercise - Server", "keywords": [ "xsuaa", "cf" ], "license": "ISC", "dependencies": { "http-server": "^14.1.1" }
}

xs-security.json

{ "scopes": [ { "name": "$XSAPPNAME.Excercise_User_Scope_1", "description": "Change grant type Excercise - Scope 1" }, { "name": "$XSAPPNAME.Excercise_System_Scope_1", "description": "Change grant type Excercise - Scope 1" } ], "authorities": ["$XSAPPNAME.Excercise_System_Scope_1"], "role-templates": [ { "name": "Excercise_Role_1", "description": "Change grant type Excercise - Role 1", "scope-references": [ "$XSAPPNAME.Excercise_User_Scope_1" ] } ], "role-collections": [ { "name": "Excercise_Role_Collection_1", "description": "Change grant type Excercise - Role Collection 1", "role-template-references": [ "$XSAPPNAME.Excercise_Role_1" ] } ]
}

.env

## Begin .env ## cf-application-uaa key1
blApp_xsappname=cf-application!tnnnn
blApp_clientId=sb-cf-application!tnnnn
blApp_clientSecret=
blApp_url=https://xxx.authentication.xxNN.hana.ondemand.com blApp_tokenEndpoint={{blApp_url}}/oauth/token
blApp_authorizationEndpoint={{blApp_url}}/oauth/authorize
blApp_scope=" " ## cf-approuter-uaa key1
approuter_xsappname=cf-approuter!tnnnnn
approuter_clientId=sb-cf-approuter!tnnnn
approuter_clientSecret=
approuter_url=https://xxx.authentication.xxNN.hana.ondemand.com approuter_tokenEndpoint={{approuter_url}}/oauth/token
approuter_authorizationEndpoint={{approuter_url}}/oauth/authorize
approuter_scope=" "
approuter_redirectUri=http://localhost:3030/callback ## End

decode-jwt.js

 const chunks = []; process.stdin.on('readable', () => { let chunk; while ((chunk = process.stdin.read()) !== null) chunks.push(chunk) }); process.stdin.on('end', () => { const token = chunks.join(""); const decoded = require("jwt-decode")(token); console.log(decoded) });