Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CAP Consuming Services - Reuse Service calling Destination with Client Credentials Flow fails #5205

Open
KarthikeyanLoganathan opened this issue Nov 25, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@KarthikeyanLoganathan
Copy link

Describe the bug
SAP internal CAP issue 17326

Scenario

  • Reuse service is B
    • Provides service reuse-service-b
    • xsappname: reuse-b!b400638
    • client-id: sb-reuse-b!b400638
  • Consumer is A
    • xsappnane: a!t400638
    • client-id: sb-a!t400638
    • Consumes service reuse-service-b
    • Consumer service instance name reuse-service-b-service-instance
      • uaa.xsappname of the clone of service-instance 2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638
      • uaa.client-id of the clone: sb-2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638

service instance reuse-service-b-service-instance service binding credentials

{
	"url": "https://reuse-service-b-srv.cert.cfapps.eu12.hana.ondemand.com/",
	"uaa": {
		"tenantmode": "shared",
		"sburl": "https://internal-xsuaa.authentication.eu12.hana.ondemand.com",
		"subaccountid": "SUB_ACCOUNT_ID",
		"credential-type": "binding-secret",
		"clientid": "sb-2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-service-b!b400638",
		"xsappname": "2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-service-b!b400638",
		"clientsecret": "67eafdfc-4563-4a52-ae85-b193c5133953$NPUmM9akxtuq5t8JO_Sw4A-QNOX_gCWpYQ3tkkif71A=",
		"serviceInstanceId": "2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8",
		"url": "https://reference-data-access-lfci5awt.authentication.eu12.hana.ondemand.com",
		"uaadomain": "authentication.eu12.hana.ondemand.com",
		"verificationkey": "-----BEGIN PUBLIC KEY-----\nSECRET\n-----END PUBLIC KEY-----",
		"apiurl": "https://api.authentication.eu12.hana.ondemand.com",
		"identityzone": "PROV_SUB_DOMAIN",
		"identityzoneid": "SUB_ACCOUNT_ID",
		"tenantid": "SUB_ACCOUNT_ID",
		"zoneid": "SUB_ACCOUNT_ID"
	}
}

How to Test Scenario:

  • get A client-credentials JWT token using
    • pick client-id, client-secret from xsuaa binding of A
    • you have token-A now
  • get Service B JWT Token using (Client-Credentials Token obtained for consumer-client-credentials-token)
    • use token-A
    • Pick client-id, client-secret ... from B service binding in Application A
    • Use token exchange flow from A to B
    • you have token-B
    • this is client credentials jwt token
  • Now, hit the application end point of reuse service
    • use token B - the client credentials token
    • the end-point is a CAP Odata consumer; internally calls remote OData service using destination using SAP Cloud SDK JS
    • Application fails as SAP Cloud SDK JS is not able to resolve destination

Callstack

getSubscriberToken (\home\vcap\app\node_modules\@sap-cloud-sdk\connectivity\dist\scp-cf\destination\get-subscriber-token.js:30)
DestinationFromServiceRetriever.getDestinationFromDestinationService (\home\vcap\app\node_modules\@sap-cloud-sdk\connectivity\dist\scp-cf\destination\destination-from-service.js:51)
getDestinationFromDestinationService (\home\vcap\app\node_modules\@sap-cloud-sdk\connectivity\dist\scp-cf\destination\destination-from-service.js:38)
getDestination (\home\vcap\app\node_modules\@sap-cloud-sdk\connectivity\dist\scp-cf\destination\destination-accessor.js:74)
process.processTicksAndRejections (<node_internals>/internal/process/task_queues:95)
await (Unknown Source:0)
processTicksAndRejections (<node_internals>/internal/process/task_queues:95)
await (Unknown Source:0)
useOrFetchDestination (\home\vcap\app\node_modules\@sap-cloud-sdk\connectivity\dist\scp-cf\destination\destination-accessor.js:38)
resolveDestination (\home\vcap\app\node_modules\@sap-cloud-sdk\connectivity\dist\scp-cf\destination\destination-accessor.js:51)
<anonymous> (\home\vcap\app\node_modules\@sap-cloud-sdk\http-client\dist\http-client.js:78)
executeHttpRequestWithOrigin (\home\vcap\app\node_modules\@sap-cloud-sdk\http-client\dist\http-client.js:278)
_executeHttpRequest (\home\vcap\app\node_modules\@sap\cds\libx\_runtime\remote\utils\client.js:64)
run (\home\vcap\app\node_modules\@sap\cds\libx\_runtime\remote\utils\client.js:227)
on_handler (\home\vcap\app\node_modules\@sap\cds\libx\_runtime\remote\Service.js:274)
next (\home\vcap\app\node_modules\@sap\cds\lib\srv\srv-dispatch.js:69)
handle (\home\vcap\app\node_modules\@sap\cds\lib\srv\srv-dispatch.js:73)
handle (\home\vcap\app\node_modules\@sap\cds\libx\_runtime\remote\Service.js:286)
dispatch (\home\vcap\app\node_modules\@sap\cds\lib\srv\srv-dispatch.js:35)
<anonymous> (\home\vcap\app\node_modules\@sap\cds\lib\srv\srv-dispatch.js:15)
run (\home\vcap\app\node_modules\@sap\cds\lib\srv\srv-api.js:72)
dispatch (\home\vcap\app\node_modules\@sap\cds\lib\srv\srv-dispatch.js:15)
run (\home\vcap\app\node_modules\@sap\cds\lib\srv\srv-api.js:76)
ODataClient.getTotalNumberOfRootRecords (\home\vcap\app\node_modules\@sap\my-common\util\ODataClient.js:392)
ODataClient.doSequentialInboundReplicationWithClientSidePagination (\home\vcap\app\node_modules\@sap\my-common\util\ODataClient.js:414)
processTicksAndRejections (<node_internals>/internal/process/task_queues:95)
await (Unknown Source:0)
ODataClient.doInboundReplication (\home\vcap\app\node_modules\@sap\my-common\util\ODataClient.js:678)
<anonymous> (\home\vcap\app\node_modules\@sap\my-common\srv\replicationRun\index.js:25)
next (\home\vcap\app\node_modules\@sap\cds\lib\srv\srv-dispatch.js:69)
handle (\home\vcap\app\node_modules\@sap\cds\lib\srv\srv-dispatch.js:73)
processTicksAndRejections (<node_internals>/internal/process/task_queues:95)
await (Unknown Source:0)
processTicksAndRejections (<node_internals>/internal/process/task_queues:95)
await (Unknown Source:0)
processTicksAndRejections (<node_internals>/internal/process/task_queues:95)
await (Unknown Source:0)
processTicksAndRejections (<node_internals>/internal/process/task_queues:95)
await (Unknown Source:0)

The runtime still tries to use user-jwt token and terminates;

The consumer call corresponds to consumer-A-clone-of-reuse-service-b-xsappname

In the runtime of service VCAP has xsappname of reuse-b
The cloud SDK is matching clone-xsappname of the clone against the environment variable xsappname
No match and call fails at retrieveUserTOken() below

/**
 * @internal
 */
async function getSubscriberToken(options) {
    const isXsuaaJwt = !!options.jwt && (0, jwt_1.isXsuaaToken)((0, jwt_1.decodeJwt)(options.jwt));
    const userJwt = await retrieveUserToken(options, isXsuaaJwt);
    const serviceJwt = await retrieveServiceToken(options, userJwt?.decoded);
    return { userJwt, serviceJwt };
}

reuse service B xsuaa credentails in memory

xsuaa credentials from environment

[
  {
    "tenantmode": "shared",
    "sburl": "https://internal-xsuaa.authentication.eu12.hana.ondemand.com",
    "subaccountid": "SUB_ACCOUNT_ID",
    "credential-type": "binding-secret",
    "clientid": "sb-reuse-b!b400638",
    "xsappname": "reuse-b!b400638",
    "clientsecret": "SECRET",
    "serviceInstanceId": "8efa7eca-938e-49f8-975e-458459376f18",
    "url": "https://PROV_SUB_DOMAIN.authentication.eu12.hana.ondemand.com",
    "uaadomain": "authentication.eu12.hana.ondemand.com",
    "trustedclientidsuffix": "|reuse-b!b400638",
    "verificationkey": "-----BEGIN PUBLIC KEY-----\\nSECRET\\nRQIDAQAB\\n-----END PUBLIC KEY-----",
    "apiurl": "https://api.authentication.eu12.hana.ondemand.com",
    "identityzone": "PROV_SUB_DOMAIN",
    "identityzoneid": "SUB_ACCOUNT_ID",
    "tenantid": "SUB_ACCOUNT_ID",
    "zoneid": "SUB_ACCOUNT_ID"
  }
]

incoming client-credentials token of the reuse service contains JWT clone of the service-instance of the reuse-service xsuaa client id

{
  "jti": "b83ebb17d12c455598c9263927089b78",
  "ext_attr": {
    "enhancer": "XSUAA",
    "subaccountid": "CONSUMER_SUB_ACCOUNT",
    "zdn": "CONSUMER_SUB_DOMAIN",
    "serviceinstanceid": "2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8"
  },
  "sub": "sb-2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638",
  "authorities": [
    "uaa.resource"
  ],
  "scope": [
    "uaa.resource"
  ],
  "client_id": "sb-2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638",
  "cid": "sb-2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638",
  "azp": "sb-2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638",
  "grant_type": "client_credentials",
  "rev_sig": "3270fa3b",
  "iat": 1732515725,
  "exp": 1732558925,
  "iss": "https://PROV_SUB_DOMAIN.authentication.eu12.hana.ondemand.com/oauth/token",
  "zid": "CONSUMER_TENANT_ID",
  "aud": [
    "uaa",
    "sb-2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638"
  ]
}

obviously there is no match of client-id of the jwt to the rda-service-srv bound xsuaa service instance's client-id
getCredentialsWithJwt returns undefined

getServiceCredentials returns undefined

getXsuaaServiceCredentials throws error 'Could not find XSUAA service binding matching the token.'

@KarthikeyanLoganathan KarthikeyanLoganathan added the bug Something isn't working label Nov 25, 2024
@KarthikeyanLoganathan
Copy link
Author

A Reuse Service is called with the context of the Consumer Application (Clone of xsuaa-instance)

In this context, subscriber tenant level destination lookup within reuse service runtime always fails

@ZhongpinWang
Copy link
Contributor

Hi @KarthikeyanLoganathan ,

We still don't fully understand your issue here. Our guess would be that you are trying to get a destination registered in a provider subaccount from a subscriber context right? It feels like you are trying to manually fetch provider client credential and use that to get a provider destination from subscriber. In this case, we would recommend not doing so because subscriber should never have access to the provider destinations.

Instead, subscriber should delegate the call to provider and let provider call the destination or remote service. In subscriber context, subscriber can only get destinations from subscriber subaccount. If our understanding is correct, then please review your architecture for multi-tenancy.

@KarthikeyanLoganathan
Copy link
Author

REUSE SERVICE USE CASE IS FAILING IN CLOUD SDK JS

In reuse service scenario, we use service broker @sap/sbf, In my case I use xsuaa as credentials provider.

for my multi-tenant reuse Service B deployment, xsuaa credentilas are

  • xsappname: reuse-b!b400638
  • client-id: sb-reuse-b!b400638
  • Uses service broker to expose the service
    • A service instance gets clone of xsappname above like 2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638

My multi-tenant SaaS app A calls reuse service B

For my Multi-tenant SaaS App A deployment,

  • xsappnane: a!t400638
  • client-id: sb-a!t400638
  • Has Service Instance of reuse Service B
    • service binding as uaa section { } with credentilas
    • xsappname: 2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638
    • client-id: sb-2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638
    • When A calls --> B, JWT token is for the
      • client id sb-2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638,
      • xsappname: 2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638
      • B runtime does not get the JWT token for
        • xsappname reuse-b!b400638
        • client id sb-reuse-b!b400638
      • B only has xsuaa service binding for xsappname reuse-b!b400638
      • Cloud SDK has JWT token for 2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638
      • Cloud SDK expects to lookup for 2cffb32b-3ebf-44b1-ad60-88af2d3ff2a8!b400638|reuse-b!b400638 in VCAP_SERVICES whereas it only has xsappname reuse-b!b400638 in VCAP_SERVICES
      • HERE CLOUD SDK FAILS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants