@villedemontreal/jwt-validator 5.7.7
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/LICENSE +21 -0
- package/README.md +313 -0
- package/dist/scripts/index.d.ts +6 -0
- package/dist/scripts/index.js +16 -0
- package/dist/scripts/index.js.map +1 -0
- package/dist/scripts/lint.d.ts +6 -0
- package/dist/scripts/lint.js +18 -0
- package/dist/scripts/lint.js.map +1 -0
- package/dist/scripts/lintFix.d.ts +6 -0
- package/dist/scripts/lintFix.js +21 -0
- package/dist/scripts/lintFix.js.map +1 -0
- package/dist/scripts/showCoverage.d.ts +13 -0
- package/dist/scripts/showCoverage.js +40 -0
- package/dist/scripts/showCoverage.js.map +1 -0
- package/dist/scripts/test.d.ts +13 -0
- package/dist/scripts/test.js +29 -0
- package/dist/scripts/test.js.map +1 -0
- package/dist/scripts/testUnits.d.ts +15 -0
- package/dist/scripts/testUnits.js +95 -0
- package/dist/scripts/testUnits.js.map +1 -0
- package/dist/scripts/watch.d.ts +14 -0
- package/dist/scripts/watch.js +96 -0
- package/dist/scripts/watch.js.map +1 -0
- package/dist/src/config/configs.d.ts +88 -0
- package/dist/src/config/configs.js +123 -0
- package/dist/src/config/configs.js.map +1 -0
- package/dist/src/config/constants.d.ts +56 -0
- package/dist/src/config/constants.js +66 -0
- package/dist/src/config/constants.js.map +1 -0
- package/dist/src/config/init.d.ts +15 -0
- package/dist/src/config/init.js +48 -0
- package/dist/src/config/init.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +32 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/jwtValidator.d.ts +21 -0
- package/dist/src/jwtValidator.js +129 -0
- package/dist/src/jwtValidator.js.map +1 -0
- package/dist/src/jwtValidator.test.d.ts +1 -0
- package/dist/src/jwtValidator.test.js +500 -0
- package/dist/src/jwtValidator.test.js.map +1 -0
- package/dist/src/middleware/jwtMiddleware.d.ts +7 -0
- package/dist/src/middleware/jwtMiddleware.js +27 -0
- package/dist/src/middleware/jwtMiddleware.js.map +1 -0
- package/dist/src/models/customError.d.ts +11 -0
- package/dist/src/models/customError.js +38 -0
- package/dist/src/models/customError.js.map +1 -0
- package/dist/src/models/expressRequest.d.ts +15 -0
- package/dist/src/models/expressRequest.js +17 -0
- package/dist/src/models/expressRequest.js.map +1 -0
- package/dist/src/models/gluuUserType.d.ts +9 -0
- package/dist/src/models/gluuUserType.js +14 -0
- package/dist/src/models/gluuUserType.js.map +1 -0
- package/dist/src/models/jwtPayload.d.ts +30 -0
- package/dist/src/models/jwtPayload.js +19 -0
- package/dist/src/models/jwtPayload.js.map +1 -0
- package/dist/src/models/pagination.d.ts +16 -0
- package/dist/src/models/pagination.js +16 -0
- package/dist/src/models/pagination.js.map +1 -0
- package/dist/src/models/publicKey.d.ts +29 -0
- package/dist/src/models/publicKey.js +13 -0
- package/dist/src/models/publicKey.js.map +1 -0
- package/dist/src/repositories/cachedPublicKeyRepository.d.ts +53 -0
- package/dist/src/repositories/cachedPublicKeyRepository.js +102 -0
- package/dist/src/repositories/cachedPublicKeyRepository.js.map +1 -0
- package/dist/src/repositories/publicKeyRepository.d.ts +19 -0
- package/dist/src/repositories/publicKeyRepository.js +44 -0
- package/dist/src/repositories/publicKeyRepository.js.map +1 -0
- package/dist/src/userValidator.d.ts +30 -0
- package/dist/src/userValidator.js +35 -0
- package/dist/src/userValidator.js.map +1 -0
- package/dist/src/userValidator.test.d.ts +1 -0
- package/dist/src/userValidator.test.js +251 -0
- package/dist/src/userValidator.test.js.map +1 -0
- package/dist/src/utils/jwtMock.d.ts +31 -0
- package/dist/src/utils/jwtMock.js +221 -0
- package/dist/src/utils/jwtMock.js.map +1 -0
- package/dist/src/utils/logger.d.ts +11 -0
- package/dist/src/utils/logger.js +54 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/testingConfigurations.d.ts +7 -0
- package/dist/src/utils/testingConfigurations.js +16 -0
- package/dist/src/utils/testingConfigurations.js.map +1 -0
- package/package.json +82 -0
- package/src/config/configs.ts +145 -0
- package/src/config/constants.ts +83 -0
- package/src/config/init.ts +58 -0
- package/src/index.ts +15 -0
- package/src/jwtValidator.test.ts +607 -0
- package/src/jwtValidator.ts +162 -0
- package/src/middleware/jwtMiddleware.ts +33 -0
- package/src/models/customError.ts +37 -0
- package/src/models/expressRequest.ts +27 -0
- package/src/models/gluuUserType.ts +9 -0
- package/src/models/jwtPayload.ts +58 -0
- package/src/models/pagination.ts +26 -0
- package/src/models/publicKey.ts +33 -0
- package/src/repositories/cachedPublicKeyRepository.ts +121 -0
- package/src/repositories/publicKeyRepository.ts +75 -0
- package/src/userValidator.test.ts +279 -0
- package/src/userValidator.ts +54 -0
- package/src/utils/jwtMock.ts +243 -0
- package/src/utils/logger.ts +60 -0
- package/src/utils/testingConfigurations.ts +12 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jwtValidator = void 0;
|
|
4
|
+
const general_utils_1 = require("@villedemontreal/general-utils");
|
|
5
|
+
const jwt = require("jsonwebtoken");
|
|
6
|
+
const moment = require("moment");
|
|
7
|
+
const constants_1 = require("./config/constants");
|
|
8
|
+
const customError_1 = require("./models/customError");
|
|
9
|
+
const jwtPayload_1 = require("./models/jwtPayload");
|
|
10
|
+
const publicKey_1 = require("./models/publicKey");
|
|
11
|
+
const cachedPublicKeyRepository_1 = require("./repositories/cachedPublicKeyRepository");
|
|
12
|
+
/**
|
|
13
|
+
* JWT Validator
|
|
14
|
+
*/
|
|
15
|
+
class JwtValidator {
|
|
16
|
+
async verifyAuthorizationHeader(header) {
|
|
17
|
+
if (general_utils_1.utils.isBlank(header)) {
|
|
18
|
+
throw (0, customError_1.createInvalidAuthHeaderError)({
|
|
19
|
+
code: constants_1.constants.errors.codes.NULL_VALUE,
|
|
20
|
+
target: 'Authorization header',
|
|
21
|
+
message: 'Empty Authorization header',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const parts = header.trim().split(' ');
|
|
25
|
+
if (parts[0] !== 'Bearer') {
|
|
26
|
+
throw (0, customError_1.createInvalidAuthHeaderError)({
|
|
27
|
+
code: constants_1.constants.errors.codes.INVALID_VALUE,
|
|
28
|
+
target: 'Authorization header',
|
|
29
|
+
message: 'Bad authentication scheme, "Bearer" required',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return await this.verifyToken(parts[1]);
|
|
33
|
+
}
|
|
34
|
+
async verifyToken(token) {
|
|
35
|
+
const payload = this.parseJwt(token);
|
|
36
|
+
const key = await this.getJwtPublicKey(payload);
|
|
37
|
+
this.validateJwtCreationTimestamp(payload, key);
|
|
38
|
+
this.validateJwtExpirationTimestamp(payload, key);
|
|
39
|
+
return this.verifyJwt(token, key.publicKey);
|
|
40
|
+
}
|
|
41
|
+
parseJwt(token) {
|
|
42
|
+
const payload = jwt.decode(token);
|
|
43
|
+
if (!payload) {
|
|
44
|
+
throw (0, customError_1.createInvalidJwtError)({
|
|
45
|
+
code: constants_1.constants.errors.codes.INVALID_VALUE,
|
|
46
|
+
target: 'jwt',
|
|
47
|
+
message: 'jwt malformed',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return payload;
|
|
51
|
+
}
|
|
52
|
+
verifyJwt(token, publicKey) {
|
|
53
|
+
let payload;
|
|
54
|
+
try {
|
|
55
|
+
payload = jwt.verify(token, publicKey);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
throw (0, customError_1.createInvalidJwtError)({
|
|
59
|
+
code: constants_1.constants.errors.codes.INVALID_VALUE,
|
|
60
|
+
target: 'jwt',
|
|
61
|
+
message: err.message,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if ((0, jwtPayload_1.isJWTPayload)(payload)) {
|
|
65
|
+
return payload;
|
|
66
|
+
}
|
|
67
|
+
throw (0, customError_1.createInvalidJwtError)({
|
|
68
|
+
code: constants_1.constants.errors.codes.INVALID_VALUE,
|
|
69
|
+
target: 'jwt',
|
|
70
|
+
message: 'expected a valid JWT payload',
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async getJwtPublicKey(payload) {
|
|
74
|
+
const keyId = payload.keyId;
|
|
75
|
+
if (!keyId || keyId <= 0) {
|
|
76
|
+
throw (0, customError_1.createInvalidJwtError)({
|
|
77
|
+
code: constants_1.constants.errors.codes.INVALID_VALUE,
|
|
78
|
+
target: 'jwt',
|
|
79
|
+
message: 'missing public key ID',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const key = await cachedPublicKeyRepository_1.cachedPublicKeyRepository.getOne(keyId);
|
|
83
|
+
// Check key state
|
|
84
|
+
if (!key || key.state !== publicKey_1.PublicKeyState.ACTIVE) {
|
|
85
|
+
throw (0, customError_1.createInvalidJwtError)({
|
|
86
|
+
code: constants_1.constants.errors.codes.INVALID_VALUE,
|
|
87
|
+
target: 'jwt',
|
|
88
|
+
message: 'this keyId is no longer active',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return key;
|
|
92
|
+
}
|
|
93
|
+
validateJwtCreationTimestamp(payload, key) {
|
|
94
|
+
// Check the jwt was not created before the creation date of the key
|
|
95
|
+
const payloadIat = moment.utc(payload.iat * 1000);
|
|
96
|
+
const keyCreatedAt = moment.utc(key.createdAt);
|
|
97
|
+
if (payloadIat.diff(keyCreatedAt) < 0) {
|
|
98
|
+
throw (0, customError_1.createInvalidJwtError)({
|
|
99
|
+
code: constants_1.constants.errors.codes.INVALID_VALUE,
|
|
100
|
+
target: 'jwt',
|
|
101
|
+
message: "this jwt can't be created before the public key",
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
validateJwtExpirationTimestamp(payload, key) {
|
|
106
|
+
// Check expiration date
|
|
107
|
+
if (key.expiresAt) {
|
|
108
|
+
const keyexpiresAt = moment.utc(key.expiresAt);
|
|
109
|
+
if (moment.utc().diff(keyexpiresAt) > 0) {
|
|
110
|
+
throw (0, customError_1.createInvalidJwtError)({
|
|
111
|
+
code: constants_1.constants.errors.codes.INVALID_VALUE,
|
|
112
|
+
target: 'jwt',
|
|
113
|
+
message: 'this keyId is expired',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// Check the jwt was not created after the expiration date of the key
|
|
117
|
+
const payloadIat = moment.utc(payload.iat * 1000);
|
|
118
|
+
if (payloadIat.diff(keyexpiresAt) > 0) {
|
|
119
|
+
throw (0, customError_1.createInvalidJwtError)({
|
|
120
|
+
code: constants_1.constants.errors.codes.INVALID_VALUE,
|
|
121
|
+
target: 'jwt',
|
|
122
|
+
message: "this jwt can't be created after the expiration of the public key",
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.jwtValidator = new JwtValidator();
|
|
129
|
+
//# sourceMappingURL=jwtValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtValidator.js","sourceRoot":"","sources":["../../src/jwtValidator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const src_1 = require("@villedemontreal/general-utils/dist/src");
|
|
4
|
+
const chai_1 = require("chai");
|
|
5
|
+
const jwt = require("jsonwebtoken");
|
|
6
|
+
const nock = require("nock");
|
|
7
|
+
const validator = require("validator");
|
|
8
|
+
const configs_1 = require("./config/configs");
|
|
9
|
+
const constants_1 = require("./config/constants");
|
|
10
|
+
const jwtValidator_1 = require("./jwtValidator");
|
|
11
|
+
const expressRequest_1 = require("./models/expressRequest");
|
|
12
|
+
const cachedPublicKeyRepository_1 = require("./repositories/cachedPublicKeyRepository");
|
|
13
|
+
const jwtMock_1 = require("./utils/jwtMock");
|
|
14
|
+
const testingConfigurations_1 = require("./utils/testingConfigurations");
|
|
15
|
+
const httpMocks = require('node-mocks-http');
|
|
16
|
+
// ==========================================
|
|
17
|
+
// Set Testing configurations
|
|
18
|
+
// ==========================================
|
|
19
|
+
(0, testingConfigurations_1.setTestingConfigurations)();
|
|
20
|
+
// ==========================================
|
|
21
|
+
// JWT Validator
|
|
22
|
+
// ==========================================
|
|
23
|
+
let date;
|
|
24
|
+
let publicKeys;
|
|
25
|
+
function createPathRegex() {
|
|
26
|
+
const regExpEscape = (s) => {
|
|
27
|
+
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
28
|
+
};
|
|
29
|
+
return new RegExp(`${regExpEscape(configs_1.configs.getEndpoint())}(.*)`);
|
|
30
|
+
}
|
|
31
|
+
before('JWT Validator - init app & get jwt public key', async () => {
|
|
32
|
+
nock.cleanAll();
|
|
33
|
+
// Use mock keys
|
|
34
|
+
await jwtMock_1.jwtMock.mockPublicKeys();
|
|
35
|
+
publicKeys = await cachedPublicKeyRepository_1.cachedPublicKeyRepository.getAll();
|
|
36
|
+
chai_1.assert.match(publicKeys[1].publicKey, /^-----BEGIN PUBLIC KEY-----\n/m);
|
|
37
|
+
chai_1.assert.match(publicKeys[1].publicKey, /^-----BEGIN PUBLIC KEY-----\n/m);
|
|
38
|
+
chai_1.assert.match(publicKeys[1].publicKey, /\n-----END PUBLIC KEY-----$/m);
|
|
39
|
+
const key = publicKeys[1].publicKey
|
|
40
|
+
.replace(/^-----BEGIN PUBLIC KEY-----\n/m, '')
|
|
41
|
+
.replace(/\n-----END PUBLIC KEY-----$/m, '')
|
|
42
|
+
.split('\n')
|
|
43
|
+
.join('');
|
|
44
|
+
chai_1.assert.isTrue(validator.default.isBase64(key));
|
|
45
|
+
});
|
|
46
|
+
it('JWT Validator - verifyHeader - should reject null header', async () => {
|
|
47
|
+
const response = await jwtValidator_1.jwtValidator.verifyAuthorizationHeader(null).catch((err) => {
|
|
48
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_AUTHORIZATION_HEADER);
|
|
49
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
50
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid Authorization header');
|
|
51
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.NULL_VALUE);
|
|
52
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'Authorization header');
|
|
53
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'Empty Authorization header');
|
|
54
|
+
});
|
|
55
|
+
chai_1.assert.isUndefined(response);
|
|
56
|
+
});
|
|
57
|
+
it('JWT Validator - verifyHeader - should reject empty header', async () => {
|
|
58
|
+
const response = await jwtValidator_1.jwtValidator.verifyAuthorizationHeader('').catch((err) => {
|
|
59
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_AUTHORIZATION_HEADER);
|
|
60
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
61
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid Authorization header');
|
|
62
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.NULL_VALUE);
|
|
63
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'Authorization header');
|
|
64
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'Empty Authorization header');
|
|
65
|
+
});
|
|
66
|
+
chai_1.assert.isUndefined(response);
|
|
67
|
+
});
|
|
68
|
+
it('JWT Validator - verifyHeader - should reject unknow authentication scheme', async () => {
|
|
69
|
+
const response = await jwtValidator_1.jwtValidator.verifyAuthorizationHeader('Unknow JWT').catch((err) => {
|
|
70
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_AUTHORIZATION_HEADER);
|
|
71
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
72
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid Authorization header');
|
|
73
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
74
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'Authorization header');
|
|
75
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'Bad authentication scheme, "Bearer" required');
|
|
76
|
+
});
|
|
77
|
+
chai_1.assert.isUndefined(response);
|
|
78
|
+
});
|
|
79
|
+
it('JWT Validator - verifyHeader - should reject bad token', async () => {
|
|
80
|
+
const response = await jwtValidator_1.jwtValidator.verifyAuthorizationHeader('Bearer JWT').catch((err) => {
|
|
81
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
82
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
83
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
84
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
85
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
86
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'jwt malformed');
|
|
87
|
+
});
|
|
88
|
+
chai_1.assert.isUndefined(response);
|
|
89
|
+
});
|
|
90
|
+
it('JWT Validator - verifyHeader - should accept good token', async () => {
|
|
91
|
+
date = new Date(publicKeys[5].createdAt);
|
|
92
|
+
date.setHours(date.getHours() + 24);
|
|
93
|
+
const payload = {
|
|
94
|
+
accessToken: 'c9ba5a95-d7f9-41f9-9a24-a7e41882f7ef',
|
|
95
|
+
iss: 'Issuer',
|
|
96
|
+
inum: 'MyInum',
|
|
97
|
+
iat: date.getTime() / 1000,
|
|
98
|
+
exp: date.getTime() / 1000 + 3600,
|
|
99
|
+
sub: '@!4025.CA62.9BB6.16C5!0001!2212.0010!0000!0000.0001',
|
|
100
|
+
keyId: 5,
|
|
101
|
+
};
|
|
102
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
103
|
+
algorithm: 'RS256',
|
|
104
|
+
});
|
|
105
|
+
const response = await jwtValidator_1.jwtValidator.verifyAuthorizationHeader('Bearer ' + token);
|
|
106
|
+
chai_1.assert.deepEqual(response, payload);
|
|
107
|
+
});
|
|
108
|
+
it('JWT Validator - verify - should reject bad token', async () => {
|
|
109
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken('JWT').catch((err) => {
|
|
110
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
111
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
112
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
113
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
114
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
115
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'jwt malformed');
|
|
116
|
+
});
|
|
117
|
+
chai_1.assert.isUndefined(response);
|
|
118
|
+
});
|
|
119
|
+
it('JWT Validator - verify - should reject invalid token: missing signature', async () => {
|
|
120
|
+
let token = '';
|
|
121
|
+
token += Buffer.from('{}', 'base64');
|
|
122
|
+
token += '.';
|
|
123
|
+
token += Buffer.from('{}', 'base64');
|
|
124
|
+
token += '.';
|
|
125
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
126
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
127
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
128
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
129
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
130
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
131
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'jwt malformed');
|
|
132
|
+
});
|
|
133
|
+
chai_1.assert.isUndefined(response);
|
|
134
|
+
});
|
|
135
|
+
it('JWT Validator - verify - should reject invalid token: empty JSON', async () => {
|
|
136
|
+
let token = '';
|
|
137
|
+
token += Buffer.from('{}', 'base64');
|
|
138
|
+
token += '.';
|
|
139
|
+
token += Buffer.from('{}', 'base64');
|
|
140
|
+
token += '.';
|
|
141
|
+
token += 'TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ';
|
|
142
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
143
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
144
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
145
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
146
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
147
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
148
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'jwt malformed');
|
|
149
|
+
});
|
|
150
|
+
chai_1.assert.isUndefined(response);
|
|
151
|
+
});
|
|
152
|
+
it('JWT Validator - verify - should reject invalid token: missing public key ID', async () => {
|
|
153
|
+
const token = jwt.sign('{"a":"a"}', 'key', { algorithm: 'HS256' });
|
|
154
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
155
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
156
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
157
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
158
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
159
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
160
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'missing public key ID');
|
|
161
|
+
});
|
|
162
|
+
chai_1.assert.isUndefined(response);
|
|
163
|
+
});
|
|
164
|
+
it('JWT Validator - verify - should reject invalid token: keyId is no longer active', async () => {
|
|
165
|
+
const token = jwt.sign('{"a":"a", "keyId": "1"}', 'key', { algorithm: 'HS256' });
|
|
166
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
167
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
168
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
169
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
170
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
171
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
172
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'this keyId is no longer active');
|
|
173
|
+
});
|
|
174
|
+
chai_1.assert.isUndefined(response);
|
|
175
|
+
});
|
|
176
|
+
it('JWT Validator - verify - should reject invalid token: keyId not found', async () => {
|
|
177
|
+
const pathRegex = createPathRegex();
|
|
178
|
+
// Intercept request
|
|
179
|
+
nock(configs_1.configs.getHost()).get(pathRegex).reply(404);
|
|
180
|
+
const token = jwt.sign('{"a":"a", "keyId": "25"}', 'key', { algorithm: 'HS256' });
|
|
181
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
182
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
183
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
184
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
185
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
186
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
187
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'this keyId is no longer active');
|
|
188
|
+
});
|
|
189
|
+
chai_1.assert.isUndefined(response);
|
|
190
|
+
});
|
|
191
|
+
it('JWT Validator - verify - should reject invalid algorithm: bad signature', async () => {
|
|
192
|
+
let token = '';
|
|
193
|
+
token += Buffer.from('{"alg":"HS256","typ":"JWT"}', 'base64');
|
|
194
|
+
token += '.';
|
|
195
|
+
token += Buffer.from('{"a":"a", "keyId": 5}', 'base64');
|
|
196
|
+
token += '.';
|
|
197
|
+
token += 'TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ';
|
|
198
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
199
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
200
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
201
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
202
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
203
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
204
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'jwt malformed');
|
|
205
|
+
});
|
|
206
|
+
chai_1.assert.isUndefined(response);
|
|
207
|
+
});
|
|
208
|
+
it('JWT Validator - verify - should reject invalid algorithm: bad signature (algorithm)', async () => {
|
|
209
|
+
const token = jwt.sign('{"a":"a", "keyId": 5}', 'key', { algorithm: 'HS256' });
|
|
210
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
211
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
212
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
213
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
214
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
215
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
216
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'invalid algorithm');
|
|
217
|
+
});
|
|
218
|
+
chai_1.assert.isUndefined(response);
|
|
219
|
+
});
|
|
220
|
+
it('JWT Validator - verify - should reject expired token', async () => {
|
|
221
|
+
date = new Date(publicKeys[5].createdAt);
|
|
222
|
+
date.setHours(date.getHours() + 24);
|
|
223
|
+
const payload = {
|
|
224
|
+
b: 'b',
|
|
225
|
+
iat: date.getTime() / 1000,
|
|
226
|
+
exp: 1,
|
|
227
|
+
keyId: 5,
|
|
228
|
+
};
|
|
229
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
230
|
+
algorithm: 'RS256',
|
|
231
|
+
});
|
|
232
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
233
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
234
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
235
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
236
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
237
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
238
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'jwt expired');
|
|
239
|
+
});
|
|
240
|
+
chai_1.assert.isUndefined(response);
|
|
241
|
+
});
|
|
242
|
+
it('JWT Validator - verify - should reject expired public key', async () => {
|
|
243
|
+
const payload = {
|
|
244
|
+
b: 'b',
|
|
245
|
+
keyId: 2,
|
|
246
|
+
};
|
|
247
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
248
|
+
algorithm: 'RS256',
|
|
249
|
+
});
|
|
250
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
251
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
252
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
253
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
254
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
255
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
256
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'this keyId is expired');
|
|
257
|
+
});
|
|
258
|
+
chai_1.assert.isUndefined(response);
|
|
259
|
+
});
|
|
260
|
+
it('JWT Validator - verify - should reject expired public key (by state)', async () => {
|
|
261
|
+
const payload = {
|
|
262
|
+
b: 'b',
|
|
263
|
+
keyId: 1,
|
|
264
|
+
};
|
|
265
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
266
|
+
algorithm: 'RS256',
|
|
267
|
+
});
|
|
268
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
269
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
270
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
271
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
272
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
273
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
274
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'this keyId is no longer active');
|
|
275
|
+
});
|
|
276
|
+
chai_1.assert.isUndefined(response);
|
|
277
|
+
});
|
|
278
|
+
it('JWT Validator - verify - should reject revoked public key', async () => {
|
|
279
|
+
const payload = {
|
|
280
|
+
b: 'b',
|
|
281
|
+
keyId: 3,
|
|
282
|
+
};
|
|
283
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
284
|
+
algorithm: 'RS256',
|
|
285
|
+
});
|
|
286
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
287
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
288
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
289
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
290
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
291
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
292
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'this keyId is no longer active');
|
|
293
|
+
});
|
|
294
|
+
chai_1.assert.isUndefined(response);
|
|
295
|
+
});
|
|
296
|
+
it('JWT Validator - verify - should reject jwt created after the expiration date of the key', async () => {
|
|
297
|
+
date = new Date(publicKeys[4].expiresAt);
|
|
298
|
+
date.setHours(date.getHours() + 24);
|
|
299
|
+
const payload = {
|
|
300
|
+
b: 'b',
|
|
301
|
+
iat: date.getTime() / 1000,
|
|
302
|
+
keyId: 4,
|
|
303
|
+
};
|
|
304
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
305
|
+
algorithm: 'RS256',
|
|
306
|
+
});
|
|
307
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
308
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
309
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
310
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
311
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
312
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
313
|
+
chai_1.assert.strictEqual(err.error.details[0].message, "this jwt can't be created after the expiration of the public key");
|
|
314
|
+
});
|
|
315
|
+
chai_1.assert.isUndefined(response);
|
|
316
|
+
});
|
|
317
|
+
it('JWT Validator - verify - should reject jwt created before the creation date of the key', async () => {
|
|
318
|
+
date = new Date(publicKeys[4].createdAt);
|
|
319
|
+
date.setHours(date.getHours() - 48);
|
|
320
|
+
const payload = {
|
|
321
|
+
b: 'b',
|
|
322
|
+
iat: date.getTime() / 1000,
|
|
323
|
+
keyId: 4,
|
|
324
|
+
};
|
|
325
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
326
|
+
algorithm: 'RS256',
|
|
327
|
+
});
|
|
328
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
329
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
330
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
331
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
332
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
333
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
334
|
+
chai_1.assert.strictEqual(err.error.details[0].message, "this jwt can't be created before the public key");
|
|
335
|
+
});
|
|
336
|
+
chai_1.assert.isUndefined(response);
|
|
337
|
+
});
|
|
338
|
+
it('JWT Validator - verify - should accept good token', async () => {
|
|
339
|
+
date = new Date();
|
|
340
|
+
const payload = {
|
|
341
|
+
accessToken: 'c9ba5a95-d7f9-41f9-9a24-a7e41882f7ef',
|
|
342
|
+
iss: 'Issuer',
|
|
343
|
+
inum: 'MyInum',
|
|
344
|
+
iat: date.getTime() / 1000,
|
|
345
|
+
exp: date.getTime() / 1000 + 3600,
|
|
346
|
+
sub: '@!4025.CA62.9BB6.16C5!0001!2212.0010!0000!0000.0001',
|
|
347
|
+
keyId: 4,
|
|
348
|
+
};
|
|
349
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
350
|
+
algorithm: 'RS256',
|
|
351
|
+
});
|
|
352
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token);
|
|
353
|
+
chai_1.assert.deepEqual(response, payload);
|
|
354
|
+
});
|
|
355
|
+
it('isRequestWithJwt', async () => {
|
|
356
|
+
const req = httpMocks.createRequest({ method: 'GET', url: '/' });
|
|
357
|
+
chai_1.assert.isFalse((0, expressRequest_1.isRequestWithJwt)(req));
|
|
358
|
+
req[constants_1.constants.requestExtraVariables.JWT] = 'Bonjour la police';
|
|
359
|
+
chai_1.assert.isTrue((0, expressRequest_1.isRequestWithJwt)(req));
|
|
360
|
+
});
|
|
361
|
+
it('JWT Validator - unable to get public key', async () => {
|
|
362
|
+
const pathRegex = createPathRegex();
|
|
363
|
+
// Intercept request
|
|
364
|
+
nock(configs_1.configs.getHost()).get(pathRegex).reply(500);
|
|
365
|
+
const token = jwt.sign('{"a":"a", "keyId": "25"}', 'key', { algorithm: 'HS256' });
|
|
366
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token).catch((err) => {
|
|
367
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.UNABLE_TO_GET_PUBLIC_KEY);
|
|
368
|
+
chai_1.assert.strictEqual(err.httpStatus, 500);
|
|
369
|
+
});
|
|
370
|
+
chai_1.assert.isUndefined(response);
|
|
371
|
+
});
|
|
372
|
+
it('JWT Validator - network error - should accept good token if cached', async () => {
|
|
373
|
+
// Invalidate cache
|
|
374
|
+
const currentNextUpdate = cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate;
|
|
375
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = undefined;
|
|
376
|
+
const pathRegex = createPathRegex();
|
|
377
|
+
// Intercept request
|
|
378
|
+
nock(configs_1.configs.getHost()).get(pathRegex).replyWithError({ code: 'ABORTED' });
|
|
379
|
+
date = new Date();
|
|
380
|
+
const payload = {
|
|
381
|
+
accessToken: 'c9ba5a95-d7f9-41f9-9a24-a7e41882f7ef',
|
|
382
|
+
iss: 'Issuer',
|
|
383
|
+
inum: 'MyInum',
|
|
384
|
+
iat: date.getTime() / 1000,
|
|
385
|
+
exp: date.getTime() / 1000 + 3600,
|
|
386
|
+
sub: '@!4025.CA62.9BB6.16C5!0001!2212.0010!0000!0000.0001',
|
|
387
|
+
keyId: 4,
|
|
388
|
+
};
|
|
389
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
390
|
+
algorithm: 'RS256',
|
|
391
|
+
});
|
|
392
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token);
|
|
393
|
+
chai_1.assert.deepEqual(response, payload);
|
|
394
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = currentNextUpdate;
|
|
395
|
+
});
|
|
396
|
+
it('JWT Validator - 500 error from api - should accept good token if cached', async () => {
|
|
397
|
+
// Invalidate cache
|
|
398
|
+
const currentNextUpdate = cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate;
|
|
399
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = undefined;
|
|
400
|
+
const pathRegex = createPathRegex();
|
|
401
|
+
// Error from api
|
|
402
|
+
// Intercept request
|
|
403
|
+
nock(configs_1.configs.getHost())
|
|
404
|
+
.get(pathRegex)
|
|
405
|
+
.reply(500, (0, src_1.createServerError)('Error while sending request'));
|
|
406
|
+
date = new Date();
|
|
407
|
+
const payload = {
|
|
408
|
+
accessToken: 'c9ba5a95-d7f9-41f9-9a24-a7e41882f7ef',
|
|
409
|
+
iss: 'Issuer',
|
|
410
|
+
inum: 'MyInum',
|
|
411
|
+
iat: date.getTime() / 1000,
|
|
412
|
+
exp: date.getTime() / 1000 + 3600,
|
|
413
|
+
sub: '@!4025.CA62.9BB6.16C5!0001!2212.0010!0000!0000.0001',
|
|
414
|
+
keyId: 4,
|
|
415
|
+
};
|
|
416
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
417
|
+
algorithm: 'RS256',
|
|
418
|
+
});
|
|
419
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token);
|
|
420
|
+
chai_1.assert.deepEqual(response, payload);
|
|
421
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = currentNextUpdate;
|
|
422
|
+
});
|
|
423
|
+
it('JWT Validator - 429 error from api - should accept good token if cached', async () => {
|
|
424
|
+
// Invalidate cache
|
|
425
|
+
const currentNextUpdate = cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate;
|
|
426
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = undefined;
|
|
427
|
+
const pathRegex = createPathRegex();
|
|
428
|
+
// Error from api
|
|
429
|
+
// Intercept request
|
|
430
|
+
nock(configs_1.configs.getHost()).get(pathRegex).reply(429);
|
|
431
|
+
date = new Date();
|
|
432
|
+
const payload = {
|
|
433
|
+
accessToken: 'c9ba5a95-d7f9-41f9-9a24-a7e41882f7ef',
|
|
434
|
+
iss: 'Issuer',
|
|
435
|
+
inum: 'MyInum',
|
|
436
|
+
iat: date.getTime() / 1000,
|
|
437
|
+
exp: date.getTime() / 1000 + 3600,
|
|
438
|
+
sub: '@!4025.CA62.9BB6.16C5!0001!2212.0010!0000!0000.0001',
|
|
439
|
+
keyId: 4,
|
|
440
|
+
};
|
|
441
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
442
|
+
algorithm: 'RS256',
|
|
443
|
+
});
|
|
444
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken(token);
|
|
445
|
+
chai_1.assert.deepEqual(response, payload);
|
|
446
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = currentNextUpdate;
|
|
447
|
+
});
|
|
448
|
+
it('JWT Validator - 400 error from api - should reject', async () => {
|
|
449
|
+
// Invalidate cache
|
|
450
|
+
const currentNextUpdate = cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate;
|
|
451
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = undefined;
|
|
452
|
+
const pathRegex = createPathRegex();
|
|
453
|
+
// Error from api
|
|
454
|
+
// Intercept request
|
|
455
|
+
nock(configs_1.configs.getHost())
|
|
456
|
+
.get(pathRegex)
|
|
457
|
+
.reply(400, (0, src_1.createInvalidParameterError)('Something is wrong'));
|
|
458
|
+
date = new Date();
|
|
459
|
+
const payload = {
|
|
460
|
+
accessToken: 'c9ba5a95-d7f9-41f9-9a24-a7e41882f7ef',
|
|
461
|
+
iss: 'Issuer',
|
|
462
|
+
inum: 'MyInum',
|
|
463
|
+
iat: date.getTime() / 1000,
|
|
464
|
+
exp: date.getTime() / 1000 + 3600,
|
|
465
|
+
sub: '@!4025.CA62.9BB6.16C5!0001!2212.0010!0000!0000.0001',
|
|
466
|
+
keyId: 4,
|
|
467
|
+
};
|
|
468
|
+
const token = jwt.sign(JSON.stringify(payload), jwtMock_1.jwtMock.getPrivateKey(), {
|
|
469
|
+
algorithm: 'RS256',
|
|
470
|
+
});
|
|
471
|
+
let error;
|
|
472
|
+
try {
|
|
473
|
+
await jwtValidator_1.jwtValidator.verifyToken(token);
|
|
474
|
+
}
|
|
475
|
+
catch (e) {
|
|
476
|
+
error = e;
|
|
477
|
+
}
|
|
478
|
+
chai_1.assert.isDefined(error);
|
|
479
|
+
chai_1.assert.instanceOf(error, src_1.ApiErrorAndInfo);
|
|
480
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = currentNextUpdate;
|
|
481
|
+
});
|
|
482
|
+
it('JWT Validator - network error - should reject bad token anyway', async () => {
|
|
483
|
+
// Invalidate cache
|
|
484
|
+
const currentNextUpdate = cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate;
|
|
485
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = undefined;
|
|
486
|
+
const pathRegex = createPathRegex();
|
|
487
|
+
// Intercept request
|
|
488
|
+
nock(configs_1.configs.getHost()).get(pathRegex).replyWithError({ code: 'ABORTED' });
|
|
489
|
+
const response = await jwtValidator_1.jwtValidator.verifyToken('JWT').catch((err) => {
|
|
490
|
+
chai_1.assert.strictEqual(err.error.code, constants_1.constants.errors.codes.INVALID_JWT);
|
|
491
|
+
chai_1.assert.strictEqual(err.error.target, 'Authorization header');
|
|
492
|
+
chai_1.assert.strictEqual(err.error.message, 'Invalid JWT');
|
|
493
|
+
chai_1.assert.strictEqual(err.error.details[0].code, constants_1.constants.errors.codes.INVALID_VALUE);
|
|
494
|
+
chai_1.assert.strictEqual(err.error.details[0].target, 'jwt');
|
|
495
|
+
chai_1.assert.strictEqual(err.error.details[0].message, 'jwt malformed');
|
|
496
|
+
});
|
|
497
|
+
chai_1.assert.isUndefined(response);
|
|
498
|
+
cachedPublicKeyRepository_1.cachedPublicKeyRepository._nextUpdate = currentNextUpdate;
|
|
499
|
+
});
|
|
500
|
+
//# sourceMappingURL=jwtValidator.test.js.map
|