9

Destinations routing easy with SAP Build Work Zone, standard edition

 1 year ago
source link: https://blogs.sap.com/2023/03/20/destinations-routing-easy-with-sap-build-work-zone-standard-edition/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
March 20, 2023 9 minute read

Destinations routing easy with SAP Build Work Zone, standard edition

0 8 374

This brief is to showcase how to use dynamic_dest routes with SAP Build Work Zone, standard edition service (a managed approuter) to run SAP BTP destinations defined on a BTP sub-account level.

Long story short. A community fellow Donny Xu had asked me the following  question.

Beyond the technical aspects involved, dynamic_dest routes offer a simple solution to the very conundrum of how to test [complex] destinations [w/o the principal user propagation] without writing a single line of code…

I shall discuss:

Putting it all together

SAP Build Work Zone, standard edition service (previously known as SAP Launchpad service) is the entry product to the SAP Build Work Zone product family. (It is also available as a free subscription service with SAP BTP Free Tier accounts.)

The dynamic_dest construct allows to call any destination defined on a sub-account level using the managed approuter, for instance:

https://<tenant>.launchpad.cfapps.<region>.hana.ondemand.com/dynamic_dest/<dest_name>/<api_endpoint>

Good to know:

  • All types of destinations are supported.
  • Please make sure all your dynamic_dest destinations have the HTML5.DynamicDestination magic property set to true.

You may refer to Configure Destinations guidelines from the official SAP documentation for further details.

Easy routing with OAuth2SAMLBearerAssertion destinations

I had a chance to test it using a number of OAuth2SAMLBearerAssertion sub-account level destinations.

You can call an OAuth2-protected remote system/API and propagate a user ID to the remote system by using the OAuth2SAMLBearerAssertion authentication type. The Destination service provides functionality for automatic token retrieval and caching, by automating the construction and sending of the SAML assertion. This simplifies application development, leaving you with only constructing the request to the remote system by providing the token, which is fetched for you by the Destination service. For more information, see User Propagation via SAML 2.0 Bearer Assertion Flow.

From the moment the target systems (SAP Analytics Cloud, SAP S/4HANA Cloud, SAP SuccessFactors etc) are correctly configured for the principal user propagation, the dynamic_dest should work out of the box…for instance:

SAP S/4HANA Cloud

https://<tenant>.launchpad.cfapps.<region>.hana.ondemand.com/dynamic_dest/S4HC-Product/$metadata

https://<tenant>.launchpad.cfapps.<region>.hana.ondemand.com/dynamic_dest/QUOVADIS-ISVENG-JWT/A_SalesOrder?$top=5

dynamic_dest-s4hc.png

SAP SuccessFactors

https://ateam.launchpad.cfapps.sap.hana.ondemand.com/dynamic_dest/Quovadis-SAP-JWT/User?$top=1&$format=json

dynamic_dest-sfsf.png

SAP Analytics Cloud

https://<tenant>.launchpad.cfapps.<region>.hana.ondemand.com/dynamic_dest/ateam-partnereng/stories

dynamic_dest%20with%20SAP%20Build%20Work%20Zone%2C%20standard%20edition

dynamic_dest with SAP Build Work Zone, standard edition

In all the above cases, the identity of an SAP BTP subaccount user that logs into the SAP Build Work Zone, standard edition (aka Launchpad service) is passed through to a dynamic destination. The destination service generates a SAML Assertion which is passed to the resource provider. In case a remote user login (with an IDP-delegated flow) is successful, a bearer access token is retrieved, and then passed to the business function call.

Thus the user’s identity must be known by a target system.

Easy routing with SAP BTP, Kyma runtime API rules

Nowadays, the kubernetes-managed, containerised workloads are becoming increasingly popular, almost ubiquitous.

With SAP BTP, Kyma runtime’s API rule CRD it is fairly easy to securely expose micro-services and their endpoints to the external world.

As security is paramount, an API rule CRD can offer a number of access strategies to help restrict access to exposed endpoints.

For the sake of this brief l opted to using the JWT access strategy as a way to protect an API rule endpoint(s) from unsolicited access.

Good to know:

  • CRD stands for custom resource definition

The most important part of the below API rule definition is the accessStrategies config as follows:

apiVersion: gateway.kyma-project.io/v1beta1
kind: APIRule
metadata:
  name: "{{ .Values.services.srv.name }}-{{ .Release.Namespace }}"
spec:
  gateway: {{ .Values.gateway }}
  host: "{{ .Values.services.srv.name }}-{{ .Release.Namespace }}.{{ .Values.clusterDomain }}"
  rules:
    - accessStrategies:
        - config:
            jwks_urls:
              - https://<tenant>.authentication.<region>.hana.ondemand.com/token_keys
            trusted_issuers:
              - https://<tenant>.authentication.<region>.hana.ondemand.com/oauth/token
            required_scope:
              - openid        
          handler: jwt
      methods:
        - GET
        - PUT
        - DELETE
        - POST
        - PATCH
        - HEAD
      path: /.*
  service:
    name: {{ .Values.services.srv.name }}
    port: {{ .Values.services.srv.port }}

The tenant and the region values are those of the managed approuter’s subaccount.

Likewise, in order to further restrict access to the API rule to specific user categories only, it is possible to include additional user authorisations (scopes) that are assigned to a user JWT token via Roles and Roles Collections assigned to business users at a BTP sub-account level.

Kyma API rule as a business URL in a destination definition

Let’s assume the following dynamic destination definition:

a%20destination%20pointing%20to%20a%20kyma%20API%20rule

a destination definition towards to a kyma API rule

It features two additional properties:

  • HTML5.DynamicDestination: true — that makes it a dynamic destination
  • HTML5.ForwardAuthToken: true — that tells the managed approuter to forward the business user JWT token to the API rule in the Authorization header as a bearer access token

Eventually, the above destination can be consumed as a dynamic destination as follows:

https://<tenant>.launchpad.cfapps.<region>.hana.ondemand.com/dynamic_dest/poster_dest/

This will result in calling of a Kyma API rule with the BTP user’s JWT passed in the Authorization header. Subsequently, the API rule will attempt to validate the endpoint access following the defined access strategies. After successful validation the access will be granted, otherwise a 401 error will be thrown.

Q. What if I wanted to use my own OIDC provider in this worklow, instead of relying on a forwarded user token?

A. That’s a very fair question. This is where OAuth2JWTBearer destination type can help exchange the user JWT token into an OAuth2 bearer access token with the required scopes…

To allow an application to call another application, passing the user context, and fetch resources, the caller application must pass an access token. In this authorization flow, the initial user token is passed to the OAuth server as input data. This process is performed automatically by the Destination service, which helps simplifying the application development: You only have to construct the right request to the target URL, by using the outcome (another access token) of the service-side automation.

Let’s take the above words for granted and build such a destination definition. We shall use an instance of XSUAA service acting as an OIDC provider…
OAuth%20JWT%20Bearer%20Authentication

OAuth JWT Bearer Authentication


And bingo! This works as advertised! (more details in the appendix section below….)

https://<tenant>.launchpad.cfapps.<region>.hana.ondemand.com/dynamic_dest/quovadis-anywhere/?host=toto.com

Picture2-26.png

Conclusion

Calling a kyma-hosted micro-service from the comfort of a managed launchpad service with the integrated SAP BTP security has never been easier;

Calling into SAP LOB applications APIs has become a “piece of cake”….

All that with little to no code.

Last but not least, I hope you have enjoyed reading this blog post. Feel free to provide feedback in the comments section below.


Appendix

Making of OAuth2JWTBearer destination type

1a. the initial JWT user token…

{
  "alg": "RS256",
  "jku": "https://<tenant>.authentication.<region>.hana.ondemand.com/token_keys",
  "kid": "<kid>",
  "typ": "JWT",
  "jid": "<jid>"
}.{
  "jti": "<jti>",
  "ext_attr": {
    "enhancer": "XSUAA",
    "subaccountid": "<subaccountid>",
    "zdn": "<zdn>"
  },
  "xs.system.attributes": {
    "xs.rolecollections": [
      "Subaccount Service Administrator",
      "SAP HANA Cloud Administrator",
      "Subscription Management Dashboard Administrator",
      "Subaccount Administrator",
      "Launchpad_Admin",
      "faas-faas_hc-faas"
    ]
  },
  "given_name": "Foo",
  "xs.user.attributes": {},
  "family_name": "Bar",
  "sub": "<sub>",
  "scope": [
    "openid",
    "faas-faas!t6455.Admin",
    "faas-faas!t6455.User",
    "uaa.user"
  ],
  "client_id": "sb-faas-faas!t6455",
  "cid": "sb-faas-faas!t6455",
  "azp": "sb-faas-faas!t6455",
  "grant_type": "authorization_code",
  "user_id": "<user_id>",
  "origin": "ldap",
  "user_name": "[email protected]",
  "email": "[email protected]",
  "auth_time": <auth_time>,
  "rev_sig": "<rev_sig>",
  "iat": <iat>,
  "exp": <exp>,
  "iss": "https://<tenant>.authentication.<region>.hana.ondemand.com/oauth/token",
  "zid": "<zid>",
  "aud": [
    "uaa",
    "openid",
    "faas-faas!t6455",
    "sb-faas-faas!t6455"
  ]
}.[Signature]

1b … gets exchanged into a bearer access token. The bearer access token issuance endpoint is that of your custom OIDC provider (that can be an XSUAA service instance, SAP IAS OIDC application or any other third-party OIDC provider).

For the sake of simplicity the below destination definition snippet uses an instance of XSUAA service [on the same BTP sub-account as the managed approuter].

{
  "owner": {
    "SubaccountId": "<SubaccountId>",
    "InstanceId": null
  },
  "destinationConfiguration": {
    "Name": "quovadis-anywhere",
    "Type": "HTTP",
    "URL": "https://poster.<business_domain>.com/",
    "Authentication": "OAuth2JWTBearer",
    "ProxyType": "Internet",
    "tokenServiceURLType": "Dedicated",
    "HTML5.DynamicDestination": "true",
    "clientId": "<clientId>",
    "Description": "poster",
    "scope": "openid",
    "HTML5.Timeout": "60000",
    "clientSecret": "<clientSecret>",
    "tokenServiceURL": "https://<tenant>.authentication.<region>.hana.ondemand.com/oauth/token"
  },
  "authTokens": [
    {
      "type": "bearer",
      "value": "eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vYXRlYW0uYXV0aGVudGljYXRpb24uc2FwLmhhbmEub25kZW1hbmQuY29tJN5W0TMNG32nVayH5yMwKHClhH3OW5Asx61KSE1hTu4HpwgDp4a-P-HG3Fw0XQmQIUe_m8YuQ0s6WFQHsbPlLLaINxfPL-Q",
      "http_header": {
        "key": "Authorization",
        "value": "Bearer eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vYXRlYW0uYXV0aGVudGljYXRpb24uc2FwLmhhbmEub25kZW1hbmQuY29tLJN5W0TMNG32nVayH5yMwKHClhH3OW5Asx61KSE1hTu4HpwgDp4a-P-HG3Fw0XQmQIUe_m8YuQ0s6WFQHsbPlLLaINxfPL-Q"
      },
      "expires_in": "42389",
      "scope": "openid"
    }
  ]
}

2. Here goes the retrieved and decoded bearer access token:

{
  "alg": "RS256",
  "jku": "https://<tenant>.authentication.<region>.hana.ondemand.com/token_keys",
  "kid": "<kid>",
  "typ": "JWT",
  "jid": "<jid>"
}.{
  "jti": "<jti>",
  "ext_attr": {
    "enhancer": "XSUAA",
    "subaccountid": "<subaccountid>",
    "zdn": "<zdn>"
  },
  "xs.system.attributes": {
    "xs.rolecollections": [
      "Subaccount Service Administrator",
      "SAP HANA Cloud Administrator",
      "Subscription Management Dashboard Administrator",
      "Subaccount Administrator",
      "Launchpad_Admin",
      "faas-faas_hc-faas"
    ]
  },
  "given_name": "Foo",
  "xs.user.attributes": {},
  "family_name": "Bar",
  "sub": "<sub>",
  "scope": [
    "openid"
  ],
  "client_id": "<client_id>",
  "cid": "<cid>",
  "azp": "<azp>",
  "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
  "user_id": "<user_id>",
  "origin": "ldap",
  "user_name": "[email protected]",
  "email": "[email protected]",
  "rev_sig": "<rev_sig>",
  "iat": <iat>,
  "exp": <exp>,
  "iss": "https://<tenant>.authentication.<region>.hana.ondemand.com/oauth/token",
  "zid": "<zid>",
  "aud": [
    "openid",
    "<client_id>"
  ]
}.[Signature]

that the managed approuter with the dynamic_dest route will use to call the business URL.

Troubleshooting tips

Sometimes it makes sense to smoke-test OAuth2SAMLBearerAssertion destinations with a valid user JWT token to be passed in the x-user-token header of the find destination REST API call.

This can be done using this handy jsp page on the subaccount level:

https://<tenant>.authentication.<region>.hana.ondemand.com/support.jsp

Then goto XS_APPLICATIONUSER page so you can fetch a short-lived JWT token of the currently logged BTP user, as follows:

https://<tenant>.authentication.<region>.hana.ondemand.com/config?action=xs_appuser

XS_APPLICATIONUSER: 
Type: JWT 
Metadata: https://<tenant>.authentication.<region>.hana.ondemand.com/sap/trust/jwt 
Test SQL: 

-- start sql 
SET 'XS_APPLICATIONUSER' = 'eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vYXRlYW0uYXV0aGVudGljYXRpb24uc2FwLmhhbmEub25kZW1hbmQuY29tFk5w-ug'; 
SELECT key,value from M_SESSION_CONTEXT WHERE KEY LIKE 'XS_%' AND CONNECTION_ID = CURRENT_CONNECTION;
-- end sql 

Token Validity: 5 minutes
Details
SAP note: 2470084

Good to know:

  • the BTP region for SAP BTP canary subaccounts is sap.

SAP Community: https://community.sap.com/

SAP Community Topic Page link: https://community.sap.com/topics/kyma

SAP Community Q&A Tags:
Kyma Open Source: https://answers.sap.com/tags/2936b97d-6a90-4cd8-b635-0e51441611eb
SAP BTP, Kyma runtime: https://answers.sap.com/tags/73554900100800003012

Follow me in SAP Community: Piotr Tesny

bestrun-5.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK