@unito/integration-cli 0.63.3 → 0.63.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/commands/oauth2.js +1 -1
- package/dist/src/resources/oauth2.d.ts +1 -1
- package/dist/src/resources/oauth2.js +2 -2
- package/dist/src/services/oauth2.js +1 -1
- package/dist/test/commands/oauth2.test.js +66 -0
- package/dist/test/resources/oauth2.test.js +28 -0
- package/dist/test/services/oauth2.test.js +37 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -102,7 +102,7 @@ class Oauth2 extends core_1.Command {
|
|
|
102
102
|
}
|
|
103
103
|
const refreshToken = decryptionResult?.successful.refreshToken;
|
|
104
104
|
core_1.ux.action.start(`Refreshing test account ${testAccount}`, undefined, { stdout: true });
|
|
105
|
-
credentials = await Oauth2Resource.updateToken(oauth2, refreshToken);
|
|
105
|
+
credentials = await Oauth2Resource.updateToken(oauth2, refreshToken, decryptionResult?.successful, environment);
|
|
106
106
|
// If provider response doesn't contain a new refresh token, use the existing one
|
|
107
107
|
credentials.refreshToken = credentials.refreshToken ?? refreshToken;
|
|
108
108
|
core_1.ux.action.stop();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Oauth2Response, Oauth2Payload } from '../services/oauth2';
|
|
2
2
|
import { Environment } from './globalConfiguration';
|
|
3
3
|
export declare function performOAuth2Flow(applicationCredentials: Oauth2Payload, environment?: Environment, credentialPayload?: Record<string, unknown>): Promise<Oauth2Response>;
|
|
4
|
-
export declare function updateToken(applicationCredentials: Oauth2Payload, refreshToken: string): Promise<Oauth2Response>;
|
|
4
|
+
export declare function updateToken(applicationCredentials: Oauth2Payload, refreshToken: string, credentialPayload?: Record<string, unknown>, environment?: Environment): Promise<Oauth2Response>;
|
|
@@ -22,7 +22,7 @@ async function performOAuth2Flow(applicationCredentials, environment = globalCon
|
|
|
22
22
|
}
|
|
23
23
|
return oauth2Response;
|
|
24
24
|
}
|
|
25
|
-
async function updateToken(applicationCredentials, refreshToken) {
|
|
26
|
-
const oauthHelper = new oauth2_1.default(applicationCredentials);
|
|
25
|
+
async function updateToken(applicationCredentials, refreshToken, credentialPayload, environment = globalConfiguration_1.Environment.Production) {
|
|
26
|
+
const oauthHelper = new oauth2_1.default(applicationCredentials, environment, credentialPayload);
|
|
27
27
|
return oauthHelper.updateToken(refreshToken);
|
|
28
28
|
}
|
|
@@ -250,7 +250,7 @@ class OAuth2Service {
|
|
|
250
250
|
});
|
|
251
251
|
}
|
|
252
252
|
try {
|
|
253
|
-
const tokenResponse = await fetch(this.tokenUrl, {
|
|
253
|
+
const tokenResponse = await fetch((0, template_1.expandTemplate)(this.tokenUrl, templateVariables, { urlEncodeVariables: true }), {
|
|
254
254
|
headers: {
|
|
255
255
|
'Content-Type': this.requestContentType,
|
|
256
256
|
...(tokenRequestHeaders ?? {}),
|
|
@@ -303,4 +303,70 @@ describe('oauth2', () => {
|
|
|
303
303
|
.it('must successfully decrypt all secrets', ctx => {
|
|
304
304
|
(0, test_1.expect)(ctx.stderr).to.contain((0, styles_1.uncolorize)('The secret boom! could not be decrypted.'));
|
|
305
305
|
});
|
|
306
|
+
test_1.test
|
|
307
|
+
.stdout()
|
|
308
|
+
.do(() => {
|
|
309
|
+
getConfigurationsStub.returns({
|
|
310
|
+
...baseConfiguration,
|
|
311
|
+
testAccounts: {
|
|
312
|
+
development: credentials,
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
sinon
|
|
316
|
+
.stub(IntegrationsPlatform, 'encryptData')
|
|
317
|
+
.onFirstCall()
|
|
318
|
+
.resolves({ encryptedData: `${Configuration.ENCRYPTION_PREFIX}encryptedAccessToken` })
|
|
319
|
+
.onSecondCall()
|
|
320
|
+
.resolves({ encryptedData: `${Configuration.ENCRYPTION_PREFIX}encryptedRefreshToken` });
|
|
321
|
+
})
|
|
322
|
+
.stub(DecryptionResource, 'decryptEntries', stub => stub
|
|
323
|
+
.onFirstCall()
|
|
324
|
+
.resolves({ successful: { ...oauth2Information }, failed: [] })
|
|
325
|
+
.onSecondCall()
|
|
326
|
+
.resolves({ successful: { refreshToken: 'test-refresh-token' }, failed: [] }))
|
|
327
|
+
.command(['oauth2', '--test-account', 'development', '--environment', 'staging'])
|
|
328
|
+
.it('passes the staging environment to updateToken when specified', () => {
|
|
329
|
+
(0, test_1.expect)(performOAuth2FlowStub.getCalls().length).to.equal(0);
|
|
330
|
+
(0, test_1.expect)(updateTokenStub.getCalls().length).to.equal(1);
|
|
331
|
+
// Verify that updateToken was called with the correct environment parameter
|
|
332
|
+
const updateTokenCall = updateTokenStub.getCall(0);
|
|
333
|
+
(0, test_1.expect)(updateTokenCall.args).to.have.lengthOf(4);
|
|
334
|
+
(0, test_1.expect)(updateTokenCall.args[0]).to.deep.equal(oauth2Information); // oauth2 config
|
|
335
|
+
(0, test_1.expect)(updateTokenCall.args[1]).to.equal('test-refresh-token'); // refresh token
|
|
336
|
+
(0, test_1.expect)(updateTokenCall.args[2]).to.deep.equal({ refreshToken: 'test-refresh-token' }); // credential payload
|
|
337
|
+
(0, test_1.expect)(updateTokenCall.args[3]).to.equal('staging'); // environment
|
|
338
|
+
});
|
|
339
|
+
test_1.test
|
|
340
|
+
.stdout()
|
|
341
|
+
.do(() => {
|
|
342
|
+
getConfigurationsStub.returns({
|
|
343
|
+
...baseConfiguration,
|
|
344
|
+
testAccounts: {
|
|
345
|
+
development: credentials,
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
sinon
|
|
349
|
+
.stub(IntegrationsPlatform, 'encryptData')
|
|
350
|
+
.onFirstCall()
|
|
351
|
+
.resolves({ encryptedData: `${Configuration.ENCRYPTION_PREFIX}encryptedAccessToken` })
|
|
352
|
+
.onSecondCall()
|
|
353
|
+
.resolves({ encryptedData: `${Configuration.ENCRYPTION_PREFIX}encryptedRefreshToken` });
|
|
354
|
+
})
|
|
355
|
+
.stub(DecryptionResource, 'decryptEntries', stub => stub
|
|
356
|
+
.onFirstCall()
|
|
357
|
+
.resolves({ successful: { ...oauth2Information }, failed: [] })
|
|
358
|
+
.onSecondCall()
|
|
359
|
+
.resolves({ successful: { refreshToken: 'test-refresh-token' }, failed: [] }))
|
|
360
|
+
.command(['oauth2', '--test-account', 'development'])
|
|
361
|
+
.it('defaults to production environment when no environment flag is specified', () => {
|
|
362
|
+
(0, test_1.expect)(performOAuth2FlowStub.getCalls().length).to.equal(0);
|
|
363
|
+
(0, test_1.expect)(updateTokenStub.getCalls().length).to.equal(1);
|
|
364
|
+
// Verify that updateToken was called with the default production environment
|
|
365
|
+
const updateTokenCall = updateTokenStub.getCall(0);
|
|
366
|
+
(0, test_1.expect)(updateTokenCall.args).to.have.lengthOf(4);
|
|
367
|
+
(0, test_1.expect)(updateTokenCall.args[0]).to.deep.equal(oauth2Information); // oauth2 config
|
|
368
|
+
(0, test_1.expect)(updateTokenCall.args[1]).to.equal('test-refresh-token'); // refresh token
|
|
369
|
+
(0, test_1.expect)(updateTokenCall.args[2]).to.deep.equal({ refreshToken: 'test-refresh-token' }); // credential payload
|
|
370
|
+
(0, test_1.expect)(updateTokenCall.args[3]).to.equal('production'); // environment (default)
|
|
371
|
+
});
|
|
306
372
|
});
|
|
@@ -52,4 +52,32 @@ describe('OAuth2Helper', () => {
|
|
|
52
52
|
await strict_1.default.rejects(response, errors_1.FailedToRetrieveAccessTokenError);
|
|
53
53
|
});
|
|
54
54
|
});
|
|
55
|
+
describe('updateToken', () => {
|
|
56
|
+
let updateTokenStub;
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
updateTokenStub = sinon_1.default.stub(oauth2_1.default.prototype, 'updateToken');
|
|
59
|
+
});
|
|
60
|
+
it('should create OAuth2Service with credential payload and call updateToken', async () => {
|
|
61
|
+
const mockResponse = { accessToken: 'new-token', refreshToken: 'new-refresh-token' };
|
|
62
|
+
updateTokenStub.resolves(mockResponse);
|
|
63
|
+
const credentialPayload = { domain: 'test-domain', customVar: 'test-value' };
|
|
64
|
+
const refreshToken = 'test-refresh-token';
|
|
65
|
+
const result = await oauth2HelperResource.updateToken(authorizationInfo, refreshToken, credentialPayload);
|
|
66
|
+
// Assert that the OAuth2Service was instantiated with the credential payload
|
|
67
|
+
// and that updateToken was called with the refresh token
|
|
68
|
+
sinon_1.default.assert.calledOnce(updateTokenStub);
|
|
69
|
+
sinon_1.default.assert.calledWith(updateTokenStub, refreshToken);
|
|
70
|
+
strict_1.default.deepEqual(result, mockResponse);
|
|
71
|
+
});
|
|
72
|
+
it('should work without credential payload', async () => {
|
|
73
|
+
const mockResponse = { accessToken: 'new-token', refreshToken: 'new-refresh-token' };
|
|
74
|
+
updateTokenStub.resolves(mockResponse);
|
|
75
|
+
const refreshToken = 'test-refresh-token';
|
|
76
|
+
const result = await oauth2HelperResource.updateToken(authorizationInfo, refreshToken);
|
|
77
|
+
// Should still work when no credential payload is provided
|
|
78
|
+
sinon_1.default.assert.calledOnce(updateTokenStub);
|
|
79
|
+
sinon_1.default.assert.calledWith(updateTokenStub, refreshToken);
|
|
80
|
+
strict_1.default.deepEqual(result, mockResponse);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
55
83
|
});
|
|
@@ -422,6 +422,43 @@ describe('OAuth2Helper', () => {
|
|
|
422
422
|
const response = oauth2Helper.updateToken(refreshToken);
|
|
423
423
|
await strict_1.default.rejects(response, errors_1.InvalidRequestContentTypeError);
|
|
424
424
|
});
|
|
425
|
+
describe('token URL template expansion', () => {
|
|
426
|
+
it('expands template variables in token URL during refresh', async () => {
|
|
427
|
+
const credentialPayload = { domain: 'test-domain' };
|
|
428
|
+
oauth2Helper = new oauth2_1.default({
|
|
429
|
+
clientId: 'test-client-id',
|
|
430
|
+
clientSecret: 'test-client-secret',
|
|
431
|
+
authorizationUrl: 'https://provider.com/oauth/authorize',
|
|
432
|
+
scopes: [{ name: 'scope1' }],
|
|
433
|
+
tokenUrl: 'https://{+domain}.provider.com/oauth/token', // Template URL
|
|
434
|
+
grantType: configurationTypes_1.GrantType.AUTHORIZATION_CODE,
|
|
435
|
+
requestContentType: configurationTypes_1.RequestContentType.URL_ENCODED,
|
|
436
|
+
}, globalConfiguration_1.Environment.Production, credentialPayload);
|
|
437
|
+
const { refreshToken } = setupSuccessfulRefreshResponse();
|
|
438
|
+
await oauth2Helper.updateToken(refreshToken);
|
|
439
|
+
// Assert that the token URL was expanded with the domain
|
|
440
|
+
sinon_1.default.assert.calledWith(fetchStub, 'https://test-domain.provider.com/oauth/token', sinon_1.default.match.object);
|
|
441
|
+
});
|
|
442
|
+
it('expands multiple template variables in token URL', async () => {
|
|
443
|
+
const credentialPayload = {
|
|
444
|
+
domain: 'my-company',
|
|
445
|
+
environment: 'staging',
|
|
446
|
+
};
|
|
447
|
+
oauth2Helper = new oauth2_1.default({
|
|
448
|
+
clientId: 'test-client-id',
|
|
449
|
+
clientSecret: 'test-client-secret',
|
|
450
|
+
authorizationUrl: 'https://provider.com/oauth/authorize',
|
|
451
|
+
scopes: [{ name: 'scope1' }],
|
|
452
|
+
tokenUrl: 'https://{+domain}.{+environment}.provider.com/oauth/token',
|
|
453
|
+
grantType: configurationTypes_1.GrantType.AUTHORIZATION_CODE,
|
|
454
|
+
requestContentType: configurationTypes_1.RequestContentType.URL_ENCODED,
|
|
455
|
+
}, globalConfiguration_1.Environment.Production, credentialPayload);
|
|
456
|
+
const { refreshToken } = setupSuccessfulRefreshResponse();
|
|
457
|
+
await oauth2Helper.updateToken(refreshToken);
|
|
458
|
+
// Assert that both template variables were expanded
|
|
459
|
+
sinon_1.default.assert.calledWith(fetchStub, 'https://my-company.staging.provider.com/oauth/token', sinon_1.default.match.object);
|
|
460
|
+
});
|
|
461
|
+
});
|
|
425
462
|
});
|
|
426
463
|
describe('encodeBody', () => {
|
|
427
464
|
it('encodes body data as URL-encoded when content type is URL_ENCODED', () => {
|
package/oclif.manifest.json
CHANGED