How grant-types keep your application secure – Exercise 2

This post has the second set of exercises demonstrating different grant types described in my article “How grant-types keep your application secure?“. This exercise looks at the grant types that derive authorization indirectly, from authorization of a token. This is what is useful for principal propagation from one application to another. 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. You have completed the lab setup as outlined in the post.
  2. You have assign the role collection “Excercise_Role_Collection_1” to the user you use for testing. This was done part of the previous set of exercises.Refer to the blog Demystifying XSUAA in SAP Cloud Foundry on how to assign a role collection to a user using SAP BTP Cockpit. It is easy to assign a role collection to a user using SAP BTP command line interface (btp CLI) too as shown below. If the user is not from the Default identity provider, substitute the key for the identity provider in place of sap.default.
    # $subaccount is the id of the subacoount and # $user is the user id (usually an email) of the user
    # in IDP sap.custom. Here sap.custom is the key for the trusted IAS tenant assigned by assign trust button. # For SAP ID service the key is sap.default btp assign security/role-collection Excercise_Role_Collection_1 --to-user $user --of-idp sap.custom --subaccount $subaccount
    

Introduction

I found httpyac to be a great tool for experiments with oAuth. The file .env you created during lab setup is for configuring the tool httpYac. This is to avoid typing the configuration every time. We will use this tool extensively in the exercises.

In this exercise we will examine the following grant types:

  • User Token grant
  • JWT Bearer Token grant

In this exercise we explore the options for a client application (for example Application Router) to request services of Business Logic Applications as illustrated in the diagram below:

The client (from XSUAA service instance) used by the Application Router is considered here to be different from the client trusted by the Business Logic Applications it requests services from. So it has to convert the token it has with user authorization to to a token accepted by the Business Logic Applications. In a typical case with standalone Application Router, Application Router is bound to the same xsuaa instance as the Business Logic Application. So, the client for which the token is issued is same one the Business Logic application trusts. There is no need for such a conversion as the token Application Router has, will be accepted by the Business Logic Application. This token can be forwarded as it is to the Business Logic Application.

Side Note:

The applications in SAP BTP, Cloud Foundry environment that calls other Applications typically use destinations to get the credentials of the client of Business Logic Applications. But the scenario is also applicable when a Business Logic Application accesses services in user context from services for which it has credentials via binding.

User Token

We need to make changes to the deployment, enable the grant type User Token for an  xsuaa instance. So, deploy the mta again, now with an extension descriptor. The descriptor configures the XSUAA service instances with the required grant types.

Copy the contents below as file mta-ext-ex2a.yaml

---
_schema-version: '3.1'
ID: cf-application-ext-2a
extends: cf-application
version: 1.0.0 resources: - name: cf-application-uaa parameters: config: oauth2-configuration: grant-types: - refresh_token - name: cf-approuter-uaa parameters: config: oauth2-configuration: grant-types: - authorization_code - user_token

Execute the following commands to deploy the package with the extension descriptor copied in the earlier step. The extension descriptor, adds user_token as a allowed grant type to cf-approuter-uaa and refresh_token to cf-application-uaa. You can check that these grant types are added to the oAuth client with SAP BTP command line interface (btp CLI) as shown below.

cf deploy cf-application_1.0.0.mtar -e mta-ext-ex2a.yaml -f --no-start
.. > btp get security/app cf-approuter!t53187 --subaccount $subaccount
.. grant-types: - authorization_code - user_token
.. > btp get security/app cf-application!t53187 --subaccount $subaccount
.. grant-types: - refresh_token
..

In this exercise Application Router will request a token using authorization code grant and then request for converting this token to a token for the client of Business Logic Application. User Token grant can be used with any token with scope uaa.user issued for a client which is configured to support user_token grant type.

Copy the contents below to file exercise-2a.http

### user_token with uaa.user scope
# @name token_response
@approuter_scope=uaa.user openid
POST {{approuter_url}}/oauth/token Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: oauth2 authorization_code approuter grant_type=user_token
&client_id={{blApp_clientId}} ### refresh_token : Get Token for Business Logic Application
# @ref token_response
# @name bl_token_response
# @jwt access_token
POST {{blApp_url}}/oauth/token Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{blApp_clientId}} {{blApp_clientSecret}} grant_type=refresh_token
&refresh_token={{token_response.refresh_token}} ### user_token with only openid scope - this fails.
@approuter_scope=openid
POST {{approuter_url}}/oauth/token Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: oauth2 authorization_code approuter grant_type=user_token
&client_id={{blApp_clientId}}

This file describes two requests. The first is for a refresh token using grant type user_token. The next request uses the refresh token and requests for access token using grant type refresh_token. Lets make the requests and see with the following command.

Start in the terminal and enter the command.

npx httpyac exercise-2a.http -i
  1. Use the arrow keys to select the first option “user_token with uaa.user scope”.
    This will request for authorization code in browser. After successful authorization, it requests for an access token and then uses the access token to request for a token for a different client using user_token grant. This call returns with only refresh_token.
  2. Use the arrow keys to select the second option “refresh_token : Get Token for Business Logic Application”.
    This will use the previously received refresh_token to and request for an oken. This call returns with refresh_token and access_token, but no id_token.
  3. Use the arrow keys to select the second option “user_token with only openid scope – this fails.”.
    This will request for authorization code in browser. After successful authorization, it requests for an access token and then uses the access token to request for a token for a different client using user_token grant. This call fails as the access_token does not have uaa.user scope.
  4. Use Ctrl-C (break) to come out the interactive mode to terminal prompt.

Note that you can execute the steps in Visual Studio Code with plugin httpYac – Rest Client as well.

JWT Bearer Token

We need to make changes to the deployment, enable the grant type JWT Bearer Token for an xsuaa instance. So, deploy the mta again, now with an extension descriptor. The descriptor configures the XSUAA service instances with the required grant types.

Copy the contents below as file mta-ext-ex2b.yaml

---
_schema-version: '3.1'
ID: cf-application-ext-2b
extends: cf-application
version: 1.0.0 resources: - name: cf-application-uaa parameters: config: oauth2-configuration: grant-types: - urn:ietf:params:oauth:grant-type:jwt-bearer - name: cf-approuter-uaa parameters: config: oauth2-configuration: grant-types: - password #workaround - authorization_code

Execute the following commands to deploy the package with the extension descriptor copied in the earlier step. The extension descriptor, adds JWT bearer as a allowed grant type to cf-application-uaa. It also adds password grant type to cf-approuter-uaa. You can check that these grant types are added to the oAuth client with SAP BTP command line interface (btp CLI) as shown below.

cf deploy cf-application_1.0.0.mtar -e mta-ext-ex2b.yaml -f --no-start
.. > btp get security/app cf-approuter!t53187 --subaccount $subaccount
.. grant-types: - authorization_code - password
.. > btp get security/app cf-application!t53187 --subaccount $subaccount
.. grant-types: - urn:ietf:params:oauth:grant-type:jwt-bearer
..

In this exercise the Application Router requests token using password grant type (with passcode) and then requests for converting this token to a token for the client of Business Logic Application using JWT Bearer grant type. Application Router normally requests token for the user using authorization code grant. But this exercise uses passcode as a workaround. The tool (httpyac) does not provide id_token using the shortcut notation and the shortcut notation is only for use of the token as Authorization header.

Copy the contents below to file exercise-2b.http

### Passcode: Get Approuter Token {{ const open = require("open") const passcode_url = `${approuter_url}/passcode` open(passcode_url);
}} # @name token_response
# @jwt id_token
POST {{approuter_url}}/oauth/token Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{approuter_clientId}} {{approuter_clientSecret}} grant_type=password
&passcode={{$password Enter Passcode}}
&scope=openid ### JWT Bearer Token: Get Token for Business Logic Application
# @ref token_response
# @name bl_token_response
# @jwt access_token
POST {{blApp_url}}/oauth/token Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{blApp_clientId}} {{blApp_clientSecret}} grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion={{token_response.id_token}}

This file describes two requests, first using password for id token and next using the id token request for an access token for another client. Lets make the requests and see with the following command.

Start in the terminal and enter the command.

npx httpyac exercise-2b.http -i
  1. Use the arrow keys to select the first option “user_token with uaa.user scope”.
    This will request for temporary authentication code in browser. After successful authorization, it requests for an access token and then uses the access token to request for a token for a different client using user_token grant. This call returns with only refresh_token.
  2. Use the arrow keys to select the second option “refresh_token : Get Token for Business Logic Application”.
    This will use the previously received refresh_token to and request for an oken. This call returns with refresh_token and access_token, but no id_token.
  3. Use the arrow keys to select the second option “user_token with only openid scope – this fails.”.
    This will request for authorization code in browser. After successful authorization, it requests for an access token and then uses the access token to request for a token for a different client using user_token grant. This call fails as the access_token does not have uaa.user scope.
  4. Use Ctrl-C (break) to come out the interactive mode to terminal prompt.

In Visual Studio Code:

Key Learnings

  • How to update grant types using MTA extension descriptor
  • Converting a token using User Token grant requires two requests whereas same with JWT bearer Token grant requires only one
  • Converting a token using User Token grant requires the client to have configuration allowing for user_token grant and the token to have authorization for uaa.user scope, whereas same with JWT bearer Token grant requires the only the Business Logic Application to have configuration allowing jwt-bearer grant.
  • How to use passcode with password grant as an alternate to authorization code grant

Next Steps

Did you understand a bit more about XSUAA service with this exercise? Please let me know in the comments.

Do you remember using one of these grant types when configuring destinations for Managed Application Router in the context of SAP Launchpad service? If not examine this developer tutorial.

Proceed with the other lab exercises to examine further: