SAP / cloud-sdk-js

Use the SAP Cloud SDK for JavaScript / TypeScript to reduce development effort when building applications on SAP Business Technology Platform that communicate with SAP solutions and services such as SAP S/4HANA Cloud, SAP SuccessFactors, and many others.
Apache License 2.0
165 stars 56 forks source link

Compatibility with SAP's SuccessFactors Learning OData API atypical OAuth flow #1592

Closed piejanssens closed 1 year ago

piejanssens commented 3 years ago

Is your feature request related to a problem? Please describe. https://answers.sap.com/questions/13475739/how-can-i-use-sap-cloud-sdkcore-to-make-requests-t.html

Describe the solution you'd like I want to be able to use SAP Cloud SDK with a destination that points to SuccessFactors Learning OData API, without having to take care of the authentication flow or the token cache myself.

Describe alternatives you've considered https://answers.sap.com/comments/13480557/view.html

FrankEssenberger commented 3 years ago

Hello @piejanssens,

welcome to our repo. Regarding your questions I did the following:

  1. Reached out to the SFSF colleagues because I think the best way would be a proper user containing standard OAuth flow is supported so that the destination service can fetch the token for you.
  2. In the meantime it would be good to have a workaround for customers. Here I think it would be easiest if the SDK provides some getSFLearningDestination() helper method or via a destination property you can switch on some custom parsing.

I have to discuss with my colleagues what they think about such a helper method somewhere. I will come back after the discussion.

Best Frank

FrankEssenberger commented 3 years ago

So we went in the discussion and our first priority is to get the service owner(s) to get some solution. We reached out to both possible solutions: Destination Service and SFSF. I hope we receive some response soon. I hope they agree do provide some acceptable solution for the customer.

I have created a BLI that this issue is not forgotten.

FrankEssenberger commented 3 years ago

Hello, I have not got any feedback on my issues. So I try to find a direct contact to get some statements if the colleagues plan on improving the situation.

FrankEssenberger commented 3 years ago

Hello everybody,

it took us a while until we found the right contact in SFSF. We were informed that all services also the Learning API supports "OAuth SAML Bearer Assertion Authentication". This flow is also supported by the destination service so it should work. The documentation is misleading.

In case it does not work, please come back to us than we can make contact to the colleagues and investigate the issue.

Have a good weekend. Frank

gregorwolf commented 3 years ago

Dear Frank,

will the SFSF colleagues correct the misleading documentation?

Best Regards Gregor

piejanssens commented 3 years ago

Hi Frank,

I would also like to see the updated documentation.

It sounds promising, but I don't want to celebrate too early. Can we please keep this open until we acknowledge that this is supported?

At this time, I have no clue how to setup "OAuth SAML Bearer Assertion Authentication" with SuccessFactors Learning. There are no options available in SuccessFactors Learning to generate/register the required key pair which would be used by CF destinations to generate the assertion.

Please find the current documentation on how SuccessFactors Learning API tokens can be obtained.

I'm really curious how this would work with SAML Bearer Assertion flow. For example, the 'userType' property which is required to get either a 'user' or 'admin' token. The API endpoints have different implementations for user and admin or as in most cases the API endpoint itself can only be called with either a user type token or an admin type token, not both.

{
   "grant_type":"client_credentials",
   "scope":{
      "userId":"Usr1",
      "companyId":"t1",
      "userType":"admin",
      "resourceType":"learning_public_api"
   }
}

This is the example from the documentation on the required "Required OAuth Token Parameters". I'm not sure what to expect from the scope; if the scope would also need to be passed as an JSON object I wonder if that is even supported by CF Connectivity. In all examples of 'SAML Bearer Assertion" I have seen so far, scope was just a string.

piejanssens commented 2 years ago

@FrankEssenberger Can you please reopen (see previous comments)?

FrankEssenberger commented 2 years ago

I reopened the issue until the colleagues gave some concrete description how to pass the information current as payload in the clientCrendentials flow via the SAML assertion. As @piejanssens pointed out this is not obvious and should be documented.

piejanssens commented 2 years ago

Hi @FrankEssenberger, did you already hear back from the SFSF colleagues on this?

FrankEssenberger commented 2 years ago

Oh, sorry I missed your question. Yes I got finally someone to talk to and we have a meeting scheduled after the holiday season in the beginning of january.

piejanssens commented 2 years ago

Could you please also raise the question why there is no destination provided to the SF Learning OData API when creating a SuccessFactors Extensibility service instance? (possibly related to the atypical OAuth authentication scheme) https://help.sap.com/products/BTP/65de2977205c403bbc107264b8eccf4b/46c5ea17eff94bc6949857e588797273.html?locale=en-US

FrankEssenberger commented 2 years ago

So I finally had the call with the colleague from SFSF. He explained the situation to me in the following way. There are two token servers:

In practice token issued from the BizX server are accepted from the learning API as well and the additional properties like resourceType or userType are not needed in this case and are obtained by the user context. I can not try this E2E since I have no test setup, but I assume you have a SFSF system at hand with the saml token server configure so you can just try out if the situation works as expected i.e. that you can call the API with the SAML token.

I really hopes this works.

Best Frank

P.S.: I also raised the question why no destination is created when you create a SuccessFactors Extensibility service instance. The colleague was not an expert on the BTP so he could not comment on this. I think this is a meaningful requirement making extensions IMO it should not only create the destination but also do this steps in the SFSF system for you so that you are directly good to go. I will try to find someone from the BTP who could comment on this.

piejanssens commented 2 years ago

Hi @FrankEssenberger,

First of all, thank you for taking this serious and following up on this! At first glance, this is great news! I did a quick test (simple GET API) and indeed, the BizX OAuth SAML Bearer token is accepted by the SF LMS API...

I will take some time to test various SF LMS API's and test both 'userType' contexts of 'admin' / 'user' (I hope not to find any issues).

Regarding the SuccessFactors Extensibility service, creating an instance does take care of automatically registering OAuth client application and setting up the destination with the keys of that registered OAuth client. Since both destinations (SF BizX and SF LMS) accept the same OAuth SAML Bearer tokens, I should be able to just export and import the same BizX destination (that was created by the SuccessFactors Extensibility service instance) and change the base URL to the API base URL to the one used by SF LMS. I will test that.

Meanwhile, could you please ask if they can make this - support of BizX bearer token in SF LMS and depreciation of LMS's token service - official by publishing this in SAP Help and/or KBA to document this?

Best regards,

Pieter

Update: API calls that usually require userType 'admin' or 'user' are working fine with the BizX OAuth SAML Bearer token. FYI - this is the current documentation on obtaining an access token for the LMS API: https://help.sap.com/viewer/5aab9bef78fc4c4fa199c1f7aa142720/2111/en-US/b4eb3f2e4bdb4e8091db2c7ace28b88b.html

FrankEssenberger commented 2 years ago

Hello @piejanssens,

I asked the colleagues to update the documentation but I do not know how quickly this will happen. Let's hope that google also finds this issue if people face the same issue.

Could we close this issue?

Best Frank

piejanssens commented 2 years ago

Hi @FrankEssenberger,

I would like to see this set in stone (documented), before closing this issue.

Regarding the SuccessFactors Extensibility service, creating an instance does take care of automatically registering OAuth client application and setting up the destination with the keys of that registered OAuth client. Since both destinations (SF BizX and SF LMS) accept the same OAuth SAML Bearer tokens, I should be able to just export and import the same BizX destination (that was created by the SuccessFactors Extensibility service instance) and change the base URL to the API base URL to the one used by SF LMS. I will test that.

I have tested this and can confirm that it works. If I want to switch all logic in my implementation to use the BizX token server, then I need to find a practical solution to generate a JWT for a given userId: many SF Learning API's are to be executed with a token of the user you are querying (read you can get the info yourself, but not as an admin even if you are entitled to do so).

Is there an API of the Cloud SDK that can help generate JWT's?

piejanssens commented 2 years ago

See https://github.com/SAP/cloud-sdk-js/issues/2016

FrankEssenberger commented 2 years ago

Is there an API of the Cloud SDK that can help generate JWT's?

We have a convience layer to retrieve client credential grant or user token in the token-accessor. However, these methods are strongly coupled to the BTP cloud foundry enviorment i.e. they ask the XSUAA to get tokens. So I guess this is not what you had in mind - you were more interested in non XSUAA service token?

HRMNYWaage commented 1 year ago

Hallo, is the Bizx token server already documented in the official LMS documentation? For my point of view there is still the old LMS token server: https://help.sap.com/docs/SAP_SUCCESSFACTORS_LEARNING/9d4c9e0d04304afdbe8f1b4480d71403/b4eb3f2e4bdb4e8091db2c7ace28b88b.html?locale=en-US

sverhaegen commented 1 year ago

Hi @FrankEssenberger, I encounter the same issue that the sap cloud sdk doesn't support SuccessFactors Learning OData api destinations. I tried the solution described by @piejanssens (creating a SuccessFactors Extensibility instance and replacing the url with the one of LMS), but I can only access data of the user from the jwt token and can't do anything admin related.

Is it possible to implement out of the box usage of a LMS destination with the cloud sdk?

FrankEssenberger commented 1 year ago

Good morning, I am currently doing a fellowship in a different team, but I would like to give my point of view. We had already a few similar issue in the past and I do not see a nice quick solution. In principle the destination service takes care of the token retrieval and the SDK just delegates to this service. This makes sense since all secret information can be stored via the service. And the ideal situation would be that SuccessFactors supports one of the existing flows.

As I understood you need a token issued from this Bizx server and you want to set certain properties for this issued token like userId and admin so that you can not only read but also change data for that user. Potentially this should even be possible if you are not in this user context e.g. a HR person wants to do something on behalf of an employee. The problem is that the destination service does not support such use cases to my knowledge.

I am a bit hesitant to add a layer within the normal destination flow like: If it is a SFSF token fetch the BizX token and pass it down the client flow as a custom JWT, because this feels like a very narrow usecase and our token fetching logic is already complicated enough but @marikaner and @jjtang1985 must decide.

Personally I would prefer to provide a helper method which fetches you the token from the BizX server - having a typed interface but also with a generic key/value object for passing properties to the call. This you would need to do before manually and then pass this JWT down the client of the SDK.

Perhaps you have already a code snippet for getting this token?

Best Frank

mr-flannery commented 1 year ago

We've decided to close this issue.

Regarding Successfactor's documentation, we understand and share your frustration, but our issue tracker is not the place to address this issue.

Regarding the feature request itself, we have decided that we will not implement it.

Best regards, Dennis