I describe what are grant types and what are the different grant types available to an application in SAP BTP Cloud Foundry environment in this article. I look at which grant types are needed for different use cases. The focus is on SAP BTP, Cloud Foundry runtime. This article shows what administrators of these applications can do to disable unused access types. I provide a hands-on exercise in companion posts for seeing it for yourself and a lab setup for further experimentation.
Motivation
If you keep doors closed, it is better for your security. This is true for applications in SAP BTP, Cloud Foundry runtime. With microservices architecture there are lots of microservices deployed as applications and so there are several doors to close. Here I look at the access control of these doors.
Do you know what kinds of access controls are available for an application in SAP BTP, Cloud Foundry environment? There is only one (unless you take a DIY approach.) This is verification of the access token that is provided with the request. The verification can be done offline or online. SAP BTP provides libraries [ex. JavaScript, Java, Python, Go] and integration to popular Application frameworks (ex. Passport, Spring Boost) for making this easier. By using these libraries, by integrating these in the applications, developers ensure that they use the current best practices for verification of access tokens. The access tokens used in SAP BTP are based on industry standard JSON Web Tokens (JWT). So there are other libraries available when developers go beyond the frameworks supported by the libraries SAP BTP offers.
But that is not the end of it. How access tokens are issued becomes the next important step for access control. If tokens are issued freely, verification of these access tokens becomes a pointless routine. Applications in SAP BTP, Cloud Foundry environment delegate the responsibility of issuing tokens to SAP BTP and trust SAP BTP to only issue access tokens to authenticated users. I had looked at the credential-types
supported by SAP BTP in an article published earlier. Here I look at another aspect of this: grant-types
. Credential type determines how the client requesting token authenticates to gets access to the APIs. A token is almost always issued on behalf of a user. How the client requesting a token gets authorization from the user to request for the token is abstracted by grant types. What grant types are used/needed depends on the use case. Disabling grant types that are not needed is akin to keeping unused doors locked.
Context of SAP BTP
The security functionality of SAP BTP is based on oAuth 2.0 Authorization Framework. The framework defines how a user – the OAuth 2.0 Resource Owner – delegate authorizations it has to resources on a Resource Server to another application – the OAuth 2.0 Client. It does this without the application needing to know the credentials of the user. This is done with the help of a trusted Authorization server. In SAP BTP, Extended Services – User Account and Authentication (XSUAA) service acts as the OAuth 2.0 Authorization server. It also provides functionality for administrating and assigning authorizations for applications (Resource Server). It is a proprietary implementation offering same UAA API for Authorization, issuing Tokens and Introspecting tokens. In this article we are mostly looking at the functionality and API for requesting tokens.
As mentioned earlier applications in SAP BTP, Cloud Foundry environment protect themselves by validating tokens send along with the requests the process. In SAP BTP, these tokens are issued by XSUAA service. The APIs for requesting tokens from XSUAA service are based on UAA API. UAA adopts oAuth 2.0 Authorization Framework. Applications accessing the API for requesting tokens are oAuth clients. When requesting for tokens, oAuth clients need to specify the grant-type
and scopes
(default is all) in the request. The oAuth clients are given authorization for grant types and scopes they may be granted when they are registered with the Authorization server. Scopes represent the access to resources. These are declared by the Resource server. XSUAA service combines the configuration of the two oAuth entities: Client and Resource Server into one entity represented by the entity called application(xsapp). An application(xsapp) is registered by creating a new instance of XSUAA service. With this registration one client and all scopes of the resource server authorized for the client are registered together. In addition the configuration allows for declaring roles and role collections which are authorization entities for assigning scopes to users. The configuration of the service instance also determines the grant types that the oAuth client may request. This configuration parameter can also be updated later. The snippet below is the relevant portion of the configuration.
"oauth2-configuration": {
...
"oauth2-configuration": {
...
"grant-types": [
"authorization_code",
"refresh_token",
"user_token",
],
...
}
...
}
You will hardly find this parameter in configuration files which are normally named xs-security.json. If grant-types
are not configured, all supported grant types are allowed for the client. Not configuring this avoids the hassle of figuring out what is needed. So most of the clients are allowed grant types they do not need. Granting more than necessary grant types is not considered a high security risk. But these are definitely unnecessary doors left open.
Solution
The first step in keeping unnecessary doors closed is knowing where these doors are, knowing how to close them. Tokens can be requested with several different grant types. What are the different grant types available with XSUAA service?
You get an overview from the summary above. You can find more details for each of the grant types in Appendix.
In SAP BTP the recommended practice for deploying applications is by packaging them as multitarget application archives(mta). The restrictions of grant types could be incorporated into the definition of configuration while packaging. This packaging offers extension possibilities during deployment. So this extension capability can be made use of to restrict the grant-types allowed for the client during deployment as well.
---
_schema-version: '3.1'
ID: cf-application-ext
extends: cf-application
version: 1.0.0
resources:
- name: cf-approuter-uaa
parameters:
config:
oauth2-configuration:
grant-types:
- password
- authorization_code
- refresh_token
- user_token
An example of an extension descriptor used in the exercises is illustrated above. Exercises in the companion posts further demonstrates how this can be applied.
It is not a good idea to go about restricting grant-types of applications without knowing what grant-types are required for the use case. The summary of grant types presented earlier and the details provided in the Appendix should help in deciding what is necessary for each use case. The exercises in companion posts take a typical web application and analyze the components to give a better idea of what grant types a use case uses.
Companion posts
The following posts have lab exercises for examining the use and result of these grant types.
- Setup for Exercises
- Exercise 1 – grant types for user authorization
- Exercise 2 – grant types for basic user propagation
- Exercise 3 – grant types for external user propagation
Conclusion
There is no urgent reason to restrict grant-types of applications. But this is an option available for reducing the unused functionality deployed. Most use cases use limited set of grant types. Newer JWT bearer token grant type is better compared to User Token for many use cases. This grant type can also be used with tokens from SAP Cloud Identity Service with no additional trust setup. This has the additional advantage of not needing additional trust configuration or group mapping. The lab exercises in companion posts will give you a better appreciation of how grant types secure applications in SAP BTP, Cloud Foundry, environment. Please let me know in comments if you found the blog and the exercises useful.
Appendix: Token Grant Types
An application(xsapp) is registered by creating a new instance of XSUAA service. With this registration one client is registered together with scopes for the client. A key or binding for the instance of XSUAA service gives the following information for use by clients.
- url: url prefix for accessing APIs
- clientId: username of credentails fof accessing APIs
- clientSecret: password of credentails fof accessing APIs
This information is referred in samples for API requests below. The premise of the samples below is that there are 2 XSUAA service instances. These are prefixed with xsuaa_ or xsuaa2_ to differentiate between two. xsuaa_ is used by the Application Router for requesting user Authorization and xsuaa2_ is declared by the Business Logic Application for protecting the resources it offers. Application Router has access to the client credentials of the Business Logic Application from destination definition it has access to.
Additional information:
- redirect_uri – registered trusted application uri for redirect with authorization code
1. Authorization Code
As you can see in the summary, Authorization Code, which is the most visible in material on the subject, is only one among several grant types for tokens supported by XSUAA service. XSUAA service is based on UAA. The documentation of UAA Token API serves as good reference for using these grant types in the context of XSUAA service too. The picture below illustrates how the client acquires a token and then requests for a token.
(Source: github/SAP/cloud-security-xsuaa-integration)
Step 2 in the picture is when the client requests authorization code for requesting token on behalf of the user who is the resource owner. The client is given the code as a parameter in a redirect from browser after authenticating the user. Once the client has the code, step 3 is when the client acquires the token. Note that request for Authorization code does not require client secret, but it does require client id. The code issued is for one time use and is associated with the client_id and the redirect_uri. The client requires the client_secret in addition for acquiring token. This is illustrated in the code snippet for requesting token with authorization code below:
POST {{xsuaa_url}}/oauth/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{xsuaa_clientId}} {{xsuaa_clientSecret}}
grant_type=authorization_code
&redirect_uri={{encodeURiComponent(redirect_uri)}}
&code={{authorization_code}}
Above is syntax used in httpYac (also by Rest Client for Visual Studio and similar tools). This provides for brevity. I use this tool in exercises.
The above described flow is used by web applications (with a server component) and is implemented in Application Router for authenticating users and granting them access in a typical HTML5 user interface in SAP BTP, Cloud Foundry runtime. This is illustrated in the figure below for Business Application Pattern.
(Source: Business Application Pattern | SAP Help Portal)
Once Application Router acquires the access token it may access the Business Logic Applications on behalf of the user. How it does that depends on if the Business Logic Application shares the oAuth client with Application Router or not. In the case of a standalone Application Router, in typical setup the oAuth client is shared between the Application Router and the Business Logic Application as they bind to the same XSUUA Service Instance. So the Application Router can simply forward the token [“forwardAuthToken”: true] it acquired to the Business Logic Application. If the oauth client used by the Application Router is not shared by the Business Logic Application, which is the case for Managed Application Router, it has to acquire a new token with the oAuth client of the Business Logic Application. This is done by requesting a token using the oAuth client of the Business Logic Application. This has to be done without requesting for authorizations from the user. The grant types that allow this are discussed later. These are used with Managed Application Router.
Side Note:As noted earlier, with XSUAA service oAuth clients and Authorizations are declared together. A token for an oAuth client normally carry only authorizations declared in the application that registered it. But a token for an oAuth client can carry authorizations declared with another oAuth client. This is done with special declarations of such grants in the definition of the application(xsapp) which defines the other oAuth client. These configuration settings are: |
2. Password
Acquiring Authorization code requires user interaction, typically in a browser. This allows for user to share credentials only with the trusted SAP Cloud Identity Services or uses a corporate identity provider for a single sign-on experience. When the clients require access without interacting with a user but the application requires a user context for granting access Password grant may be used. This requires sharing the user credentials with the client.
POST {{xsuaa_url}}/oauth/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{xsuaa_clientId}} {{xsuaa_clientSecret}}
grant_type=password
&username={{username}}
&password={{password}}
&login_hint={"origin":"sap.custom"}
Note: sap.custom
is the identity provider key for the trusted SAP Cloud Identity Services tenant. This should be changed to sap.default with SAP ID service (the default IDP is to be used). Password grant is not supported for SAML based Identity providers.
Note that login_hint needs to be a URI component encoded JSON string. The description above is for brevity. It needs to be encoded for example like encodeURIComponent( JSON.stringify( {"origin":"sap.default"} ) )
.
3. Passcode
An alternate to authorization code for granting authorization to a client without sharing password is use of passcode. Passcode can be generated by logging on in browser are url {{xsuaa_url}}/passcode
. This is a temporary Authentication Code. It can be shared with the client for granting access. The code is for use only once. But the access can be extended using refresh tokens. Refresh tokens are discussed later. As you can see grant_type for this is again password.
POST {{xsuaa_url}}/oauth/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{xsuaa_clientId}} {{xsuaa_clientSecret}}
grant_type=password
&passcode={{passcode}}
4. Refresh Token
Validity of access tokens provided by XSUAA service is short. Even though this is configurable, it is recommended to keep the validity short to reduce the risk when the token is leaked. XSUAA service returns refresh tokens in addition to access tokens. This token can have longer validity and can be saved for use later.
POST {{xsuaa_url}}/oauth/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{xsuaa_clientId}} {{xsuaa_clientSecret}}
grant_type=refresh_token
&refresh_token={{token_response.refresh_token}}
5. User Token
When a client has acquired authorization for the user, and wants to access a Business Logic Application with this authorization, but accessing the Business Logic Application needs authorization for a different oAuth client, the token it has acquired can be used to get authorization for the other client. User Token is a grant type that allows this. But, this method has been superseded by more convenient JWT Bearer Token that was introduced in a later version.
POST {{xsuaa_url}}/oauth/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: bearer {{token_response_with_uaa_user_scope.access_token}}
client_id={{xsuaa2_clientId}}
&grant_type=user_token
Note that this returns only refresh token and a later call is required to acquire the access token. Further, it the access token provided as credentials should have scope uaa.user
. This requires that the client defines this scope in its definition. But it is not explicitly necessary to grant this scope to a user as all authenticated users get this scope. But, this scope has to be requested when acquiring the token. The client requesting the token, not the target client, should support this grant type.
6. JWT bearer Token
This is an improved method for acquiring tokens for other clients with already available access token for a different client. Further, only id token (or a token with openid scope) is required for this method. The receiving client is required to have the grant type supporting this method.
POST {{xsuaa2_url}}/oauth/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{xsuaa2_clientId}} {{xsuaa2_clientSecret}}
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion={{trusted_idp_response.id_token}}
Note: The id token used could be one issued by the trusted SAP Cloud Identity Services tenant of the subaccount. The setup required for this is described in this sample integrating SAP AppGyver with an application in SAP BTP, Cloud Foundry environment.
7. SAML2 bearer (Assertion)
External JWT bearer Token grant is only supported for id tokens from the trusted OpenID based Identity Provider – SAP Cloud Identity Services tenant. SAML based Identity Providers cannot provide id tokens. But, assertions from SAML based identity providers can also provide authorization to clients to acquire tokens. Since users and hence the authorization in SAP BTP are always in the context of the authenticating Identity Provider, all role assignments to users or groups have to be setup independently for each trusted SAML based identity provider, independently from those setup for trusted SAP Cloud Identity Service. Receiving application may rely on attributes of the user like email address for identifying the users. So from the application’s perspective, users authorized by different identity providers may be considered same.
SAML2 bearer grant type is used when calling applications are outside of SAP BTP or when they are applications from another Identity Zone to whose tokens are not trusted. Increasingly, such applications use the same SAP Cloud Identity Service tenant as their trusted identity provider and can then use the id tokens from it with JWT bearer token grant instead of using this method.
POST {{saml_tokenEndPoint}}
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{xsuaa2_clientId}} {{xsuaa2_clientSecret}}
grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer
&assertion={{saml2_assertion}}
This blog from Piotr Tesny describes how to create saml2 assertion. Signed SAML2 assertion which is an XML document has to be base64 encoded and then encoded for use as a URI component. The endpoint for requesting tokens using saml2 bearer assertions in mentioned in the SAML metadata of XSUAA service at {{xsuaa2_url}}/saml/metadata
8. Client Credentials
Client credentials grants tokens with no user authorization. So this is to be reserved for technical access. Administrator access is also preferred to be done in a user context to enable auditing of activities.
POST {{xsuaa_url}}/oauth/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic {{xsuaa_clientId}} {{xsuaa_clientSecret}}
grant_type=client_credentials