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:
- 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.
- 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
- Node.js runtime with npm
- Cloud MTA Build Tool (MBT)
- Cloud Foundry Command Line Interface (CLI) with multiapps plugin
- SAP BTP command line interface (btp CLI)
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
- you have setup the lab for exercises
- you learnt to examine application configuration using SAP BTP command line interface (btp CLI)
- you know how to get tokens using httpyac
- you know how to decode and examine JWT with the script in the setup
Next Steps
Proceed with the lab exercises to examine further:
- Exercise 1 – grant types for user authorization
- Exercise 2 – grant types for basic user propagation
- Exercise 3 – grant types for external user propagation
Appendix 1 – Files for Exercises
Make a new directory and copy the content to the files.
Folder Structure
│ mta.yaml │ xs-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)
});