adobe / acc-js-sdk

A JavaScript SDK for Adobe Campaign Classic
Apache License 2.0
21 stars 22 forks source link

Failing to call anonymous methods #96

Closed aimanicose4 closed 1 year ago

aimanicose4 commented 1 year ago

Hi Team,
I'm facing an issue calling anonymous methods. Normal behavior through SOAP call would allow for an anonymous method to be called without any authentification. Through the SDK though, this behavior is not possible through anonymous logon. An "Access Forbidden" error is sent when making the call since the method "xtk:persist#GetEntityIfMoreRecent" is being called before every request which requires authentication.

Is it possible to fix this issue if it is within the intended purposes of the anonymous logon, otherwise is there a turnaround ?

Thank you.

mkiki commented 1 year ago

Hi @aimanicose4, I'd like to understand the issue better.

I'm not aware of any anonymous SOAP methods in Campaign, but maybe I'm wrong. Do you have a more specific example? Is there a particular SOAP method you'd like to call anonymously? Is it a custom SOAP method? Could you share some sample code which illustrate the issue?

My guess is that indeed, in order to call any SOAP API, the SDK needs to lookup the corresponding schema, from which it will get the SOAP method definition. This is done via the GetEntityIfMoreRecent call, which indeed, requires authentication.

If you can provide a simple example, I can look for a solution.

aimanicose4 commented 1 year ago

Hello @mkiki , Thank you for you response.

The particular SOAP method i'd like to call anonymously is indeed a custom one I created in ACC. I basically want to create a method to bypass the standard adobe campaign logon method and have a sort of sigle sign on system for our front end application that is accessible through our company's authentication protocol. The application communicates with ACC through a nodeJS server and the point is to avoid having a double sign on scenario.

The method declaration looks like this :

image

With an implementation like this :

image

That way, I can authenticate a user to ACC without him having to type his credentials anywhere. The accounts used for this application would be unusable in the ACC client but that won't be an issue since it's the wanted behavior anyway.

After creating the method, I managed to call it successfully through SOAP API using Postman without any authentication method. But couldn't reproduce the same behavior through SDK.

I actually managed to "make it work" yesterday by tinkering a little bit in the SDK code (Logon() method of client.js file) and changing the behavior of AnonymousUser authentication like this :

image

And calling my customized anonymous method directly using ofAnonymousUser connection. But as you can see this is a very use case specific change and is not sustainable to change the code after each update to the sdk.

I would love to have a standard way for calling my anonymous methods anonymously granted, I am 100% sure the method exists so calling GetEntityIfMoreRecent is rendered unnecessary.

mkiki commented 1 year ago

Hi @aimanicose4, I understand better now. Implementing custom auth mechansim is tricky. I'm not sure it can actually be done in a secure way.

In recent versions of Campaign, we have improved our support for IMS authentication, and maybe it's possible to use IMS federated id to achieve secure SSO. Unfortunately, I'm not familiar with all the details, but the basic id is that Adobe IMS Federated id service can securely delegate authentication to your identity provider, and will provide you IMS bearer tokens that are compatible with ACC. But you'll probably need a fairly recent version of ACC for this (8.5 or above). Give me a couple of days to find out more, but I think it's probably the best long term sustainable and secure way to achieve what you want.

Now, in the short term, I can think of 2 approaches and 2 use cases: 1/ ability to call anonymous SOAP methods (independently of the login policy) 2/ provide a supported way in the SDK for custom login schemes. I'm a bit reluctant to this, because I do not believe it's feasible to guarantee security with custom login schemes.

I'll have to do some research and run some tests to implement 1/ I thinks this should solve your use case.

aimanicose4 commented 1 year ago

Hi @mkiki , Thank you so much for your help.

I sadly don't think IMS authentication would solve my issue even if I were on >=8.5 since my front end application is bound to my company's own authentication protocol so I'm kinda forced to work around it.

I also believe 1/ would help solve the issue for now.

Thanks once again.

mkiki commented 1 year ago

Ok, I had a quick look. It seems this would be quite simple to implement.

What about the following. It's basically a 2 step process

If this looks good to you, I can make a new SDK version on monday. Would you agree to review and comment the PR?

// First create an anonymous client which will server to call the anonymous SOAP call
// No need to call "logon" for this client since it will only call anonymous SOAP mathods.
const anonymousConnectionParameters = sdk.ConnectionParameters.ofAnonymousUser("https://my.campaign.adobe.com");
const anonymousClient = await sdk.init(anonymousConnectionParameters);

// Make the anonymous call (the makeSoapCall method does not exist in the SDK today,
// the idea would be to add this function in a future release of the SDK).
// As the SDK cannot read the schemas for anonymous call, you would need to provide 2 arrays which
// describe both input and output parameters, with proper names and types
// (in other words, what you have in the <method> definition)
inputParams = [
  { name: "token", type: "string", value: "xxx" },
];
outputParams = [
  { name: "sessionToken", type: "string" },
  { name: "securityToken", type: "string" },
];
const tokens = await anonymousClient.makeSoapCall("xtk:session", "CustomizedLogon", true, inputParams, outputParams);

// Now use the tokens to created a logged client.
// This requires a not-yet-implemented "ofSessionAndSecurityToken" authentiation method which would take
// both session and service tokens.
// Now you need to call logon (and logoff when you're done)
const sessionToken = tokens[0];
const securityToken = tokens[1];
const client = sdk.ConnectionParameters.ofSessionAndSecurityToken("https://my.campaign.adobe.com", sessionToken, securityToken);
await client.logon();

// Do your stuff

// Cleanup after you're done
await client.logoff();
aimanicose4 commented 1 year ago

This seems like a perfect solution to me.

Yes, I am up to to review and comment the PR.

Thank you so much @mkiki for your quick response.

mkiki commented 1 year ago

Hi @aimanicose4 , thanks for your review. I've built a new version of the SDK (1.1.38) with support for anonymous SOAP calls. There's succinct documentation here: https://opensource.adobe.com/acc-js-sdk/anonymous.html

aimanicose4 commented 1 year ago

Thank you !