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

feat: Get promise token for CS autofix requests #830

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

phornig
Copy link

@phornig phornig commented Mar 25, 2025

For sites of delivery type cloud service a promise token needs to be stored in the autofix job to be able to authenticate against the cloud service AEM instance.
This PR uses the IMS Promise client to exchange the user's token against a promise token which is stored in the sqs message payload to be used in the autofix worker later on. The promise token is not considered a secret, but may be optionally encrypted using a shared secret.

@alinarublea alinarublea requested a review from solaris007 March 26, 2025 09:26
Copy link
Member

@solaris007 solaris007 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally unsure why encryption is needed. please involve AEM security team for a spot review of encryption.

@@ -86,7 +71,7 @@ function BrandsController(dataAccess, log, env) {
const imsOrgId = organization.getImsOrgId();
const imsUserToken = getImsUserToken(context);
const brandClient = BrandClient.createFrom(context);
const brands = await brandClient.getBrandsForOrganization(imsOrgId, imsUserToken);
const brands = await brandClient.getBrandsForOrganization(imsOrgId, `Bearer ${imsUserToken}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the fact that an imsUserToken is at some point used as a bearer token in an authorization header should not be a signature requirement, please remove.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what your ask is here. I refactored out the getImsUserToken function to utils to re-use and made it return only the token not the whole authorization header, because going by the function name that would be more expected. But the brands client actually expects the whole authorization header, so I need to add back the Bearer string to make the code functionally equivalent.

if (!context.env?.AUTOFIX_CRYPT_SECRET || !context.env?.AUTOFIX_CRYPT_SALT) {
encryptedPromiseToken = promiseToken;
} else {
const algorithm = context.env?.AUTOFIX_CRYPT_ALG || 'aes-192-cbc';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this default algorithm? it is an uncommon choice, more standard would be AES-256-GCM?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No particular reason. I updated to use the algorithm you propose and made the key length also configurable. In the end the promise token is not considered a secret, so encrypting it is an additional, optional layer of safety which @alinarublea proposed to add. The tokens are also fairly short lived, so the algorithm used won't matter too much.

context.env.AUTOFIX_CRYPT_SALT,
24,
);
const iv = crypto.randomBytes(16);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though a random IV is generated, it's not stored or sent with the ciphertext. Without the IV, decryption later becomes problematic. Typically, you’d prepend the IV to the ciphertext so that it can be used for decryption.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, added it, also refactored to have the encryption in the IMS client to have encryption/decryption closer together, see PR there adobe/spacecat-shared#667

const key = await promisify(crypto.scrypt)(
context.env.AUTOFIX_CRYPT_SECRET,
context.env.AUTOFIX_CRYPT_SALT,
24,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AES-256 uses a 32-byte key, providing stronger encryption, in case you plan to switch

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the algorithm fixed, having it configurable isn't really feasible, nor needed, moved encryption code to adobe/spacecat-shared#667

* @returns {string} imsUserToken - The IMS User access token.
* @throws {ErrorWithStatusCode} - If the Authorization header is missing.
*/
export function getImsUserToken(context) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar code is to be found in spacecat-shared-ims-client - please re-use

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not find any similar code in spacecat-shared-ims-client. There is private method 'getBearerToken' somewhere in spacecat-shared-http-utils, I'd rather not refactor a completely unrelated module within this PR. Already refactored to re-use within this module, so I am not adding additional code.

@phornig
Copy link
Author

phornig commented Mar 27, 2025

Moved encryption related code to the IMS client for better re-use, see adobe/spacecat-shared#667
Since promise token are not considered secret, we could also drop encryption completely, now it is optional.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants