@mimik/oauth-helper 2.2.0 → 3.0.0

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 CHANGED
@@ -22,13 +22,8 @@ const oauthHelper = require('@mimik/oauth-helper');
22
22
  ```
23
23
 
24
24
  * [oauth-helper](#module_oauth-helper)
25
- * _async_
26
- * [~rpAuth(type, options)](#module_oauth-helper..rpAuth) ⇒ <code>Promise</code>
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.&lt;string&gt;</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.&lt;string&gt;</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.&lt;string&gt;</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.&lt;string&gt;</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 { implicit, server, generic } = config.security;
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": "2.2.0",
3
+ "version": "3.0.0",
4
4
  "description": "Oauth helper for mimik microservices",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -29,13 +29,11 @@
29
29
  "url": "https://bitbucket.org/mimiktech/oauth-helper"
30
30
  },
31
31
  "dependencies": {
32
- "@mimik/request-retry": "^2.1.4",
33
- "@mimik/response-helper": "^2.6.3",
32
+ "@mimik/request-retry": "^3.0.0",
33
+ "@mimik/response-helper": "^3.0.0",
34
34
  "@mimik/sumologic-winston-logger": "^1.6.15",
35
- "@mimik/swagger-helper": "^3.0.3",
36
35
  "bluebird": "3.7.2",
37
- "jsonwebtoken": "9.0.0",
38
- "lodash": "4.17.21"
36
+ "jsonwebtoken": "9.0.0"
39
37
  },
40
38
  "devDependencies": {
41
39
  "@mimik/eslint-plugin-dependencies": "^2.4.5",
@@ -43,7 +41,7 @@
43
41
  "@mimik/request-helper": "^1.7.8",
44
42
  "body-parser": "1.20.2",
45
43
  "chai": "4.3.7",
46
- "eslint": "8.38.0",
44
+ "eslint": "8.39.0",
47
45
  "eslint-config-airbnb": "19.0.4",
48
46
  "eslint-plugin-import": "2.27.5",
49
47
  "eslint-plugin-jsx-a11y": "6.7.1",
@@ -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 = {
@@ -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
  };