@mimik/oauth-helper 2.2.0 → 3.0.1
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/README.md +2 -52
- package/index.js +1 -298
- package/package.json +13 -15
- package/test/oauthHelper.spec.js +0 -372
- package/test/testConfig.js +0 -111
package/README.md
CHANGED
|
@@ -22,13 +22,8 @@ const oauthHelper = require('@mimik/oauth-helper');
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
* [oauth-helper](#module_oauth-helper)
|
|
25
|
-
*
|
|
26
|
-
|
|
27
|
-
* [~authProfile(method, id, correlationId, options)](#module_oauth-helper..authProfile) ⇒ <code>Promise</code>
|
|
28
|
-
* _callback_
|
|
29
|
-
* [~apiKeySecurityHelper(request, definitions, apiKey, next)](#module_oauth-helper..apiKeySecurityHelper)
|
|
30
|
-
* [~apiTokenSecurityHelper(request, definitions, scopes, next)](#module_oauth-helper..apiTokenSecurityHelper)
|
|
31
|
-
* [~apiTokenAdminSecurityHelper(request, definitions, scopes, next)](#module_oauth-helper..apiTokenAdminSecurityHelper)
|
|
25
|
+
* [~rpAuth(type, options)](#module_oauth-helper..rpAuth) ⇒ <code>Promise</code>
|
|
26
|
+
* [~authProfile(method, id, correlationId, options)](#module_oauth-helper..authProfile) ⇒ <code>Promise</code>
|
|
32
27
|
|
|
33
28
|
<a name="module_oauth-helper..rpAuth"></a>
|
|
34
29
|
|
|
@@ -88,51 +83,6 @@ Make an authProfile request to mID.
|
|
|
88
83
|
| correlationId | <code>UUID.<string></code> | CorrelationId to associated with the request. |
|
|
89
84
|
| options | <code>object</code> | Options to be added to the request. metrics can then be added to the options. |
|
|
90
85
|
|
|
91
|
-
<a name="module_oauth-helper..apiKeySecurityHelper"></a>
|
|
92
|
-
|
|
93
|
-
### oauth-helper~apiKeySecurityHelper(request, definitions, apiKey, next)
|
|
94
|
-
Validate the request by checking the apiKey. To be used for `apikey`;
|
|
95
|
-
|
|
96
|
-
**Kind**: inner method of [<code>oauth-helper</code>](#module_oauth-helper)
|
|
97
|
-
**Category**: callback
|
|
98
|
-
|
|
99
|
-
| Param | Type | Description |
|
|
100
|
-
| --- | --- | --- |
|
|
101
|
-
| request | <code>object</code> | The request with a token in the header. |
|
|
102
|
-
| definitions | <code>object</code> | Swagger security definitions to compare with. |
|
|
103
|
-
| apiKey | <code>Array.<string></code> | APIky extracted from the defined location. |
|
|
104
|
-
| next | [<code>requestCallback</code>](#requestCallback) | The callback that handles the response. The validation adds the following properties to the request: - apiKey Only the header location is allowed. |
|
|
105
|
-
|
|
106
|
-
<a name="module_oauth-helper..apiTokenSecurityHelper"></a>
|
|
107
|
-
|
|
108
|
-
### oauth-helper~apiTokenSecurityHelper(request, definitions, scopes, next)
|
|
109
|
-
Validate the request by inspecting the token. To be used for `system` and `user` token.
|
|
110
|
-
|
|
111
|
-
**Kind**: inner method of [<code>oauth-helper</code>](#module_oauth-helper)
|
|
112
|
-
**Category**: callback
|
|
113
|
-
|
|
114
|
-
| Param | Type | Description |
|
|
115
|
-
| --- | --- | --- |
|
|
116
|
-
| request | <code>object</code> | The request with a token in the header. |
|
|
117
|
-
| definitions | <code>object</code> | Swagger security definitions to compare with. |
|
|
118
|
-
| scopes | <code>Array.<string></code> | List of swagger scopes associated whith the requested endpoint. |
|
|
119
|
-
| next | [<code>requestCallback</code>](#requestCallback) | The callback that handles the response. The validation adds the following properties to the request: - in case of 'system' token: 'claims', clientId', 'tokenType', 'customer', 'onBehlaf'. If the token is a cluster token the property 'cluster' is set to true. - in case of 'user' token: claims, userId, appId, onBehalfId, 'onBehalf'. The claims array contains the claims that are included on the scope of the recieved token. It there is no claims in the scope the claims property in request is an emtpy array. The scope must have the followimg format: `<action>:<resourceName>::<claims>`` where claims is a set of claims separatedby `,`. The is an exception for onBelf scope where the format is `onbBehalf:<action><resourceName>::<claims>`. The claims will be validated looking at the definitions property of the swagger file, by looking at at the top level properties of a definition named: `<resourceName>Claims`. If there is multiple scopes to use, the claims array will contain a concatenation of all the claims if present. |
|
|
120
|
-
|
|
121
|
-
<a name="module_oauth-helper..apiTokenAdminSecurityHelper"></a>
|
|
122
|
-
|
|
123
|
-
### oauth-helper~apiTokenAdminSecurityHelper(request, definitions, scopes, next)
|
|
124
|
-
Validate the request by inspecting the token. To be used for `admin` token.
|
|
125
|
-
|
|
126
|
-
**Kind**: inner method of [<code>oauth-helper</code>](#module_oauth-helper)
|
|
127
|
-
**Category**: callback
|
|
128
|
-
|
|
129
|
-
| Param | Type | Description |
|
|
130
|
-
| --- | --- | --- |
|
|
131
|
-
| request | <code>object</code> | The request with a token in the header. |
|
|
132
|
-
| definitions | <code>object</code> | Swagger security definitions to compare with. |
|
|
133
|
-
| scopes | <code>Array.<string></code> | List of swagger scopes associated whith the requested endpoint. |
|
|
134
|
-
| next | [<code>requestCallback</code>](#requestCallback) | The callback that handles the response. The validation adds the following properties to the request: 'claims', clientId', tokenType', 'customer'. The claims array contains the claims that are included on the scope of the recieved token. It there is no claims in the scope the claims property in request is an emtpy array. The scope must have the followimg format: `<action>:<resourceName>::<claims>`` where claims is a set of claims separatedby `,`. The is an exception for onBelf scope where the format is `onbBehalf:<action><resourceName>::<claims>`. The claims will be validated looking at the definitions property of the swagger file, by looking at at the top level properties of a definition named: `<resourceName>Claims`. If there is multiple scopes to use, the claims array will contain a concatenation of all the claims if present. |
|
|
135
|
-
|
|
136
86
|
<a name="requestCallback"></a>
|
|
137
87
|
|
|
138
88
|
## requestCallback : <code>function</code>
|
package/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
const Promise = require('bluebird');
|
|
2
2
|
const jwt = require('jsonwebtoken');
|
|
3
|
-
const _ = require('lodash');
|
|
4
3
|
|
|
5
4
|
const { rpRetry } = require('@mimik/request-retry');
|
|
6
5
|
const logger = require('@mimik/sumologic-winston-logger');
|
|
7
6
|
const { getRichError } = require('@mimik/response-helper');
|
|
8
|
-
const { TOKEN_PARAMS } = require('@mimik/swagger-helper');
|
|
9
7
|
|
|
10
8
|
Promise.config({ cancellation: true });
|
|
11
9
|
/**
|
|
@@ -15,22 +13,7 @@ Promise.config({ cancellation: true });
|
|
|
15
13
|
*/
|
|
16
14
|
|
|
17
15
|
const TOKEN_REFRESH_TOLERANCE = 900; // in seconds
|
|
18
|
-
const ON_BEHALF = 'onBehalf';
|
|
19
|
-
const SUB_ADMIN = 'subAdmin';
|
|
20
|
-
const ADMIN = 'admin';
|
|
21
|
-
const USER = 'user';
|
|
22
|
-
const NO_GENERIC = 'noGeneric';
|
|
23
|
-
// const APPLICATION = 'application';
|
|
24
|
-
const IMPLICIT = 'implicit';
|
|
25
|
-
const CLIENT = '@clients';
|
|
26
|
-
const AUTHORIZATION = 'authorization';
|
|
27
|
-
const HEADER = 'header';
|
|
28
16
|
const CLUSTER = 'cluster';
|
|
29
|
-
const SCOPES_SEPARATOR = ' ';
|
|
30
|
-
const CLAIMS_SEPARATOR = ',';
|
|
31
|
-
const RESOURCE_SEPARATOR = ':';
|
|
32
|
-
const SCOPE_CLAIMS_SEPARATOR = '::';
|
|
33
|
-
const CLAIMS_DEFINITION = 'Claims';
|
|
34
17
|
const CLIENT_CEDENTIALS = 'client_credentials';
|
|
35
18
|
const REFRESH_TOKEN = 'refresh_token';
|
|
36
19
|
|
|
@@ -51,100 +34,7 @@ const createToken = (value) => {
|
|
|
51
34
|
};
|
|
52
35
|
|
|
53
36
|
module.exports = (config) => {
|
|
54
|
-
const {
|
|
55
|
-
const jwtOptions = (fl) => {
|
|
56
|
-
if (fl === IMPLICIT) { // user flow
|
|
57
|
-
return {
|
|
58
|
-
audience: (implicit && implicit.audience) || server.audience,
|
|
59
|
-
issuer: (implicit && implicit.issuer) || server.issuer,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
// server to server or admin flow (application)
|
|
63
|
-
return {
|
|
64
|
-
audience: (generic.audience === NO_GENERIC) ? server.audience : generic.audience,
|
|
65
|
-
issuer: server.issuer,
|
|
66
|
-
// subject: `${config.serverSettings.id}@clients`,
|
|
67
|
-
};
|
|
68
|
-
};
|
|
69
|
-
const keys = (fl) => {
|
|
70
|
-
if (fl === IMPLICIT) { // user flow
|
|
71
|
-
return (implicit && implicit.key)
|
|
72
|
-
|| ((generic.key === NO_GENERIC) ? server.accessKey : generic.key);
|
|
73
|
-
}
|
|
74
|
-
// server to server or admin flow (application)
|
|
75
|
-
return (generic.key === NO_GENERIC) ? server.accessKey : generic.key;
|
|
76
|
-
};
|
|
77
|
-
const checkHeaders = (headers) => {
|
|
78
|
-
if (!headers) {
|
|
79
|
-
throw new Error('missing header');
|
|
80
|
-
}
|
|
81
|
-
const authNames = Object.keys(headers).filter((key) => key.toLowerCase() === AUTHORIZATION);
|
|
82
|
-
const authNamesLength = authNames.length;
|
|
83
|
-
|
|
84
|
-
if (authNamesLength === 0) {
|
|
85
|
-
throw new Error(`missing ${AUTHORIZATION} header`);
|
|
86
|
-
}
|
|
87
|
-
if (authNamesLength !== 1) {
|
|
88
|
-
throw new Error(`duplicated ${AUTHORIZATION} header`);
|
|
89
|
-
}
|
|
90
|
-
const auth = headers[authNames[0]].split(' ');
|
|
91
|
-
|
|
92
|
-
if ((auth[0] !== 'bearer' && auth[0] !== 'Bearer') || auth.length !== 2) {
|
|
93
|
-
throw new Error(`authorization type incorrect: ${auth[0]}`);
|
|
94
|
-
}
|
|
95
|
-
return auth[1];
|
|
96
|
-
};
|
|
97
|
-
const checkScopes = (tokenScopes, defScopes, swagger) => {
|
|
98
|
-
if (!tokenScopes) {
|
|
99
|
-
throw new Error('no scope in authorization token');
|
|
100
|
-
}
|
|
101
|
-
let claims = [];
|
|
102
|
-
let onBehalf = false;
|
|
103
|
-
|
|
104
|
-
if (defScopes && defScopes.length !== 0) {
|
|
105
|
-
const currentScopes = tokenScopes.split(SCOPES_SEPARATOR);
|
|
106
|
-
const intersects = [];
|
|
107
|
-
let resourceIndex = 1;
|
|
108
|
-
|
|
109
|
-
currentScopes.forEach((currentScope) => {
|
|
110
|
-
const analyzedScope = currentScope.split(SCOPE_CLAIMS_SEPARATOR);
|
|
111
|
-
const analyzedResource = analyzedScope[0].split(RESOURCE_SEPARATOR);
|
|
112
|
-
if (analyzedResource[0] === ON_BEHALF) {
|
|
113
|
-
onBehalf = true;
|
|
114
|
-
resourceIndex = 2; // legacy handling
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (defScopes.includes(analyzedScope[0])) {
|
|
118
|
-
if (analyzedScope[1]) {
|
|
119
|
-
const includedDefinitionName = `${analyzedResource[resourceIndex]}${CLAIMS_DEFINITION}`;
|
|
120
|
-
|
|
121
|
-
if (!swagger || !swagger.swaggerObject || !swagger.swaggerObject.definitions) {
|
|
122
|
-
throw new Error(`missing ${includedDefinitionName} definition: no definitions`);
|
|
123
|
-
}
|
|
124
|
-
const includedDefinition = swagger.swaggerObject.definitions[includedDefinitionName];
|
|
125
|
-
|
|
126
|
-
if (!includedDefinition) {
|
|
127
|
-
throw new Error(`missing ${includedDefinitionName} definition`);
|
|
128
|
-
}
|
|
129
|
-
const includedClaims = analyzedScope[1].split(CLAIMS_SEPARATOR);
|
|
130
|
-
const definitionClaims = Object.keys(includedDefinition);
|
|
131
|
-
const claimsIntersects = _.intersection(includedClaims, definitionClaims);
|
|
132
|
-
|
|
133
|
-
if (claimsIntersects.length !== includedClaims.length) {
|
|
134
|
-
throw new Error(`incorrect claims included: ${_.difference(includedClaims, claimsIntersects)}`);
|
|
135
|
-
}
|
|
136
|
-
claims = claims.concat(claimsIntersects);
|
|
137
|
-
}
|
|
138
|
-
intersects.push(analyzedScope[0]);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
if (intersects.length === 0) {
|
|
142
|
-
throw new Error(`incorrect scopes: ${tokenScopes}`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return { onBehalf, claims };
|
|
146
|
-
};
|
|
147
|
-
|
|
37
|
+
const { server } = config.security;
|
|
148
38
|
const getToken = (type, origin, correlationId, options) => {
|
|
149
39
|
const tokenOptions = {
|
|
150
40
|
method: 'POST',
|
|
@@ -292,190 +182,6 @@ module.exports = (config) => {
|
|
|
292
182
|
});
|
|
293
183
|
};
|
|
294
184
|
|
|
295
|
-
/**
|
|
296
|
-
* Validate the request by checking the apiKey. To be used for `apikey`;
|
|
297
|
-
*
|
|
298
|
-
* @function apiKeySecurityHelper
|
|
299
|
-
* @category callback
|
|
300
|
-
* @param {object} request - The request with a token in the header.
|
|
301
|
-
* @param {object} definitions - Swagger security definitions to compare with.
|
|
302
|
-
* @param {string[]} apiKey - APIky extracted from the defined location.
|
|
303
|
-
* @param {requestCallback} next - The callback that handles the response.
|
|
304
|
-
*
|
|
305
|
-
* The validation adds the following properties to the request:
|
|
306
|
-
* - apiKey
|
|
307
|
-
* Only the header location is allowed.
|
|
308
|
-
*/
|
|
309
|
-
const apiKeySecurityHelper = (request, definitions, apiKey, next) => {
|
|
310
|
-
if (definitions.in !== HEADER) {
|
|
311
|
-
next(new Error(`invalid location: only ${HEADER} is accepted`));
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
if (config.security.apiKeys.includes(apiKey)) {
|
|
315
|
-
request.apiKey = apiKey;
|
|
316
|
-
next(null);
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
next(new Error('invalid API key'));
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Validate the request by inspecting the token. To be used for `system` and `user` token.
|
|
324
|
-
*
|
|
325
|
-
* @function apiTokenSecurityHelper
|
|
326
|
-
* @category callback
|
|
327
|
-
* @param {object} request - The request with a token in the header.
|
|
328
|
-
* @param {object} definitions - Swagger security definitions to compare with.
|
|
329
|
-
* @param {string[]} scopes - List of swagger scopes associated whith the requested endpoint.
|
|
330
|
-
* @param {requestCallback} next - The callback that handles the response.
|
|
331
|
-
*
|
|
332
|
-
* The validation adds the following properties to the request:
|
|
333
|
-
* - in case of 'system' token: 'claims', clientId', 'tokenType', 'customer', 'onBehlaf'. If the token is a cluster token the property 'cluster' is set to true.
|
|
334
|
-
* - in case of 'user' token: claims, userId, appId, onBehalfId, 'onBehalf'.
|
|
335
|
-
*
|
|
336
|
-
* The claims array contains the claims that are included on the scope of the recieved token. It there is no claims in the scope the claims property in request is an emtpy array.
|
|
337
|
-
* The scope must have the followimg format: `<action>:<resourceName>::<claims>`` where claims is a set of claims separatedby `,`. The is an exception for onBelf scope where the format is `onbBehalf:<action><resourceName>::<claims>`.
|
|
338
|
-
* The claims will be validated looking at the definitions property of the swagger file, by looking at at the top level properties of a definition named: `<resourceName>Claims`.
|
|
339
|
-
* If there is multiple scopes to use, the claims array will contain a concatenation of all the claims if present.
|
|
340
|
-
*/
|
|
341
|
-
const apiTokenSecurityHelper = (request, definitions, scopes, next) => {
|
|
342
|
-
let authToken;
|
|
343
|
-
const { flow } = definitions;
|
|
344
|
-
|
|
345
|
-
try { authToken = checkHeaders(request.headers); }
|
|
346
|
-
catch (err) {
|
|
347
|
-
next(err);
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
const token = jwt.decode(authToken);
|
|
351
|
-
|
|
352
|
-
if (!token) {
|
|
353
|
-
next(new Error('invalid token'));
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
if (token.subType === ADMIN || token.subType === SUB_ADMIN) {
|
|
357
|
-
next(new Error('invalid token: wrong type'));
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
try { jwt.verify(authToken, keys(flow), jwtOptions(flow)); }
|
|
361
|
-
catch (err) {
|
|
362
|
-
if (flow !== IMPLICIT && generic.previousKey) { // backward compatibility
|
|
363
|
-
try { jwt.verify(authToken, generic.previousKey, jwtOptions(flow)); }
|
|
364
|
-
catch (secondErr) {
|
|
365
|
-
next(secondErr);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
next(err);
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
let scopeResult;
|
|
375
|
-
|
|
376
|
-
try { scopeResult = checkScopes(token.scope, scopes, request.swagger); }
|
|
377
|
-
catch (errScopes) {
|
|
378
|
-
next(errScopes);
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
if (scopeResult.onBehalf) request[TOKEN_PARAMS.onBehalf] = true;
|
|
382
|
-
request[TOKEN_PARAMS.claims] = scopeResult.claims;
|
|
383
|
-
if (definitions.flow === IMPLICIT) {
|
|
384
|
-
if (token.sub) request[TOKEN_PARAMS.userId] = token.sub;
|
|
385
|
-
if (token.azp) request[TOKEN_PARAMS.appId] = token.azp;
|
|
386
|
-
if (token.may_act && token.may_act.sub) {
|
|
387
|
-
request[TOKEN_PARAMS.onBehalfId] = token.sub;
|
|
388
|
-
request[TOKEN_PARAMS.userId] = token.may_act.sub;
|
|
389
|
-
}
|
|
390
|
-
request.tokenType = USER;
|
|
391
|
-
next(null);
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
// server to server or admin flow (application)
|
|
395
|
-
if (token.sub) request[TOKEN_PARAMS.clientId] = token.sub;
|
|
396
|
-
if (token.subType) request[TOKEN_PARAMS.tokenType] = token.subType;
|
|
397
|
-
if (token.cust) request[TOKEN_PARAMS.customer] = token.cust;
|
|
398
|
-
if (token.type === CLUSTER) request[TOKEN_PARAMS.cluster] = true;
|
|
399
|
-
next(null);
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Validate the request by inspecting the token. To be used for `admin` token.
|
|
404
|
-
*
|
|
405
|
-
* @function apiTokenAdminSecurityHelper
|
|
406
|
-
* @category callback
|
|
407
|
-
* @param {object} request - The request with a token in the header.
|
|
408
|
-
* @param {object} definitions - Swagger security definitions to compare with.
|
|
409
|
-
* @param {string[]} scopes - List of swagger scopes associated whith the requested endpoint.
|
|
410
|
-
* @param {requestCallback} next - The callback that handles the response.
|
|
411
|
-
*
|
|
412
|
-
* The validation adds the following properties to the request: 'claims', clientId', tokenType', 'customer'.
|
|
413
|
-
*
|
|
414
|
-
* The claims array contains the claims that are included on the scope of the recieved token. It there is no claims in the scope the claims property in request is an emtpy array.
|
|
415
|
-
* The scope must have the followimg format: `<action>:<resourceName>::<claims>`` where claims is a set of claims separatedby `,`. The is an exception for onBelf scope where the format is `onbBehalf:<action><resourceName>::<claims>`.
|
|
416
|
-
* The claims will be validated looking at the definitions property of the swagger file, by looking at at the top level properties of a definition named: `<resourceName>Claims`.
|
|
417
|
-
* If there is multiple scopes to use, the claims array will contain a concatenation of all the claims if present.
|
|
418
|
-
*/
|
|
419
|
-
const apiTokenAdminSecurityHelper = (request, definitions, scopes, next) => {
|
|
420
|
-
let authToken;
|
|
421
|
-
const { flow } = definitions;
|
|
422
|
-
|
|
423
|
-
try { authToken = checkHeaders(request.headers); }
|
|
424
|
-
catch (err) {
|
|
425
|
-
next(err);
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const token = jwt.decode(authToken);
|
|
430
|
-
|
|
431
|
-
if (!token) {
|
|
432
|
-
next(new Error('invalid token'));
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
if (token.subType !== ADMIN && token.subType !== SUB_ADMIN) {
|
|
436
|
-
next(new Error('invalid token: wrong type'));
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
if (token.subType === SUB_ADMIN) {
|
|
440
|
-
if (!token.cust) {
|
|
441
|
-
next(new Error('invalid token: no customer'));
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
else if (token.sub !== `${config.security.admin.externalId}${CLIENT}`) {
|
|
446
|
-
next(new Error(`jwt subject invalid: ${token.sub}`));
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
try {
|
|
450
|
-
jwt.verify(authToken, keys(flow), jwtOptions(flow));
|
|
451
|
-
}
|
|
452
|
-
catch (err) {
|
|
453
|
-
if (generic.previousKey) { // backward compatibility
|
|
454
|
-
try { jwt.verify(authToken, generic.previousKey, jwtOptions(flow)); }
|
|
455
|
-
catch (secondErr) {
|
|
456
|
-
next(secondErr);
|
|
457
|
-
return;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
next(err);
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
let scopeResult;
|
|
466
|
-
|
|
467
|
-
try { scopeResult = checkScopes(token.scope, scopes, request.swagger); }
|
|
468
|
-
catch (errScopes) {
|
|
469
|
-
next(errScopes);
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
request[TOKEN_PARAMS.claims] = scopeResult.claims;
|
|
473
|
-
if (token.subType) request[TOKEN_PARAMS.tokenType] = token.subType;
|
|
474
|
-
if (token.sub) request[TOKEN_PARAMS.clientId] = token.sub;
|
|
475
|
-
if (token.cust) request[TOKEN_PARAMS.customer] = token.cust;
|
|
476
|
-
next(null);
|
|
477
|
-
};
|
|
478
|
-
|
|
479
185
|
/**
|
|
480
186
|
* Make an authProfile request to mID.
|
|
481
187
|
*
|
|
@@ -515,9 +221,6 @@ module.exports = (config) => {
|
|
|
515
221
|
|
|
516
222
|
return {
|
|
517
223
|
rpAuth,
|
|
518
|
-
apiKeySecurityHelper,
|
|
519
|
-
apiTokenSecurityHelper,
|
|
520
|
-
apiTokenAdminSecurityHelper,
|
|
521
224
|
authProfile,
|
|
522
225
|
};
|
|
523
226
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mimik/oauth-helper",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Oauth helper for mimik microservices",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -29,25 +29,23 @@
|
|
|
29
29
|
"url": "https://bitbucket.org/mimiktech/oauth-helper"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@mimik/request-retry": "^
|
|
33
|
-
"@mimik/response-helper": "^
|
|
34
|
-
"@mimik/sumologic-winston-logger": "^1.6.
|
|
35
|
-
"@mimik/swagger-helper": "^3.0.3",
|
|
32
|
+
"@mimik/request-retry": "^3.0.1",
|
|
33
|
+
"@mimik/response-helper": "^3.0.1",
|
|
34
|
+
"@mimik/sumologic-winston-logger": "^1.6.20",
|
|
36
35
|
"bluebird": "3.7.2",
|
|
37
|
-
"jsonwebtoken": "9.0.
|
|
38
|
-
"lodash": "4.17.21"
|
|
36
|
+
"jsonwebtoken": "9.0.2"
|
|
39
37
|
},
|
|
40
38
|
"devDependencies": {
|
|
41
|
-
"@mimik/eslint-plugin-dependencies": "^2.4.
|
|
42
|
-
"@mimik/eslint-plugin-document-env": "^1.0.
|
|
43
|
-
"@mimik/request-helper": "^1.7.
|
|
39
|
+
"@mimik/eslint-plugin-dependencies": "^2.4.6",
|
|
40
|
+
"@mimik/eslint-plugin-document-env": "^1.0.6",
|
|
41
|
+
"@mimik/request-helper": "^1.7.10",
|
|
44
42
|
"body-parser": "1.20.2",
|
|
45
|
-
"chai": "4.3.
|
|
46
|
-
"eslint": "8.
|
|
43
|
+
"chai": "4.3.10",
|
|
44
|
+
"eslint": "8.55.0",
|
|
47
45
|
"eslint-config-airbnb": "19.0.4",
|
|
48
|
-
"eslint-plugin-import": "2.
|
|
49
|
-
"eslint-plugin-jsx-a11y": "6.
|
|
50
|
-
"eslint-plugin-react": "7.
|
|
46
|
+
"eslint-plugin-import": "2.29.0",
|
|
47
|
+
"eslint-plugin-jsx-a11y": "6.8.0",
|
|
48
|
+
"eslint-plugin-react": "7.33.2",
|
|
51
49
|
"eslint-plugin-react-hooks": "4.6.0",
|
|
52
50
|
"express": "4.18.2",
|
|
53
51
|
"husky": "8.0.3",
|
package/test/oauthHelper.spec.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const jwt = require('jsonwebtoken');
|
|
2
1
|
const chai = require('chai');
|
|
3
2
|
|
|
4
3
|
require('./testEnv');
|
|
@@ -9,395 +8,24 @@ const { rpRetry } = require('@mimik/request-retry');
|
|
|
9
8
|
const oauthHelper = require('../index');
|
|
10
9
|
const {
|
|
11
10
|
config,
|
|
12
|
-
payload,
|
|
13
|
-
options,
|
|
14
|
-
definition,
|
|
15
|
-
scope,
|
|
16
11
|
} = require('./testConfig');
|
|
17
12
|
const mockServer = require('./serversMock');
|
|
18
13
|
|
|
19
14
|
const { expect } = chai;
|
|
20
15
|
chai.should();
|
|
21
16
|
|
|
22
|
-
const USER = 'user';
|
|
23
|
-
const UNKNOWN = 'unknown';
|
|
24
|
-
|
|
25
17
|
const correlationId = getCorrelationId('--test-OauthHelper--');
|
|
26
|
-
const oauthImplImplicit = oauthHelper(config.implImplicit);
|
|
27
18
|
// const oauthImplNoGeneric = oauthHelper(config.implNoGeneric);
|
|
28
19
|
// const oauthImplGeneric = oauthHelper(config.implGeneric);
|
|
29
20
|
const oauthAppGeneric = oauthHelper(config.appGeneric);
|
|
30
|
-
const oauthAppNoGeneric = oauthHelper(config.appNoGeneric);
|
|
31
21
|
const oauthAppUnknownIssuer = oauthHelper(config.appUnknownIssuer);
|
|
32
22
|
// const oauthAppExpiredToken = oauthHelper(config.appExpiredToken);
|
|
33
23
|
const oauthAppExpiredTokenAndFail = oauthHelper(config.appExpiredTokenAndFail);
|
|
34
24
|
|
|
35
|
-
const tokenImpl = jwt.sign(payload.regular, config.implImplicit.security.implicit.key, options.implImplicit);
|
|
36
|
-
const tokenImplNoScope = jwt.sign(payload.noScope, config.implImplicit.security.implicit.key, options.implImplicit);
|
|
37
|
-
const tokenImplOnBehalf = jwt.sign(payload.onBehalf, config.implImplicit.security.implicit.key, options.implImplicit);
|
|
38
|
-
const tokenImplExchange = jwt.sign(payload.exchange, config.implImplicit.security.implicit.key, options.implImplicit);
|
|
39
|
-
const tokenApp = jwt.sign(payload.regular, config.appGeneric.security.generic.key, options.appGeneric);
|
|
40
|
-
const adminTokenApp = jwt.sign(payload.admin, config.appGeneric.security.generic.key, options.adminApp);
|
|
41
|
-
const adminTokenAppWrongId = jwt.sign(payload.admin, config.appGeneric.security.generic.key, options.adminAppWrongId);
|
|
42
|
-
const adminTokenAppNoScope = jwt.sign(payload.adminNoScope, config.appGeneric.security.generic.key, options.adminApp);
|
|
43
|
-
const subAdminTokenApp = jwt.sign(payload.subAdmin, config.appGeneric.security.generic.key, options.adminApp);
|
|
44
|
-
const subAdminTokenAppNoCustomer = jwt.sign(payload.subAdminNoCustomer, config.appGeneric.security.generic.key, options.adminApp);
|
|
45
|
-
const tokenWithClaims = jwt.sign(payload.withClaims, config.implImplicit.security.implicit.key, options.implImplicit);
|
|
46
|
-
|
|
47
25
|
describe('OauthHelper Unit Tests', () => {
|
|
48
26
|
before(() => {
|
|
49
27
|
mockServer.listen();
|
|
50
28
|
});
|
|
51
|
-
describe('apiKeySecurityHelper(request, definitions, scopes, next)', () => {
|
|
52
|
-
it('no header should generate an error invalid API key', () => {
|
|
53
|
-
oauthAppGeneric.apiKeySecurityHelper({}, definition.apiKey, UNKNOWN, (err) => {
|
|
54
|
-
if (!err) throw new Error('cannot be successful');
|
|
55
|
-
expect(err.message).to.include('invalid API key');
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
it('header with no name should generate an error invalid API key', () => {
|
|
59
|
-
oauthAppGeneric.apiKeySecurityHelper({ headers: {} }, definition.apiKey, UNKNOWN, (err) => {
|
|
60
|
-
if (!err) throw new Error('cannot be successful');
|
|
61
|
-
expect(err.message).to.include('invalid API key');
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
it('header with wrong name should generate an error invalid API key', () => {
|
|
65
|
-
oauthAppGeneric.apiKeySecurityHelper({ headers: { authorization: 'Unknown 1234' } }, definition.apiKey, UNKNOWN, (err) => {
|
|
66
|
-
if (!err) throw new Error('cannot be successful');
|
|
67
|
-
expect(err.message).to.include('invalid API key');
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
it('should generate an error because of invalid API key', () => {
|
|
71
|
-
oauthAppGeneric.apiKeySecurityHelper({ headers: { api_key: UNKNOWN } }, definition.apiKey, UNKNOWN, (err) => {
|
|
72
|
-
if (!err) throw new Error('cannot be successful');
|
|
73
|
-
expect(err.message).to.include('invalid API key');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
it('should be successful with request update', () => {
|
|
77
|
-
const request = {
|
|
78
|
-
headers: {
|
|
79
|
-
api_key: '12345',
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
oauthAppGeneric.apiKeySecurityHelper(request, definition.apiKey, request.headers.api_key, (err) => {
|
|
83
|
-
if (err) throw err;
|
|
84
|
-
expect(request.apiKey).to.equal('12345');
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
describe('apiTokenSecurityHelper(request, definitions, scopes, next)', () => {
|
|
89
|
-
it('should generate an error missing header', () => {
|
|
90
|
-
oauthImplImplicit.apiTokenSecurityHelper({}, definition.implicit, scope.scopes, (err) => {
|
|
91
|
-
if (!err) throw new Error('cannot be successful');
|
|
92
|
-
expect(err.message).to.equal('missing header');
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
it('should generate an error missing authorization header', () => {
|
|
96
|
-
oauthImplImplicit.apiTokenSecurityHelper({ headers: {} }, definition.implicit, scope.scopes, (err) => {
|
|
97
|
-
if (!err) throw new Error('cannot be successful');
|
|
98
|
-
expect(err.message).to.equal('missing authorization header');
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
it('should generate an error duplicated authorization header', () => {
|
|
102
|
-
oauthImplImplicit.apiTokenSecurityHelper({ headers: { authorization: '1234', Authorization: '4321' } }, definition.implicit, scope.scopes, (err) => {
|
|
103
|
-
if (!err) throw new Error('cannot be successful');
|
|
104
|
-
expect(err.message).to.equal('duplicated authorization header');
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
it('should generate an error authorization type incorrect', () => {
|
|
108
|
-
oauthImplImplicit.apiTokenSecurityHelper({ headers: { authorization: 'Unknown 1234' } }, definition.implicit, scope.scopes, (err) => {
|
|
109
|
-
if (!err) throw new Error('cannot be successful');
|
|
110
|
-
expect(err.message).to.equal('authorization type incorrect: Unknown');
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
it('should generate an error invalid token', () => {
|
|
114
|
-
oauthImplImplicit.apiTokenSecurityHelper({ headers: { authorization: 'Bearer 1234' } }, definition.implicit, scope.scopes, (err) => {
|
|
115
|
-
if (!err) throw new Error('cannot be successful');
|
|
116
|
-
expect(err.message).to.equal('invalid token');
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
it('should generate an error invalid token: wrong type', () => {
|
|
120
|
-
oauthImplImplicit.apiTokenSecurityHelper({ headers: { authorization: `Bearer ${adminTokenApp}` } }, definition.implicit, scope.scopes, (err) => {
|
|
121
|
-
if (!err) throw new Error('cannot be successful');
|
|
122
|
-
expect(err.message).to.equal('invalid token: wrong type');
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
it('should generate an error invalid signature', () => {
|
|
126
|
-
oauthImplImplicit.apiTokenSecurityHelper({ headers: { authorization: `Bearer ${tokenApp}` } }, definition.implicit, scope.scopes, (err) => {
|
|
127
|
-
if (!err) throw new Error('cannot be successful');
|
|
128
|
-
expect(err.message).to.equal('invalid signature');
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
it('should generate an error no scope in authorization token', () => {
|
|
132
|
-
oauthImplImplicit.apiTokenSecurityHelper({ headers: { authorization: `Bearer ${tokenImplNoScope}` } }, definition.implicit, scope.scopes, (err) => {
|
|
133
|
-
if (!err) throw new Error('cannot be successful');
|
|
134
|
-
expect(err.message).to.equal('no scope in authorization token');
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
it('should generate an error incorrect scopes', () => {
|
|
138
|
-
oauthImplImplicit.apiTokenSecurityHelper({ headers: { authorization: `Bearer ${tokenImpl}` } }, definition.implicit, scope.otherScopes, (err) => {
|
|
139
|
-
if (!err) throw new Error('cannot be successful');
|
|
140
|
-
expect(err.message).to.equal(`incorrect scopes: ${scope.regular}`);
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
it('should generate an error missing definition: no definition', () => {
|
|
144
|
-
oauthImplImplicit.apiTokenSecurityHelper({ headers: { authorization: `Bearer ${tokenWithClaims}` } }, definition.implicit, scope.forClaims, (err) => {
|
|
145
|
-
if (!err) throw new Error('cannot be successful');
|
|
146
|
-
expect(err.message).to.equal('missing userClaims definition: no definitions');
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
it('should generate an error missing definition', () => {
|
|
150
|
-
oauthImplImplicit.apiTokenSecurityHelper({
|
|
151
|
-
headers: { authorization: `Bearer ${tokenWithClaims}` },
|
|
152
|
-
swagger: {
|
|
153
|
-
swaggerObject: {
|
|
154
|
-
definitions: {
|
|
155
|
-
testClaims: {
|
|
156
|
-
test: 'test',
|
|
157
|
-
},
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
}, definition.implicit, scope.forClaims, (err) => {
|
|
162
|
-
if (!err) throw new Error('cannot be successful');
|
|
163
|
-
expect(err.message).to.equal('missing userClaims definition');
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
it('should generate an error incorrect claims included', () => {
|
|
167
|
-
oauthImplImplicit.apiTokenSecurityHelper({
|
|
168
|
-
headers: { authorization: `Bearer ${tokenWithClaims}` },
|
|
169
|
-
swagger: {
|
|
170
|
-
swaggerObject: {
|
|
171
|
-
definitions: {
|
|
172
|
-
userClaims: {
|
|
173
|
-
test: 'test',
|
|
174
|
-
},
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
}, definition.implicit, scope.forClaims, (err) => {
|
|
179
|
-
if (!err) throw new Error('cannot be successful');
|
|
180
|
-
expect(err.message).to.equal('incorrect claims included: lastName,firstName');
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
it('should generate an error incorrect claims included', () => {
|
|
184
|
-
oauthImplImplicit.apiTokenSecurityHelper({
|
|
185
|
-
headers: { authorization: `Bearer ${tokenWithClaims}` },
|
|
186
|
-
swagger: {
|
|
187
|
-
swaggerObject: {
|
|
188
|
-
definitions: {
|
|
189
|
-
userClaims: {
|
|
190
|
-
lastName: 'test',
|
|
191
|
-
test: 'test',
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
}, definition.implicit, scope.forClaims, (err) => {
|
|
197
|
-
if (!err) throw new Error('cannot be successful');
|
|
198
|
-
expect(err.message).to.equal('incorrect claims included: firstName');
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
it('should return a token and request contains claims', () => {
|
|
202
|
-
const request = {
|
|
203
|
-
headers: { authorization: `Bearer ${tokenWithClaims}` },
|
|
204
|
-
swagger: {
|
|
205
|
-
swaggerObject: {
|
|
206
|
-
definitions: {
|
|
207
|
-
userClaims: {
|
|
208
|
-
lastName: 'test',
|
|
209
|
-
firstName: 'test',
|
|
210
|
-
test: 'test',
|
|
211
|
-
},
|
|
212
|
-
},
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
};
|
|
216
|
-
oauthImplImplicit.apiTokenSecurityHelper(request, definition.implicit, scope.forClaims, (err) => {
|
|
217
|
-
if (err) throw err;
|
|
218
|
-
expect(request.claims).to.deep.equal(['lastName', 'firstName']);
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
it('should return a token and request contains multiple claims', () => {
|
|
222
|
-
const request = {
|
|
223
|
-
headers: { authorization: `Bearer ${tokenWithClaims}` },
|
|
224
|
-
swagger: {
|
|
225
|
-
swaggerObject: {
|
|
226
|
-
definitions: {
|
|
227
|
-
userClaims: {
|
|
228
|
-
lastName: 'test',
|
|
229
|
-
firstName: 'test',
|
|
230
|
-
test: 'test',
|
|
231
|
-
},
|
|
232
|
-
usersClaims: {
|
|
233
|
-
email: 'test',
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
},
|
|
237
|
-
},
|
|
238
|
-
};
|
|
239
|
-
oauthImplImplicit.apiTokenSecurityHelper(request, definition.implicit, scope.forClaimsMultiple, (err) => {
|
|
240
|
-
if (err) throw err;
|
|
241
|
-
expect(request.claims).to.deep.equal(['lastName', 'firstName', 'email']);
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
it('should have update request implicit with authorization', () => {
|
|
245
|
-
const request = {
|
|
246
|
-
headers: {
|
|
247
|
-
authorization: `Bearer ${tokenImpl}`,
|
|
248
|
-
},
|
|
249
|
-
};
|
|
250
|
-
oauthImplImplicit.apiTokenSecurityHelper(request, definition.implicit, scope.scopes, (err) => {
|
|
251
|
-
if (err) throw err;
|
|
252
|
-
expect(request.userId).to.equal(options.implImplicit.subject);
|
|
253
|
-
expect(request.tokenType).to.equal(USER);
|
|
254
|
-
expect(request.onBehalf).to.equal(undefined);
|
|
255
|
-
expect(request.appId).to.equal(payload.regular.azp);
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
it('should have update request implicit with Authorization', () => {
|
|
259
|
-
const request = {
|
|
260
|
-
headers: {
|
|
261
|
-
Authorization: `Bearer ${tokenImpl}`,
|
|
262
|
-
},
|
|
263
|
-
};
|
|
264
|
-
oauthImplImplicit.apiTokenSecurityHelper(request, definition.implicit, scope.scopes, (err) => {
|
|
265
|
-
if (err) throw err;
|
|
266
|
-
expect(request.userId).to.equal(options.implImplicit.subject);
|
|
267
|
-
expect(request.tokenType).to.equal(USER);
|
|
268
|
-
expect(request.onBehalf).to.equal(undefined);
|
|
269
|
-
expect(request.appId).to.equal(payload.regular.azp);
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
it('should have update request with onBehalf', () => {
|
|
273
|
-
const request = {
|
|
274
|
-
headers: {
|
|
275
|
-
authorization: `Bearer ${tokenImplOnBehalf}`,
|
|
276
|
-
},
|
|
277
|
-
};
|
|
278
|
-
oauthImplImplicit.apiTokenSecurityHelper(request, definition.implicit, scope.onBehalfScopes, (err) => {
|
|
279
|
-
if (err) throw err;
|
|
280
|
-
expect(request.userId).to.equal(options.implImplicit.subject);
|
|
281
|
-
expect(request.tokenType).to.equal(USER);
|
|
282
|
-
expect(request.onBehalf).to.equal(true);
|
|
283
|
-
expect(request.appId).to.equal(undefined);
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
it('should have update request with exchange', () => {
|
|
287
|
-
const request = {
|
|
288
|
-
headers: {
|
|
289
|
-
authorization: `Bearer ${tokenImplExchange}`,
|
|
290
|
-
},
|
|
291
|
-
};
|
|
292
|
-
oauthImplImplicit.apiTokenSecurityHelper(request, definition.implicit, scope.scopes, (err) => {
|
|
293
|
-
if (err) throw err;
|
|
294
|
-
expect(request.userId).to.equal(payload.exchange.may_act.sub);
|
|
295
|
-
expect(request.onBehalfId).to.equal(options.implImplicit.subject);
|
|
296
|
-
expect(request.tokenType).to.equal(USER);
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
it('should have update request application', () => {
|
|
300
|
-
const request = {
|
|
301
|
-
headers: {
|
|
302
|
-
authorization: `Bearer ${tokenApp}`,
|
|
303
|
-
},
|
|
304
|
-
};
|
|
305
|
-
oauthAppGeneric.apiTokenSecurityHelper(request, definition.application, scope.scopes, (err) => {
|
|
306
|
-
if (err) throw err;
|
|
307
|
-
expect(request.clientId).to.equal(options.appGeneric.subject);
|
|
308
|
-
expect(request.customer).to.equal(payload.regular.cust);
|
|
309
|
-
expect(request.tokenType).to.equal(payload.regular.subType);
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
describe('apiTokenAdminSecurityHelper(request, definitions, scopes, next)', () => {
|
|
314
|
-
it('should generate an error missing header', () => {
|
|
315
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper({}, definition.application, scope.scopes, (err) => {
|
|
316
|
-
if (!err) throw new Error('cannot be successful');
|
|
317
|
-
expect(err.message).to.equal('missing header');
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
it('should generate an error missing authorization header', () => {
|
|
321
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper({ headers: {} }, definition.application, scope.scopes, (err) => {
|
|
322
|
-
if (!err) throw new Error('cannot be successful');
|
|
323
|
-
expect(err.message).to.equal('missing authorization header');
|
|
324
|
-
});
|
|
325
|
-
});
|
|
326
|
-
it('should generate an error authorization type incorrect', () => {
|
|
327
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper({ headers: { authorization: 'Unknown 1234' } }, definition.application, scope.scopes, (err) => {
|
|
328
|
-
if (!err) throw new Error('cannot be successful');
|
|
329
|
-
expect(err.message).to.equal('authorization type incorrect: Unknown');
|
|
330
|
-
});
|
|
331
|
-
});
|
|
332
|
-
it('should generate an error invalid token', () => {
|
|
333
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper({ headers: { authorization: 'Bearer 1234' } }, definition.application, scope.scopes, (err) => {
|
|
334
|
-
if (!err) throw new Error('cannot be successful');
|
|
335
|
-
expect(err.message).to.equal('invalid token');
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
it('should generate an error invalid token: wrong type', () => {
|
|
339
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper({ headers: { authorization: `Bearer ${tokenApp}` } }, definition.application, scope.scopes, (err) => {
|
|
340
|
-
if (!err) throw new Error('cannot be successful');
|
|
341
|
-
expect(err.message).to.equal('invalid token: wrong type');
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
it('should generate an error invalid signature', () => {
|
|
345
|
-
oauthAppNoGeneric.apiTokenAdminSecurityHelper({ headers: { authorization: `Bearer ${adminTokenApp}` } }, definition.application, scope.scopes, (err) => {
|
|
346
|
-
if (!err) throw new Error('cannot be successful');
|
|
347
|
-
expect(err.message).to.equal('invalid signature');
|
|
348
|
-
});
|
|
349
|
-
});
|
|
350
|
-
it('should generate an error no scope in authorization token', () => {
|
|
351
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper({ headers: { authorization: `Bearer ${adminTokenAppNoScope}` } }, definition.application, scope.scopes, (err) => {
|
|
352
|
-
if (!err) throw new Error('cannot be successful');
|
|
353
|
-
expect(err.message).to.equal('no scope in authorization token');
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
it('should generate an error incorrect scopes', () => {
|
|
357
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper({ headers: { authorization: `Bearer ${adminTokenApp}` } }, definition.application, scope.otherScopes, (err) => {
|
|
358
|
-
if (!err) throw new Error('cannot be successful');
|
|
359
|
-
expect(err.message).to.equal(`incorrect scopes: ${scope.regular}`);
|
|
360
|
-
});
|
|
361
|
-
});
|
|
362
|
-
it('should generate an error jwt subject invalid', () => {
|
|
363
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper({ headers: { authorization: `Bearer ${adminTokenAppWrongId}` } }, definition.application, scope.scopes, (err) => {
|
|
364
|
-
if (!err) throw new Error('cannot be successful');
|
|
365
|
-
expect(err.message).to.equal(`jwt subject invalid: ${options.adminAppWrongId.subject}`);
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
it('should generate an error invalid token: no customer', () => {
|
|
369
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper({ headers: { authorization: `Bearer ${subAdminTokenAppNoCustomer}` } }, definition.application, scope.scopes, (err) => {
|
|
370
|
-
if (!err) throw new Error('cannot be successful');
|
|
371
|
-
expect(err.message).to.equal('invalid token: no customer');
|
|
372
|
-
});
|
|
373
|
-
});
|
|
374
|
-
it('should have update request admin', () => {
|
|
375
|
-
const request = {
|
|
376
|
-
headers: {
|
|
377
|
-
authorization: `Bearer ${adminTokenApp}`,
|
|
378
|
-
},
|
|
379
|
-
};
|
|
380
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper(request, definition.application, scope.scopes, (err) => {
|
|
381
|
-
if (err) throw err;
|
|
382
|
-
expect(request.clientId).to.equal(options.adminApp.subject);
|
|
383
|
-
expect(request.tokenType).to.equal(payload.admin.subType);
|
|
384
|
-
expect(request.customer).to.equal(payload.admin.cust);
|
|
385
|
-
});
|
|
386
|
-
});
|
|
387
|
-
it('should have update request subAdmin', () => {
|
|
388
|
-
const request = {
|
|
389
|
-
headers: {
|
|
390
|
-
authorization: `Bearer ${subAdminTokenApp}`,
|
|
391
|
-
},
|
|
392
|
-
};
|
|
393
|
-
oauthAppGeneric.apiTokenAdminSecurityHelper(request, definition.application, scope.scopes, (err) => {
|
|
394
|
-
if (err) throw err;
|
|
395
|
-
expect(request.clientId).to.equal(options.adminApp.subject);
|
|
396
|
-
expect(request.tokenType).to.equal(payload.subAdmin.subType);
|
|
397
|
-
expect(request.customer).to.equal(payload.subAdmin.cust);
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
});
|
|
401
29
|
describe('rpAuth(type, options)', function test() {
|
|
402
30
|
this.timeout(200000);
|
|
403
31
|
const requestOptions = {
|
package/test/testConfig.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
const NO_GENERIC = 'noGeneric';
|
|
2
|
-
const APPLICATION = 'application';
|
|
3
|
-
const IMPLICIT = 'implicit';
|
|
4
|
-
const SUB_ADMIN = 'subAdmin';
|
|
5
|
-
const ADMIN = 'admin';
|
|
6
|
-
const CLIENT = '@clients';
|
|
7
|
-
const API_KEY = 'api_key';
|
|
8
|
-
const HEADER = 'header';
|
|
9
2
|
|
|
10
3
|
const config = {
|
|
11
4
|
implImplicit: {
|
|
@@ -213,111 +206,7 @@ const config = {
|
|
|
213
206
|
},
|
|
214
207
|
},
|
|
215
208
|
};
|
|
216
|
-
const scope = {
|
|
217
|
-
regular: 'test:1 test:2 test:3',
|
|
218
|
-
onBehalf: 'test:1 onBehalf:1',
|
|
219
|
-
withClaims: 'get:user::lastName,firstName get:users::email',
|
|
220
|
-
scopes: ['test:1', 'test:2', 'test:3'],
|
|
221
|
-
otherScopes: ['test:4', 'test:5'],
|
|
222
|
-
onBehalfScopes: ['onBehalf:1', 'test:6'],
|
|
223
|
-
forClaims: ['get:user'],
|
|
224
|
-
forClaimsMultiple: ['get:user', 'get:users'],
|
|
225
|
-
};
|
|
226
|
-
const cust = 'testCustomer';
|
|
227
|
-
const subType = 'testType';
|
|
228
|
-
const azp = 'applicationId';
|
|
229
|
-
const definition = {
|
|
230
|
-
implicit: {
|
|
231
|
-
flow: IMPLICIT,
|
|
232
|
-
},
|
|
233
|
-
application: {
|
|
234
|
-
flow: APPLICATION,
|
|
235
|
-
},
|
|
236
|
-
apiKey: {
|
|
237
|
-
name: API_KEY,
|
|
238
|
-
in: HEADER,
|
|
239
|
-
},
|
|
240
|
-
};
|
|
241
|
-
const payload = {
|
|
242
|
-
regular: {
|
|
243
|
-
scope: scope.regular,
|
|
244
|
-
subType,
|
|
245
|
-
azp,
|
|
246
|
-
cust,
|
|
247
|
-
},
|
|
248
|
-
noScope: {
|
|
249
|
-
subType,
|
|
250
|
-
cust,
|
|
251
|
-
},
|
|
252
|
-
onBehalf: {
|
|
253
|
-
scope: scope.onBehalf,
|
|
254
|
-
subType,
|
|
255
|
-
cust,
|
|
256
|
-
},
|
|
257
|
-
withClaims: {
|
|
258
|
-
scope: scope.withClaims,
|
|
259
|
-
subType,
|
|
260
|
-
azp,
|
|
261
|
-
cust,
|
|
262
|
-
},
|
|
263
|
-
exchange: {
|
|
264
|
-
scope: scope.regular,
|
|
265
|
-
subType,
|
|
266
|
-
cust,
|
|
267
|
-
may_act: {
|
|
268
|
-
sub: 'managerId',
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
admin: {
|
|
272
|
-
scope: scope.regular,
|
|
273
|
-
subType: ADMIN,
|
|
274
|
-
cust,
|
|
275
|
-
},
|
|
276
|
-
adminNoScope: {
|
|
277
|
-
subType: ADMIN,
|
|
278
|
-
cust,
|
|
279
|
-
},
|
|
280
|
-
subAdmin: {
|
|
281
|
-
scope: scope.regular,
|
|
282
|
-
subType: SUB_ADMIN,
|
|
283
|
-
cust,
|
|
284
|
-
},
|
|
285
|
-
subAdminNoCustomer: {
|
|
286
|
-
scope: scope.regular,
|
|
287
|
-
subType: SUB_ADMIN,
|
|
288
|
-
},
|
|
289
|
-
};
|
|
290
|
-
const options = {
|
|
291
|
-
implImplicit: {
|
|
292
|
-
expiresIn: Date.now() + 100000,
|
|
293
|
-
audience: config.implImplicit.security.implicit.audience,
|
|
294
|
-
issuer: config.implImplicit.security.implicit.issuer,
|
|
295
|
-
subject: 'userId',
|
|
296
|
-
},
|
|
297
|
-
appGeneric: {
|
|
298
|
-
expiresIn: Date.now() + 100000,
|
|
299
|
-
audience: config.appGeneric.security.generic.audience,
|
|
300
|
-
issuer: config.appGeneric.security.server.issuer,
|
|
301
|
-
subject: `${config.appGeneric.server.id}${CLIENT}`,
|
|
302
|
-
},
|
|
303
|
-
adminApp: {
|
|
304
|
-
expiresIn: Date.now() + 100000,
|
|
305
|
-
audience: config.appGeneric.security.generic.audience,
|
|
306
|
-
issuer: config.appGeneric.security.server.issuer,
|
|
307
|
-
subject: `${config.appGeneric.security.admin.externalId}${CLIENT}`,
|
|
308
|
-
},
|
|
309
|
-
adminAppWrongId: {
|
|
310
|
-
expiresIn: Date.now() + 100000,
|
|
311
|
-
audience: config.appGeneric.security.generic.audience,
|
|
312
|
-
issuer: config.appGeneric.security.server.issuer,
|
|
313
|
-
subject: `wrongId${CLIENT}`,
|
|
314
|
-
},
|
|
315
|
-
};
|
|
316
209
|
|
|
317
210
|
module.exports = {
|
|
318
211
|
config,
|
|
319
|
-
payload,
|
|
320
|
-
options,
|
|
321
|
-
definition,
|
|
322
|
-
scope,
|
|
323
212
|
};
|