Skip to content

Commit 6b5dada

Browse files
authored
[SITES-36232] secretID authentication (#248)
* secretID authentication setup wizard now accept site token as an optional field, and also automatically update site context for prerender UI. added authorization header with site token to request for product template and spreadsheet (config.json) * auto test update updated auto test to handle the extra arguement
1 parent 396fd92 commit 6b5dada

8 files changed

Lines changed: 67 additions & 20 deletions

File tree

actions/check-product-changes/poller.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ async function poll(params, aioLibs, logger) {
393393
const counts = { published: 0, unpublished: 0, ignored: 0, failed: 0 };
394394
const {
395395
org, site, pathFormat,
396-
configName, configSheet,
396+
siteToken, configName, configSheet,
397397
adminAuthToken,
398398
productsTemplate, storeUrl, contentUrl,
399399
logLevel, logIngestorEndpoint,
@@ -408,6 +408,7 @@ async function poll(params, aioLibs, logger) {
408408
: [null]);
409409

410410
const sharedContext = {
411+
siteToken,
411412
storeUrl,
412413
contentUrl,
413414
configName,

actions/lib/runtimeConfig.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ const DEFAULTS = {
1919
CONTENT_URL: undefined,
2020
STORE_URL: undefined,
2121
PRODUCTS_TEMPLATE: undefined,
22-
23-
LOCALES: undefined
22+
LOCALES: undefined,
23+
SITE_TOKEN: undefined
2424
};
2525

2626
/**
@@ -54,6 +54,8 @@ function getRuntimeConfig(params = {}, options = {}) {
5454
}
5555

5656
const adminToken = merged.AEM_ADMIN_API_AUTH_TOKEN;
57+
const siteToken = merged.SITE_TOKEN;
58+
5759

5860
// Validate admin token if requested
5961
if (options.validateToken) {
@@ -98,6 +100,7 @@ function getRuntimeConfig(params = {}, options = {}) {
98100
logLevel: merged.LOG_LEVEL,
99101
logIngestorEndpoint: merged.LOG_INGESTOR_ENDPOINT,
100102
adminAuthToken: adminToken,
103+
siteToken: siteToken,
101104
contentUrl: merged.CONTENT_URL,
102105
storeUrl: merged.STORE_URL,
103106
productsTemplate: merged.PRODUCTS_TEMPLATE,

actions/pdp-renderer/lib.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,16 @@ async function prepareBaseTemplate(url, blocks, context) {
7373
url = url.replace(/\s+/g, '').replace(/\/$/, '').replace('{locale}', context.locale);
7474
}
7575

76-
const baseTemplateHtml = await fetch(`${url}.plain.html`).then(resp => resp.text());
76+
const { siteToken } = context;
77+
78+
let options = undefined;
79+
80+
// Site Validation: needs to be a non empty string
81+
if (typeof siteToken === 'string' && siteToken.trim()) {
82+
options = {headers:{'authorization': `token ${siteToken}`}}
83+
}
84+
85+
const baseTemplateHtml = await fetch(`${url}.plain.html`, {...options}).then(resp => resp.text());
7786

7887
const $ = cheerio.load(`<main>${baseTemplateHtml}</main>`);
7988

actions/utils.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,14 @@ async function request(name, url, req, timeout = 60000) {
195195
*/
196196
async function requestSpreadsheet(name, sheet, context, offset = 0) {
197197
const { contentUrl } = context;
198+
const { siteToken } = context;
199+
200+
let options = undefined;
201+
// Site Token Validation: needs to be a non empty string
202+
if (typeof siteToken === 'string' && siteToken.trim()) {
203+
options = {headers:{'authorization': `token ${siteToken}`}}
204+
}
205+
198206
let sheetUrl = `${contentUrl}/${name}.json`
199207
const requestURL = new URL(sheetUrl);
200208

@@ -206,7 +214,7 @@ async function requestSpreadsheet(name, sheet, context, offset = 0) {
206214
requestURL.searchParams.set('offset', offset);
207215
}
208216

209-
return request('spreadsheet', requestURL.toString());
217+
return request('spreadsheet', requestURL.toString(), options);
210218
}
211219

212220
/**
@@ -232,9 +240,16 @@ async function requestPublishedProductsIndex(context) {
232240
}
233241

234242
async function requestConfigService(context) {
235-
const { contentUrl, configName = 'config' } = context;
243+
const { contentUrl, configName = 'config', siteToken = undefined } = context;
244+
245+
let options = undefined;
246+
// Site Token Validation: needs to be a non empty string
247+
if (typeof siteToken === 'string' && siteToken.trim()) {
248+
options = {headers:{'authorization': `token ${siteToken}`}}
249+
}
250+
236251
let publicConfig = `${contentUrl}/${configName}.json`
237-
return request('configservice', publicConfig);
252+
return request('configservice', publicConfig, options);
238253
}
239254

240255
/**
@@ -249,6 +264,7 @@ async function requestConfigService(context) {
249264
*/
250265
async function getConfig(context) {
251266
const { configName = 'config', configSheet, logger, locale } = context;
267+
252268
if (!context.config) {
253269
// try to fetch the config from the config service first
254270
logger.debug(`Fetching public config`);

app.config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ application:
1515
STORE_URL: "${STORE_URL}"
1616
CONFIG_NAME: "config"
1717
LOCALES: "${LOCALES}"
18+
SITE_TOKEN: "${SITE_TOKEN}"
1819
actions:
1920
pdp-renderer:
2021
function: "actions/pdp-renderer/index.js"

bin/setup/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ const RULES_MAP = {
404404
id: parsedData.id,
405405
org: parsedData.org,
406406
site: parsedData.site,
407+
siteToken: parsedData.siteToken,
407408
namespace: parsedData.appbuilderProjectJSON?.project?.workspace?.details?.runtime?.namespaces?.[0]?.name
408409
}
409410
});
@@ -672,10 +673,11 @@ const RULES_MAP = {
672673
envObject['STORE_URL'] = appConfigParams.storeUrl;
673674
envObject['PRODUCTS_TEMPLATE'] = appConfigParams.productsTemplate;
674675
envObject['LOCALES'] = appConfigParams.locales;
676+
envObject['SITE_TOKEN'] = appConfigParams.siteToken;
675677

676678
const newEnvContent = dotenvStringify(envObject);
677679
fs.writeFileSync(envPath, newEnvContent);
678-
console.log('Successfully updated .env file with AEM_ADMIN_API_AUTH_TOKEN.');
680+
console.log('Successfully updated .env file with provided parameters.');
679681

680682
} catch (error) {
681683
console.error('Failed to write configuration files:', error);

bin/setup/ui/setup-wizard.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,8 @@ export class SetupWizard extends LitElement {
543543
productsTemplate: '',
544544
storeUrl: '',
545545
configName: 'config',
546-
locales: null
546+
locales: null,
547+
siteToken: ''
547548
};
548549
this.previewData = null;
549550
this.healthChecks = [];
@@ -1240,6 +1241,7 @@ export class SetupWizard extends LitElement {
12401241
id: `${this.org}/${this.site}`,
12411242
org: this.org,
12421243
site: this.site,
1244+
...(this.advancedSettings.siteToken && {siteToken: this.advancedSettings.siteToken}),
12431245
appbuilderProjectJSON: {
12441246
project: {
12451247
name: this.aioConfigFile?.name?.replace('.json', '') || 'aem-commerce-prerender',
@@ -1310,6 +1312,7 @@ export class SetupWizard extends LitElement {
13101312
}
13111313
}
13121314

1315+
// Step 1: Org and site configuration, and Helix Token
13131316
renderStep1AccessToken() {
13141317
return html`<div class="step-content">
13151318
<h3>Step 1: Get Access Token</h3>
@@ -1411,6 +1414,7 @@ export class SetupWizard extends LitElement {
14111414
</div>`;
14121415
}
14131416

1417+
// Step 2: Appbuilder workspace configuration/upload
14141418
renderStep2Token() {
14151419
return html`<div class="step-content">
14161420
<h3>Step 2: AIO Configuration</h3>
@@ -1473,6 +1477,7 @@ export class SetupWizard extends LitElement {
14731477
</div>`;
14741478
}
14751479

1480+
// Step 3: Site COnfiguration
14761481
renderStep3AdvancedSettings() {
14771482
return html`
14781483
<div class="step-content">
@@ -1549,13 +1554,21 @@ export class SetupWizard extends LitElement {
15491554
.value=${this.advancedSettings.storeUrl}
15501555
@input=${e => this.handleAdvancedSettingInput('storeUrl', e.target.value)}
15511556
></sp-textfield>
1557+
1558+
<sp-field-label for="store-url" required>Site Token (Optional)</sp-field-label>
1559+
<sp-textfield
1560+
id="site-token"
1561+
.value=${this.advancedSettings.siteToken}
1562+
@input=${e => this.handleAdvancedSettingInput('siteToken', e.target.value)}
1563+
></sp-textfield>
15521564
</div>
15531565
</sp-accordion-item>
15541566
</sp-accordion>
15551567
</div>
15561568
</div>`;
15571569
}
15581570

1571+
// Step 4: Preview and apply configuration
15591572
renderStep4Review() {
15601573
return html`
15611574
<div class="step-content">

test/lib.test.js

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ describe('lib', () => {
108108
jest.clearAllMocks();
109109
});
110110

111+
// test 1: should replace {locale} token when locale is provided and not default
111112
test('should replace {locale} token when locale is provided and not default', async () => {
112113
global.fetch.mockResolvedValueOnce({
113114
text: () => Promise.resolve(mockTemplateHtml)
@@ -119,9 +120,10 @@ describe('lib', () => {
119120

120121
await prepareBaseTemplate(url, blocks, context);
121122

122-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/en/products/default.plain.html');
123+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/en/products/default.plain.html', {});
123124
});
124125

126+
// test 2: should replace {locale} token with complex locale codes
125127
test('should replace {locale} token with complex locale codes', async () => {
126128
global.fetch.mockResolvedValueOnce({
127129
text: () => Promise.resolve(mockTemplateHtml)
@@ -133,7 +135,7 @@ describe('lib', () => {
133135

134136
await prepareBaseTemplate(url, blocks, context);
135137

136-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/en/uk/products/default.plain.html');
138+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/en/uk/products/default.plain.html', {});
137139
});
138140

139141
test('should handle URL with multiple {locale} tokens (only replaces first occurrence)', async () => {
@@ -148,7 +150,7 @@ describe('lib', () => {
148150
await prepareBaseTemplate(url, blocks, context);
149151

150152
// Current implementation only replaces the first {locale} occurrence
151-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/fr/category/{locale}/products/default.plain.html');
153+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/fr/category/{locale}/products/default.plain.html', {});
152154
});
153155

154156
test('should trim whitespace and trailing slash before locale replacement', async () => {
@@ -162,7 +164,7 @@ describe('lib', () => {
162164

163165
await prepareBaseTemplate(url, blocks, context);
164166

165-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/de/products/default.plain.html');
167+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/de/products/default.plain.html', {});
166168
});
167169

168170
test('should not replace {locale} token when locale is "default"', async () => {
@@ -176,7 +178,7 @@ describe('lib', () => {
176178

177179
await prepareBaseTemplate(url, blocks, context);
178180

179-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/{locale}/products/default.plain.html');
181+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/{locale}/products/default.plain.html', {});
180182
});
181183

182184
test('should not replace {locale} token when locale is not provided', async () => {
@@ -190,7 +192,7 @@ describe('lib', () => {
190192

191193
await prepareBaseTemplate(url, blocks, context);
192194

193-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/{locale}/products/default.plain.html');
195+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/{locale}/products/default.plain.html', {});
194196
});
195197

196198
test('should not replace {locale} token when locale is null', async () => {
@@ -204,7 +206,7 @@ describe('lib', () => {
204206

205207
await prepareBaseTemplate(url, blocks, context);
206208

207-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/{locale}/products/default.plain.html');
209+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/{locale}/products/default.plain.html', {});
208210
});
209211

210212
test('should not replace {locale} token when locale is undefined', async () => {
@@ -218,7 +220,7 @@ describe('lib', () => {
218220

219221
await prepareBaseTemplate(url, blocks, context);
220222

221-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/{locale}/products/default.plain.html');
223+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/{locale}/products/default.plain.html', {});
222224
});
223225

224226
test('should replace blocks with handlebars partials after locale replacement', async () => {
@@ -232,7 +234,7 @@ describe('lib', () => {
232234

233235
const result = await prepareBaseTemplate(url, blocks, context);
234236

235-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/es/products/default.plain.html');
237+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/es/products/default.plain.html', {});
236238
expect(result).toContain('{{> hero }}');
237239
expect(result).toContain('{{> product-recommendations }}');
238240
});
@@ -248,7 +250,7 @@ describe('lib', () => {
248250

249251
await prepareBaseTemplate(url, blocks, context);
250252

251-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/products/default.plain.html');
253+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/products/default.plain.html', {});
252254
});
253255

254256
test('should handle empty blocks array', async () => {
@@ -262,7 +264,7 @@ describe('lib', () => {
262264

263265
const result = await prepareBaseTemplate(url, blocks, context);
264266

265-
expect(global.fetch).toHaveBeenCalledWith('https://content.com/it/products/default.plain.html');
267+
expect(global.fetch).toHaveBeenCalledWith('https://content.com/it/products/default.plain.html', {});
266268
expect(result).toBe('<div class="hero">Hero content</div><div class="product-recommendations">Recommendations</div>\n');
267269
});
268270

0 commit comments

Comments
 (0)