@axinom/mosaic-id-guard 0.26.0-rc.9 → 0.26.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/dist/common/helpers/parse-jwt-token-error-handler.d.ts +3 -1
- package/dist/common/helpers/parse-jwt-token-error-handler.d.ts.map +1 -1
- package/dist/common/helpers/parse-jwt-token-error-handler.js +50 -12
- package/dist/common/helpers/parse-jwt-token-error-handler.js.map +1 -1
- package/dist/common/parse-jwt-token.d.ts.map +1 -1
- package/dist/common/parse-jwt-token.js +3 -1
- package/dist/common/parse-jwt-token.js.map +1 -1
- package/dist/graphql/ax-guard-plugin.d.ts +2 -1
- package/dist/graphql/ax-guard-plugin.d.ts.map +1 -1
- package/dist/graphql/ax-guard-plugin.js +2 -2
- package/dist/graphql/ax-guard-plugin.js.map +1 -1
- package/dist/graphql/generate-permissions-file-plugin.d.ts +2 -1
- package/dist/graphql/generate-permissions-file-plugin.d.ts.map +1 -1
- package/dist/graphql/generate-permissions-file-plugin.js +7 -5
- package/dist/graphql/generate-permissions-file-plugin.js.map +1 -1
- package/dist/message-bus/guarded-transactional-inbox-message-handler.d.ts +4 -0
- package/dist/message-bus/guarded-transactional-inbox-message-handler.d.ts.map +1 -1
- package/dist/message-bus/guarded-transactional-inbox-message-handler.js +10 -0
- package/dist/message-bus/guarded-transactional-inbox-message-handler.js.map +1 -1
- package/package.json +9 -8
- package/src/common/helpers/parse-jwt-token-error-handler.ts +65 -20
- package/src/common/parse-jwt-token.spec.ts +131 -76
- package/src/common/parse-jwt-token.ts +4 -1
- package/src/graphql/ax-guard-plugin.ts +3 -1
- package/src/graphql/generate-permissions-file-plugin.ts +12 -8
- package/src/message-bus/guarded-transactional-inbox-message-handler.spec.ts +170 -0
- package/src/message-bus/guarded-transactional-inbox-message-handler.ts +20 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IdGuardErrors } from '../id-guard-errors';
|
|
2
|
+
import { AuthenticationConfig } from '../types';
|
|
2
3
|
type JwtErrors = typeof IdGuardErrors.MalformedToken.code | typeof IdGuardErrors.AccessTokenExpired.code | typeof IdGuardErrors.SigningKeyNotFound.code | typeof IdGuardErrors.JwksError.code | typeof IdGuardErrors.AccessTokenVerificationFailed.code | typeof IdGuardErrors.AuthConfigInvalid.code | typeof IdGuardErrors.AccessTokenRequired.code | typeof IdGuardErrors.IdentityServiceNotAccessible.code | typeof IdGuardErrors.UserServiceNotAccessible.code;
|
|
3
4
|
/**
|
|
4
5
|
* Handles an error thrown by the parseJwtToken function.
|
|
@@ -7,8 +8,9 @@ type JwtErrors = typeof IdGuardErrors.MalformedToken.code | typeof IdGuardErrors
|
|
|
7
8
|
* @param err Error of type unknown
|
|
8
9
|
* @param authType Auth Type - 'MANAGEMENT' | 'END_USER'
|
|
9
10
|
* @param token JWT token
|
|
11
|
+
* @param authConfig an object with ID/User service connection information or a path to a public key file.
|
|
10
12
|
* @returns [code, message, originalError]
|
|
11
13
|
*/
|
|
12
|
-
export declare const handleJwtParseError: (err: unknown, authType: 'MANAGEMENT' | 'END_USER' | undefined, token: string) => [code: JwtErrors, message: string, originalError: Error];
|
|
14
|
+
export declare const handleJwtParseError: (err: unknown, authType: 'MANAGEMENT' | 'END_USER' | undefined, token: string, authConfig: string | AuthenticationConfig) => [code: JwtErrors, message: string, originalError: Error | undefined, details: string | Record<string, unknown> | undefined];
|
|
13
15
|
export {};
|
|
14
16
|
//# sourceMappingURL=parse-jwt-token-error-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-jwt-token-error-handler.d.ts","sourceRoot":"","sources":["../../../src/common/helpers/parse-jwt-token-error-handler.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"parse-jwt-token-error-handler.d.ts","sourceRoot":"","sources":["../../../src/common/helpers/parse-jwt-token-error-handler.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAGL,oBAAoB,EACrB,MAAM,UAAU,CAAC;AAGlB,KAAK,SAAS,GACV,OAAO,aAAa,CAAC,cAAc,CAAC,IAAI,GACxC,OAAO,aAAa,CAAC,kBAAkB,CAAC,IAAI,GAC5C,OAAO,aAAa,CAAC,kBAAkB,CAAC,IAAI,GAC5C,OAAO,aAAa,CAAC,SAAS,CAAC,IAAI,GACnC,OAAO,aAAa,CAAC,6BAA6B,CAAC,IAAI,GACvD,OAAO,aAAa,CAAC,iBAAiB,CAAC,IAAI,GAC3C,OAAO,aAAa,CAAC,mBAAmB,CAAC,IAAI,GAC7C,OAAO,aAAa,CAAC,4BAA4B,CAAC,IAAI,GACtD,OAAO,aAAa,CAAC,wBAAwB,CAAC,IAAI,CAAC;AAiFvD;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,QACzB,OAAO,YACF,YAAY,GAAG,UAAU,GAAG,SAAS,SACxC,MAAM,cACD,MAAM,GAAG,oBAAoB,gIAqE1C,CAAC"}
|
|
@@ -38,16 +38,28 @@ const id_guard_errors_1 = require("../id-guard-errors");
|
|
|
38
38
|
* @param errorCode a value from the IdGuardErrors
|
|
39
39
|
* @param authType Auth Type - 'MANAGEMENT' | 'END_USER'
|
|
40
40
|
* @param token JWT Token
|
|
41
|
+
* @param authConfig an object with ID/User service connection information or a path to a public key file.
|
|
41
42
|
* @returns
|
|
42
43
|
*/
|
|
43
|
-
const buildJwtErrorMessage = (errorCode, authType, token) => {
|
|
44
|
+
const buildJwtErrorMessage = (errorCode, authType, token, authConfig) => {
|
|
44
45
|
let message = '';
|
|
45
46
|
switch (errorCode) {
|
|
46
47
|
case id_guard_errors_1.IdGuardErrors.SigningKeyNotFound.code: {
|
|
47
48
|
const decodedToken = jsonwebtoken_1.default.decode(token);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
if (typeof authConfig === 'string') {
|
|
50
|
+
message = `Could not find a matching signing key to verify the token used in the request. Please try again with a new token or contact Axinom support if the problem persists.`;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
if (decodedToken.tenantId !==
|
|
54
|
+
authConfig.tenantId ||
|
|
55
|
+
decodedToken.environmentId !==
|
|
56
|
+
authConfig.environmentId) {
|
|
57
|
+
message = `The service is configured to work with a different Tenant ID/Environment ID than found in the token.`;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
message = `Could not find a matching signing key to verify the token used in the request. The token's signing key may have been revoked. Please try again with a new token.`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
51
63
|
break;
|
|
52
64
|
}
|
|
53
65
|
case id_guard_errors_1.IdGuardErrors.JwksError.code: {
|
|
@@ -90,38 +102,64 @@ const buildJwtErrorMessage = (errorCode, authType, token) => {
|
|
|
90
102
|
* @param err Error of type unknown
|
|
91
103
|
* @param authType Auth Type - 'MANAGEMENT' | 'END_USER'
|
|
92
104
|
* @param token JWT token
|
|
105
|
+
* @param authConfig an object with ID/User service connection information or a path to a public key file.
|
|
93
106
|
* @returns [code, message, originalError]
|
|
94
107
|
*/
|
|
95
|
-
const handleJwtParseError = (err, authType, token) => {
|
|
108
|
+
const handleJwtParseError = (err, authType, token, authConfig) => {
|
|
96
109
|
let code;
|
|
97
110
|
let message;
|
|
98
111
|
let originalError;
|
|
112
|
+
let details;
|
|
99
113
|
if (err instanceof jsonwebtoken_1.default.TokenExpiredError) {
|
|
100
114
|
code = id_guard_errors_1.IdGuardErrors.AccessTokenExpired.code;
|
|
101
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
115
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
102
116
|
}
|
|
103
117
|
else if (err instanceof jwks.SigningKeyNotFoundError) {
|
|
104
118
|
code = id_guard_errors_1.IdGuardErrors.SigningKeyNotFound.code;
|
|
105
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
119
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
120
|
+
const decodedToken = jsonwebtoken_1.default.decode(token);
|
|
121
|
+
if (typeof authConfig === 'string') {
|
|
122
|
+
details = {
|
|
123
|
+
tokenKid: decodedToken.kid,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
if (decodedToken.tenantId !==
|
|
128
|
+
authConfig.tenantId ||
|
|
129
|
+
decodedToken.environmentId !==
|
|
130
|
+
authConfig.environmentId) {
|
|
131
|
+
details = {
|
|
132
|
+
service: {
|
|
133
|
+
tenantId: authConfig.tenantId,
|
|
134
|
+
environmentId: authConfig.environmentId,
|
|
135
|
+
},
|
|
136
|
+
token: {
|
|
137
|
+
tenantId: decodedToken.tenantId,
|
|
138
|
+
environmentId: decodedToken
|
|
139
|
+
.environmentId,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
106
144
|
}
|
|
107
145
|
else if (err instanceof jwks.JwksError) {
|
|
108
146
|
code = id_guard_errors_1.IdGuardErrors.JwksError.code;
|
|
109
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
147
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
110
148
|
}
|
|
111
149
|
else if (err.code === 'ECONNREFUSED') {
|
|
112
150
|
code =
|
|
113
151
|
authType === 'END_USER'
|
|
114
152
|
? id_guard_errors_1.IdGuardErrors.UserServiceNotAccessible.code
|
|
115
153
|
: id_guard_errors_1.IdGuardErrors.IdentityServiceNotAccessible.code;
|
|
116
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
154
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
117
155
|
}
|
|
118
156
|
else if (err instanceof SyntaxError) {
|
|
119
157
|
code = id_guard_errors_1.IdGuardErrors.MalformedToken.code;
|
|
120
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
158
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
121
159
|
}
|
|
122
160
|
else {
|
|
123
161
|
code = id_guard_errors_1.IdGuardErrors.AccessTokenVerificationFailed.code;
|
|
124
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
162
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
125
163
|
}
|
|
126
164
|
// If thrown error is an instance of Error, take that as the original error. If not, create a new NonMosaicError and encapsulate the unknown error in it
|
|
127
165
|
if (err instanceof Error) {
|
|
@@ -130,7 +168,7 @@ const handleJwtParseError = (err, authType, token) => {
|
|
|
130
168
|
else {
|
|
131
169
|
originalError = new mosaic_service_common_1.NonMosaicError(err);
|
|
132
170
|
}
|
|
133
|
-
return [code, message, originalError];
|
|
171
|
+
return [code, message, originalError, details];
|
|
134
172
|
};
|
|
135
173
|
exports.handleJwtParseError = handleJwtParseError;
|
|
136
174
|
//# sourceMappingURL=parse-jwt-token-error-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-jwt-token-error-handler.js","sourceRoot":"","sources":["../../../src/common/helpers/parse-jwt-token-error-handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yEAGuC;AACvC,gEAA+B;AAC/B,+CAAiC;AACjC,wDAAmD;
|
|
1
|
+
{"version":3,"file":"parse-jwt-token-error-handler.js","sourceRoot":"","sources":["../../../src/common/helpers/parse-jwt-token-error-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-jwt-token.d.ts","sourceRoot":"","sources":["../../src/common/parse-jwt-token.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,oBAAoB,EAEpB,8BAA8B,EAC9B,oBAAoB,EACpB,4BAA4B,EAC5B,+BAA+B,EAChC,MAAM,SAAS,CAAC;AAEjB;;;;;GAKG;AACH,eAAO,MAAM,aAAa,UACjB,MAAM,GAAG,SAAS,cACb,MAAM,GAAG,oBAAoB,aAC9B,YAAY,GAAG,UAAU,KACnC,QAAQ,+BAA+B,GAAG,4BAA4B,
|
|
1
|
+
{"version":3,"file":"parse-jwt-token.d.ts","sourceRoot":"","sources":["../../src/common/parse-jwt-token.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,oBAAoB,EAEpB,8BAA8B,EAC9B,oBAAoB,EACpB,4BAA4B,EAC5B,+BAA+B,EAChC,MAAM,SAAS,CAAC;AAEjB;;;;;GAKG;AACH,eAAO,MAAM,aAAa,UACjB,MAAM,GAAG,SAAS,cACb,MAAM,GAAG,oBAAoB,aAC9B,YAAY,GAAG,UAAU,KACnC,QAAQ,+BAA+B,GAAG,4BAA4B,CAoFxE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,UAC/B,MAAM,KACZ,8BAEF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,UAC5B,MAAM,KACZ,oBAEF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,UACzB,MAAM,wBACS,MAAM,KAC3B,QAAQ,OAAO,CA8BjB,CAAC"}
|
|
@@ -46,6 +46,7 @@ const parseJwtToken = async (token, authConfig, authType) => {
|
|
|
46
46
|
let code;
|
|
47
47
|
let message;
|
|
48
48
|
let originalError;
|
|
49
|
+
let details;
|
|
49
50
|
let subject;
|
|
50
51
|
let authErrorInfo;
|
|
51
52
|
if (!(0, mosaic_service_common_1.isNullOrWhitespace)(token)) {
|
|
@@ -80,7 +81,7 @@ const parseJwtToken = async (token, authConfig, authType) => {
|
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
catch (err) {
|
|
83
|
-
[code, message, originalError] = (0, helpers_1.handleJwtParseError)(err, authType, token);
|
|
84
|
+
[code, message, originalError, details] = (0, helpers_1.handleJwtParseError)(err, authType, token, authConfig);
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
else {
|
|
@@ -95,6 +96,7 @@ const parseJwtToken = async (token, authConfig, authType) => {
|
|
|
95
96
|
code,
|
|
96
97
|
message,
|
|
97
98
|
error: originalError,
|
|
99
|
+
details: { details },
|
|
98
100
|
};
|
|
99
101
|
}
|
|
100
102
|
// At this point the authType will have a value.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-jwt-token.js","sourceRoot":"","sources":["../../src/common/parse-jwt-token.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yEAGuC;AACvC,uCAAyB;AACzB,gEAA+B;AAE/B,2EAGqC;AACrC,uCAAgD;AAChD,uDAAkD;AAClD,+CAA8C;AAC9C,6DAA2D;AAC3D,iDAA6C;AAU7C;;;;;GAKG;AACI,MAAM,aAAa,GAAG,KAAK,EAChC,KAAyB,EACzB,UAAyC,EACzC,QAAoC,EACqC,EAAE;IAC3E,IAAI,IAAwB,CAAC;IAC7B,IAAI,OAA2B,CAAC;IAChC,IAAI,aAAgC,CAAC;IACrC,IAAI,OAIS,CAAC;IACd,IAAI,aAA0C,CAAC;IAE/C,IAAI,CAAC,IAAA,0CAAkB,EAAC,KAAK,CAAC,EAAE;QAC9B,IAAI;YACF,yIAAyI;YACzI,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;gBAClC,IAAI,QAAQ,KAAK,SAAS,EAAE;oBAC1B,IAAI,GAAG,+BAAa,CAAC,iBAAiB,CAAC,IAAI,CAAC;oBAC5C,OAAO;wBACL,wEAAwE,CAAC;oBAC3E,aAAa,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;iBACpC;qBAAM;oBACL,MAAM,aAAa,GAAG,UAAoB,CAAC;oBAC3C,MAAM,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;oBACzD,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,IAAA,wCAAmB,GAAE,CAAC,CAAC;oBACpE,OAAO,GAAG,OAAyC,CAAC;iBACrD;aACF;iBAAM;gBACL,IAAI,QAAQ,KAAK,SAAS,EAAE;oBAC1B,IAAI,GAAG,+BAAa,CAAC,iBAAiB,CAAC,IAAI,CAAC;oBAC5C,OAAO,GAAG,oDAAoD,CAAC;oBAC/D,aAAa,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;iBACpC;qBAAM,IAAI,QAAQ,KAAK,YAAY,EAAE;oBACpC,OAAO,GAAG,MAAM,IAAA,6DAAiC,EAAC,KAAK,EAAE,UAAU,CAAC,CAAC;iBACtE;qBAAM,IAAI,QAAQ,KAAK,UAAU,EAAE;oBAClC,OAAO,GAAG,MAAM,IAAA,mDAAuB,EAAC,KAAK,EAAE,UAAU,CAAC,CAAC;iBAC5D;aACF;SACF;QAAC,OAAO,GAAG,EAAE;YACZ,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,CAAC,GAAG,IAAA,6BAAmB,
|
|
1
|
+
{"version":3,"file":"parse-jwt-token.js","sourceRoot":"","sources":["../../src/common/parse-jwt-token.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BasicConfig } from '@axinom/mosaic-service-common';
|
|
1
2
|
import { Plugin } from 'graphile-build';
|
|
2
3
|
/**
|
|
3
4
|
* AxGuard plugin is created by combining three plugins - `QueryMutationGuardPlugin`,
|
|
@@ -23,5 +24,5 @@ import { Plugin } from 'graphile-build';
|
|
|
23
24
|
*
|
|
24
25
|
* @returns
|
|
25
26
|
*/
|
|
26
|
-
export declare const AxGuardPlugin: (permissionDefinitionExportPath?: string) => Plugin;
|
|
27
|
+
export declare const AxGuardPlugin: (config?: BasicConfig, permissionDefinitionExportPath?: string) => Plugin;
|
|
27
28
|
//# sourceMappingURL=ax-guard-plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ax-guard-plugin.d.ts","sourceRoot":"","sources":["../../src/graphql/ax-guard-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAMxC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"ax-guard-plugin.d.ts","sourceRoot":"","sources":["../../src/graphql/ax-guard-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAMxC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,aAAa,YACf,WAAW,mCACa,MAAM,KACtC,MAMF,CAAC"}
|
|
@@ -29,8 +29,8 @@ const subscription_guard_plugin_1 = require("./subscription-guard-plugin");
|
|
|
29
29
|
*
|
|
30
30
|
* @returns
|
|
31
31
|
*/
|
|
32
|
-
const AxGuardPlugin = (permissionDefinitionExportPath) => {
|
|
33
|
-
return (0, graphile_utils_1.makePluginByCombiningPlugins)((0, generate_permissions_file_plugin_1.PermissionDefinitionExporterPlugin)(permissionDefinitionExportPath), query_mutation_guard_plugin_1.QueryMutationGuardPlugin, subscription_guard_plugin_1.SubscriptionGuardPlugin);
|
|
32
|
+
const AxGuardPlugin = (config, permissionDefinitionExportPath) => {
|
|
33
|
+
return (0, graphile_utils_1.makePluginByCombiningPlugins)((0, generate_permissions_file_plugin_1.PermissionDefinitionExporterPlugin)(config, permissionDefinitionExportPath), query_mutation_guard_plugin_1.QueryMutationGuardPlugin, subscription_guard_plugin_1.SubscriptionGuardPlugin);
|
|
34
34
|
};
|
|
35
35
|
exports.AxGuardPlugin = AxGuardPlugin;
|
|
36
36
|
//# sourceMappingURL=ax-guard-plugin.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ax-guard-plugin.js","sourceRoot":"","sources":["../../src/graphql/ax-guard-plugin.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"ax-guard-plugin.js","sourceRoot":"","sources":["../../src/graphql/ax-guard-plugin.ts"],"names":[],"mappings":";;;AAEA,mDAA8D;AAC9D,yFAAwF;AACxF,+EAAyE;AACzE,2EAAsE;AAEtE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACI,MAAM,aAAa,GAAG,CAC3B,MAAoB,EACpB,8BAAuC,EAC/B,EAAE;IACV,OAAO,IAAA,6CAA4B,EACjC,IAAA,qEAAkC,EAAC,MAAM,EAAE,8BAA8B,CAAC,EAC1E,sDAAwB,EACxB,mDAAuB,CACxB,CAAC;AACJ,CAAC,CAAC;AATW,QAAA,aAAa,iBASxB"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { BasicConfig } from 'libs/service-common/dist';
|
|
1
2
|
import { Plugin } from 'postgraphile';
|
|
2
3
|
/**
|
|
3
4
|
* Exports the permissions definition to a file.
|
|
4
5
|
* @param permissionDefinitionExportPath
|
|
5
6
|
* @returns
|
|
6
7
|
*/
|
|
7
|
-
export declare function PermissionDefinitionExporterPlugin(permissionDefinitionExportPath?: string): Plugin;
|
|
8
|
+
export declare function PermissionDefinitionExporterPlugin(config?: BasicConfig, permissionDefinitionExportPath?: string): Plugin;
|
|
8
9
|
//# sourceMappingURL=generate-permissions-file-plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-permissions-file-plugin.d.ts","sourceRoot":"","sources":["../../src/graphql/generate-permissions-file-plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate-permissions-file-plugin.d.ts","sourceRoot":"","sources":["../../src/graphql/generate-permissions-file-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;GAIG;AACH,wBAAgB,kCAAkC,CAChD,MAAM,CAAC,EAAE,WAAW,EACpB,8BAA8B,CAAC,EAAE,MAAM,GACtC,MAAM,CAqBR"}
|
|
@@ -11,15 +11,17 @@ const path_1 = __importDefault(require("path"));
|
|
|
11
11
|
* @param permissionDefinitionExportPath
|
|
12
12
|
* @returns
|
|
13
13
|
*/
|
|
14
|
-
function PermissionDefinitionExporterPlugin(permissionDefinitionExportPath) {
|
|
14
|
+
function PermissionDefinitionExporterPlugin(config, permissionDefinitionExportPath) {
|
|
15
15
|
return (builder, options) => {
|
|
16
16
|
// Write permissions to file when the schema is built.
|
|
17
17
|
builder.hook('finalize', (schema, _build, _context) => {
|
|
18
|
-
if (
|
|
19
|
-
if (
|
|
20
|
-
|
|
18
|
+
if (config === null || config === void 0 ? void 0 : config.isDev) {
|
|
19
|
+
if (permissionDefinitionExportPath !== undefined) {
|
|
20
|
+
if (options.permissionDefinition === undefined) {
|
|
21
|
+
throw new Error('When a permissionDefinitionExportPath is provided to AxGuard Plugin, permissionDefinition must be defined in the Postgraphile options.');
|
|
22
|
+
}
|
|
23
|
+
writeSourceFile(permissionDefinitionExportPath, JSON.stringify(options.permissionDefinition, null, 2));
|
|
21
24
|
}
|
|
22
|
-
writeSourceFile(permissionDefinitionExportPath, JSON.stringify(options.permissionDefinition, null, 2));
|
|
23
25
|
}
|
|
24
26
|
return schema;
|
|
25
27
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-permissions-file-plugin.js","sourceRoot":"","sources":["../../src/graphql/generate-permissions-file-plugin.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;
|
|
1
|
+
{"version":3,"file":"generate-permissions-file-plugin.js","sourceRoot":"","sources":["../../src/graphql/generate-permissions-file-plugin.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AAEpB,gDAAwB;AAGxB;;;;GAIG;AACH,SAAgB,kCAAkC,CAChD,MAAoB,EACpB,8BAAuC;IAEvC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;QAC1B,sDAAsD;QACtD,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;YACpD,IAAI,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,EAAE;gBACjB,IAAI,8BAA8B,KAAK,SAAS,EAAE;oBAChD,IAAI,OAAO,CAAC,oBAAoB,KAAK,SAAS,EAAE;wBAC9C,MAAM,IAAI,KAAK,CACb,wIAAwI,CACzI,CAAC;qBACH;oBACD,eAAe,CACb,8BAA8B,EAC9B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC,CACtD,CAAC;iBACH;aACF;YAED,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAxBD,gFAwBC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,OAAe,EAAE,QAAgB;IACxD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE;QACzC,YAAE,CAAC,SAAS,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;KAC1D;IACD,yFAAyF;IACzF,IAAI,YAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;QAC1B,MAAM,eAAe,GAAG,YAAE,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QACxE,IAAI,eAAe,CAAC,QAAQ,EAAE,KAAK,QAAQ,EAAE;YAC3C,OAAO;SACR;KACF;IACD,YAAE,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -2,6 +2,7 @@ import { MessagingSettings } from '@axinom/mosaic-message-bus-abstractions';
|
|
|
2
2
|
import { Logger } from '@axinom/mosaic-service-common';
|
|
3
3
|
import { DbConfig, TransactionalInboxMessage, TransactionalInboxMessageHandler } from '@axinom/mosaic-transactional-inbox-outbox';
|
|
4
4
|
import { ClientBase } from 'pg';
|
|
5
|
+
import { InboxMessage } from 'pg-transactional-outbox';
|
|
5
6
|
import { AuthenticatedManagementSubject, AuthenticationConfig } from '../common';
|
|
6
7
|
export interface GuardedContext {
|
|
7
8
|
subject: AuthenticatedManagementSubject;
|
|
@@ -36,5 +37,8 @@ export declare abstract class GuardedTransactionalInboxMessageHandler<TMessage,
|
|
|
36
37
|
*/
|
|
37
38
|
protected abstract setPgSettings(envOwnerClient: ClientBase, subject: AuthenticatedManagementSubject): Promise<void>;
|
|
38
39
|
mapError(error: Error): Error;
|
|
40
|
+
protected updateErrorDetails(error: Error & {
|
|
41
|
+
details?: Record<string, unknown>;
|
|
42
|
+
}, message: InboxMessage, context?: GuardedContext): void;
|
|
39
43
|
}
|
|
40
44
|
//# sourceMappingURL=guarded-transactional-inbox-message-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guarded-transactional-inbox-message-handler.d.ts","sourceRoot":"","sources":["../../src/message-bus/guarded-transactional-inbox-message-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EACL,MAAM,EAGP,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,QAAQ,EACR,yBAAyB,EACzB,gCAAgC,EACjC,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EACL,8BAA8B,EAC9B,oBAAoB,EAGrB,MAAM,WAAW,CAAC;AAGnB,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,8BAA8B,CAAC;IACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG;IAAE,oBAAoB,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,8BAAsB,uCAAuC,CAC3D,QAAQ,EACR,OAAO,SAAS,aAAa,CAC7B,SAAQ,gCAAgC,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC;IAYzE,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE;IAG/B,OAAO,CAAC,UAAU;IAdpB;;;;;;;;OAQG;gBAED,iBAAiB,EAAE,iBAAiB,EAC1B,WAAW,EAAE,MAAM,EAAE,EAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACP,UAAU,EAAE,MAAM,GAAG,oBAAoB;IAWnD,SAAS,CAAC,wBAAwB,+EAEhB,UAAU,KACzB,QAAQ,cAAc,CAAC,CAYxB;IAEF;;;;;;;;;OASG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,CAC9B,cAAc,EAAE,UAAU,EAC1B,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,IAAI,CAAC;IAEP,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK;
|
|
1
|
+
{"version":3,"file":"guarded-transactional-inbox-message-handler.d.ts","sourceRoot":"","sources":["../../src/message-bus/guarded-transactional-inbox-message-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EACL,MAAM,EAGP,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,QAAQ,EACR,yBAAyB,EACzB,gCAAgC,EACjC,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACL,8BAA8B,EAC9B,oBAAoB,EAGrB,MAAM,WAAW,CAAC;AAGnB,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,8BAA8B,CAAC;IACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG;IAAE,oBAAoB,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,8BAAsB,uCAAuC,CAC3D,QAAQ,EACR,OAAO,SAAS,aAAa,CAC7B,SAAQ,gCAAgC,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC;IAYzE,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE;IAG/B,OAAO,CAAC,UAAU;IAdpB;;;;;;;;OAQG;gBAED,iBAAiB,EAAE,iBAAiB,EAC1B,WAAW,EAAE,MAAM,EAAE,EAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACP,UAAU,EAAE,MAAM,GAAG,oBAAoB;IAWnD,SAAS,CAAC,wBAAwB,+EAEhB,UAAU,KACzB,QAAQ,cAAc,CAAC,CAYxB;IAEF;;;;;;;;;OASG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,CAC9B,cAAc,EAAE,UAAU,EAC1B,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,IAAI,CAAC;IAEP,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK;cAInB,kBAAkB,CACnC,KAAK,EAAE,KAAK,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EACpD,OAAO,EAAE,YAAY,EACrB,OAAO,CAAC,EAAE,cAAc,GACvB,IAAI;CAcR"}
|
|
@@ -36,6 +36,16 @@ class GuardedTransactionalInboxMessageHandler extends mosaic_transactional_inbox
|
|
|
36
36
|
mapError(error) {
|
|
37
37
|
return (0, mosaic_service_common_1.getMappedError)(error);
|
|
38
38
|
}
|
|
39
|
+
updateErrorDetails(error, message, context) {
|
|
40
|
+
var _a, _b, _c, _d, _e;
|
|
41
|
+
super.updateErrorDetails(error, message, context);
|
|
42
|
+
if (((_a = error.details) === null || _a === void 0 ? void 0 : _a.tenantId) && ((_b = error.details) === null || _b === void 0 ? void 0 : _b.environmentId)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (((_c = context === null || context === void 0 ? void 0 : context.subject) === null || _c === void 0 ? void 0 : _c.tenantId) && ((_d = context === null || context === void 0 ? void 0 : context.subject) === null || _d === void 0 ? void 0 : _d.environmentId)) {
|
|
46
|
+
error.details = Object.assign({ tenantId: context.subject.tenantId, environmentId: context.subject.environmentId }, ((_e = error.details) !== null && _e !== void 0 ? _e : {}));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
39
49
|
}
|
|
40
50
|
exports.GuardedTransactionalInboxMessageHandler = GuardedTransactionalInboxMessageHandler;
|
|
41
51
|
//# sourceMappingURL=guarded-transactional-inbox-message-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guarded-transactional-inbox-message-handler.js","sourceRoot":"","sources":["../../src/message-bus/guarded-transactional-inbox-message-handler.ts"],"names":[],"mappings":";;;AACA,yEAIuC;AACvC,iGAImD;
|
|
1
|
+
{"version":3,"file":"guarded-transactional-inbox-message-handler.js","sourceRoot":"","sources":["../../src/message-bus/guarded-transactional-inbox-message-handler.ts"],"names":[],"mappings":";;;AACA,yEAIuC;AACvC,iGAImD;AAGnD,sCAKmB;AACnB,+EAAiE;AASjE,MAAsB,uCAGpB,SAAQ,oEAAmE;IAC3E;;;;;;;;OAQG;IACH,YACE,iBAAoC,EAC1B,WAAqB,EAC/B,MAAc,EACd,MAAe,EACP,UAAyC;QAEjD,MAAM,OAAO,GAAG,KAAK,EACnB,OAA4C,EAC5C,cAA0B,EACD,EAAE;YAC3B,OAAO,IAAI,CAAC,wBAAwB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QAChE,CAAC,CAAC;QACF,KAAK,CAAC,iBAAiB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAXxC,gBAAW,GAAX,WAAW,CAAU;QAGvB,eAAU,GAAV,UAAU,CAA+B;QAWzC,6BAAwB,GAAG,KAAK,EACxC,OAA4C,EAC5C,cAA0B,EACD,EAAE;YAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;YACzC,IAAI,KAAK,KAAK,SAAS,EAAE;gBACvB,MAAM,IAAI,mCAAW,CAAC,sBAAa,CAAC,mBAAmB,CAAC,CAAC;aAC1D;YACD,MAAM,OAAO,GAAG,MAAM,IAAA,0CAAiC,EACrD,KAAK,EACL,IAAI,CAAC,UAAU,CAChB,CAAC;YACF,MAAM,IAAA,8CAAgB,EAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACzE,IAAI,CAAC,aAAa,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;YAC5C,OAAO,EAAE,OAAO,EAAE,CAAC;QACrB,CAAC,CAAC;IAjBF,CAAC;IAkCQ,QAAQ,CAAC,KAAY;QAC5B,OAAO,IAAA,sCAAc,EAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAEkB,kBAAkB,CACnC,KAAoD,EACpD,OAAqB,EACrB,OAAwB;;QAExB,KAAK,CAAC,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAA,MAAA,KAAK,CAAC,OAAO,0CAAE,QAAQ,MAAI,MAAA,KAAK,CAAC,OAAO,0CAAE,aAAa,CAAA,EAAE;YAC3D,OAAO;SACR;QAED,IAAI,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,0CAAE,QAAQ,MAAI,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,0CAAE,aAAa,CAAA,EAAE;YACjE,KAAK,CAAC,OAAO,mBACX,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,EAClC,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC,aAAa,IACzC,CAAC,MAAA,KAAK,CAAC,OAAO,mCAAI,EAAE,CAAC,CACzB,CAAC;SACH;IACH,CAAC;CACF;AAnFD,0FAmFC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-id-guard",
|
|
3
|
-
"version": "0.26.0
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Authentication and authorization helpers for Axinom Mosaic services",
|
|
5
5
|
"author": "Axinom",
|
|
6
6
|
"license": "PROPRIETARY",
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
"dev": "tsc -w",
|
|
23
23
|
"test": "jest --silent",
|
|
24
24
|
"test:watch": "jest --watch --silent",
|
|
25
|
-
"test:cov": "jest --coverage --silent",
|
|
26
|
-
"posttest:cov": "ts-node
|
|
25
|
+
"test:cov": "jest --coverage --silent && yarn posttest:cov",
|
|
26
|
+
"posttest:cov": "ts-node ../../../scripts/open-test-coverage.ts -- services/id/lib-id-guard",
|
|
27
27
|
"test:ci": "jest --reporters=default --reporters=jest-junit --coverage --coverageReporters=cobertura --coverageReporters=html",
|
|
28
28
|
"lint": "eslint . --ext .ts,.tsx,.js --color --cache"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@axinom/mosaic-id-utils": "^0.15.11
|
|
32
|
-
"@axinom/mosaic-message-bus": "^0.21.0
|
|
33
|
-
"@axinom/mosaic-service-common": "^0.43.0
|
|
34
|
-
"@axinom/mosaic-transactional-inbox-outbox": "^0.3.0
|
|
31
|
+
"@axinom/mosaic-id-utils": "^0.15.11",
|
|
32
|
+
"@axinom/mosaic-message-bus": "^0.21.0",
|
|
33
|
+
"@axinom/mosaic-service-common": "^0.43.0",
|
|
34
|
+
"@axinom/mosaic-transactional-inbox-outbox": "^0.3.0",
|
|
35
35
|
"amqplib": "^0.10.3",
|
|
36
36
|
"express": "^4.17.1",
|
|
37
37
|
"express-bearer-token": "^2.4.0",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"jwks-rsa": "^1.8.1",
|
|
45
45
|
"lru-cache": "^7.18.3",
|
|
46
46
|
"pg": "^8.11.3",
|
|
47
|
+
"pg-transactional-outbox": "^0.4.0-beta.11",
|
|
47
48
|
"postgraphile": "^4.13.0",
|
|
48
49
|
"rascal": "^14.0.1",
|
|
49
50
|
"subscriptions-transport-ws": "^0.9.19"
|
|
@@ -63,5 +64,5 @@
|
|
|
63
64
|
"publishConfig": {
|
|
64
65
|
"access": "public"
|
|
65
66
|
},
|
|
66
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "e583a1076964626d1d0b1f9fb507d1defc307102"
|
|
67
68
|
}
|
|
@@ -5,7 +5,11 @@ import {
|
|
|
5
5
|
import jwt from 'jsonwebtoken';
|
|
6
6
|
import * as jwks from 'jwks-rsa';
|
|
7
7
|
import { IdGuardErrors } from '../id-guard-errors';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
AuthenticatedEndUser,
|
|
10
|
+
AuthenticatedManagementSubject,
|
|
11
|
+
AuthenticationConfig,
|
|
12
|
+
} from '../types';
|
|
9
13
|
|
|
10
14
|
// Type for JWT parse error codes
|
|
11
15
|
type JwtErrors =
|
|
@@ -26,28 +30,34 @@ type JwtErrors =
|
|
|
26
30
|
* @param errorCode a value from the IdGuardErrors
|
|
27
31
|
* @param authType Auth Type - 'MANAGEMENT' | 'END_USER'
|
|
28
32
|
* @param token JWT Token
|
|
33
|
+
* @param authConfig an object with ID/User service connection information or a path to a public key file.
|
|
29
34
|
* @returns
|
|
30
35
|
*/
|
|
31
36
|
const buildJwtErrorMessage = (
|
|
32
37
|
errorCode: JwtErrors,
|
|
33
38
|
authType: 'MANAGEMENT' | 'END_USER' | undefined,
|
|
34
39
|
token: string,
|
|
40
|
+
authConfig: string | AuthenticationConfig,
|
|
35
41
|
): string => {
|
|
36
42
|
let message = '';
|
|
37
43
|
switch (errorCode) {
|
|
38
44
|
case IdGuardErrors.SigningKeyNotFound.code: {
|
|
39
45
|
const decodedToken = jwt.decode(token);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
|
|
47
|
+
if (typeof authConfig === 'string') {
|
|
48
|
+
message = `Could not find a matching signing key to verify the token used in the request. Please try again with a new token or contact Axinom support if the problem persists.`;
|
|
49
|
+
} else {
|
|
50
|
+
if (
|
|
51
|
+
(decodedToken as AuthenticatedManagementSubject).tenantId !==
|
|
52
|
+
authConfig.tenantId ||
|
|
53
|
+
(decodedToken as AuthenticatedManagementSubject).environmentId !==
|
|
54
|
+
authConfig.environmentId
|
|
55
|
+
) {
|
|
56
|
+
message = `The service is configured to work with a different Tenant ID/Environment ID than found in the token.`;
|
|
57
|
+
} else {
|
|
58
|
+
message = `Could not find a matching signing key to verify the token used in the request. The token's signing key may have been revoked. Please try again with a new token.`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
51
61
|
break;
|
|
52
62
|
}
|
|
53
63
|
case IdGuardErrors.JwksError.code: {
|
|
@@ -99,38 +109,73 @@ const buildJwtErrorMessage = (
|
|
|
99
109
|
* @param err Error of type unknown
|
|
100
110
|
* @param authType Auth Type - 'MANAGEMENT' | 'END_USER'
|
|
101
111
|
* @param token JWT token
|
|
112
|
+
* @param authConfig an object with ID/User service connection information or a path to a public key file.
|
|
102
113
|
* @returns [code, message, originalError]
|
|
103
114
|
*/
|
|
104
115
|
export const handleJwtParseError = (
|
|
105
116
|
err: unknown,
|
|
106
117
|
authType: 'MANAGEMENT' | 'END_USER' | undefined,
|
|
107
118
|
token: string,
|
|
108
|
-
|
|
119
|
+
authConfig: string | AuthenticationConfig,
|
|
120
|
+
): [
|
|
121
|
+
code: JwtErrors,
|
|
122
|
+
message: string,
|
|
123
|
+
originalError: Error | undefined,
|
|
124
|
+
details: string | Record<string, unknown> | undefined,
|
|
125
|
+
] => {
|
|
109
126
|
let code: JwtErrors | undefined;
|
|
110
127
|
let message: string | undefined;
|
|
111
128
|
let originalError: Error | undefined;
|
|
129
|
+
let details: string | Record<string, unknown> | undefined;
|
|
112
130
|
|
|
113
131
|
if (err instanceof jwt.TokenExpiredError) {
|
|
114
132
|
code = IdGuardErrors.AccessTokenExpired.code;
|
|
115
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
133
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
116
134
|
} else if (err instanceof jwks.SigningKeyNotFoundError) {
|
|
117
135
|
code = IdGuardErrors.SigningKeyNotFound.code;
|
|
118
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
136
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
137
|
+
|
|
138
|
+
const decodedToken = jwt.decode(token);
|
|
139
|
+
|
|
140
|
+
if (typeof authConfig === 'string') {
|
|
141
|
+
details = {
|
|
142
|
+
tokenKid: (decodedToken as jwt.JwtHeader).kid,
|
|
143
|
+
};
|
|
144
|
+
} else {
|
|
145
|
+
if (
|
|
146
|
+
(decodedToken as AuthenticatedManagementSubject).tenantId !==
|
|
147
|
+
authConfig.tenantId ||
|
|
148
|
+
(decodedToken as AuthenticatedManagementSubject).environmentId !==
|
|
149
|
+
authConfig.environmentId
|
|
150
|
+
) {
|
|
151
|
+
details = {
|
|
152
|
+
service: {
|
|
153
|
+
tenantId: authConfig.tenantId,
|
|
154
|
+
environmentId: authConfig.environmentId,
|
|
155
|
+
},
|
|
156
|
+
token: {
|
|
157
|
+
tenantId: (decodedToken as AuthenticatedManagementSubject).tenantId,
|
|
158
|
+
environmentId: (decodedToken as AuthenticatedManagementSubject)
|
|
159
|
+
.environmentId,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
119
164
|
} else if (err instanceof jwks.JwksError) {
|
|
120
165
|
code = IdGuardErrors.JwksError.code;
|
|
121
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
166
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
122
167
|
} else if ((err as { code?: string }).code === 'ECONNREFUSED') {
|
|
123
168
|
code =
|
|
124
169
|
authType === 'END_USER'
|
|
125
170
|
? IdGuardErrors.UserServiceNotAccessible.code
|
|
126
171
|
: IdGuardErrors.IdentityServiceNotAccessible.code;
|
|
127
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
172
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
128
173
|
} else if (err instanceof SyntaxError) {
|
|
129
174
|
code = IdGuardErrors.MalformedToken.code;
|
|
130
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
175
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
131
176
|
} else {
|
|
132
177
|
code = IdGuardErrors.AccessTokenVerificationFailed.code;
|
|
133
|
-
message = buildJwtErrorMessage(code, authType, token);
|
|
178
|
+
message = buildJwtErrorMessage(code, authType, token, authConfig);
|
|
134
179
|
}
|
|
135
180
|
|
|
136
181
|
// If thrown error is an instance of Error, take that as the original error. If not, create a new NonMosaicError and encapsulate the unknown error in it
|
|
@@ -139,5 +184,5 @@ export const handleJwtParseError = (
|
|
|
139
184
|
} else {
|
|
140
185
|
originalError = new NonMosaicError(err);
|
|
141
186
|
}
|
|
142
|
-
return [code, message, originalError];
|
|
187
|
+
return [code, message, originalError, details];
|
|
143
188
|
};
|
|
@@ -353,50 +353,80 @@ describe('parse-jwt-token', () => {
|
|
|
353
353
|
},
|
|
354
354
|
);
|
|
355
355
|
|
|
356
|
-
it.
|
|
357
|
-
{
|
|
358
|
-
tenantId,
|
|
359
|
-
environmentId,
|
|
356
|
+
it('When authType is MANAGEMENT and Could not find a matching signing key, getAuthenticatedManagementSubject throws a jwks.SigningKeyNotFoundError, a SIGNING_KEY_NOT_FOUND error is raised', async () => {
|
|
357
|
+
const authenticationConfig = {
|
|
358
|
+
tenantId: tenantId,
|
|
359
|
+
environmentId: environmentId,
|
|
360
360
|
authEndpoint: 'https://id.mosaic.axinom.net',
|
|
361
|
-
}
|
|
362
|
-
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const getAuthenticatedManagementSubjectMock = jest.spyOn(
|
|
364
|
+
getAuthenticatedSubject,
|
|
365
|
+
'getAuthenticatedManagementSubject',
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
getAuthenticatedManagementSubjectMock.mockImplementation(
|
|
369
|
+
(_token, _authParams) => {
|
|
370
|
+
throw new SigningKeyNotFoundError('Signing Key Not Found');
|
|
371
|
+
},
|
|
372
|
+
);
|
|
373
|
+
const authContext = await parseJwtToken(
|
|
374
|
+
RS256ManagementUserToken,
|
|
375
|
+
authenticationConfig,
|
|
376
|
+
'MANAGEMENT',
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
expect(authContext.authErrorInfo).toBeDefined();
|
|
380
|
+
expect(authContext.subject).toBeUndefined();
|
|
381
|
+
expect(getAuthenticatedManagementSubjectMock).toHaveBeenCalledTimes(1);
|
|
382
|
+
|
|
383
|
+
expect(authContext.authErrorInfo).toMatchObject({
|
|
384
|
+
code: 'SIGNING_KEY_NOT_FOUND',
|
|
385
|
+
message: `Could not find a matching signing key to verify the token used in the request. The token's signing key may have been revoked. Please try again with a new token.`,
|
|
386
|
+
error: {
|
|
387
|
+
name: 'SigningKeyNotFoundError',
|
|
388
|
+
message: 'Signing Key Not Found',
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
getAuthenticatedManagementSubjectMock.mockRestore();
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('When authType is MANAGEMENT and Tenant ID/Environment ID is different, getAuthenticatedManagementSubject throws a jwks.SigningKeyNotFoundError, a SIGNING_KEY_NOT_FOUND error is raised', async () => {
|
|
396
|
+
const authenticationConfig = {
|
|
363
397
|
tenantId: '',
|
|
364
398
|
environmentId: '',
|
|
365
399
|
authEndpoint: 'https://id.mosaic.axinom.net',
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
getAuthenticatedSubject,
|
|
372
|
-
'getAuthenticatedManagementSubject',
|
|
373
|
-
);
|
|
400
|
+
};
|
|
401
|
+
const getAuthenticatedManagementSubjectMock = jest.spyOn(
|
|
402
|
+
getAuthenticatedSubject,
|
|
403
|
+
'getAuthenticatedManagementSubject',
|
|
404
|
+
);
|
|
374
405
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
406
|
+
getAuthenticatedManagementSubjectMock.mockImplementation(
|
|
407
|
+
(_token, _authParams) => {
|
|
408
|
+
throw new SigningKeyNotFoundError('Signing Key Not Found');
|
|
409
|
+
},
|
|
410
|
+
);
|
|
411
|
+
const authContext = await parseJwtToken(
|
|
412
|
+
RS256ManagementUserToken,
|
|
413
|
+
authenticationConfig,
|
|
414
|
+
'MANAGEMENT',
|
|
415
|
+
);
|
|
385
416
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
);
|
|
417
|
+
expect(authContext.authErrorInfo).toBeDefined();
|
|
418
|
+
expect(authContext.subject).toBeUndefined();
|
|
419
|
+
expect(getAuthenticatedManagementSubjectMock).toHaveBeenCalledTimes(1);
|
|
420
|
+
expect(authContext.authErrorInfo).toMatchObject({
|
|
421
|
+
code: 'SIGNING_KEY_NOT_FOUND',
|
|
422
|
+
message: `The service is configured to work with a different Tenant ID/Environment ID than found in the token.`,
|
|
423
|
+
error: {
|
|
424
|
+
name: 'SigningKeyNotFoundError',
|
|
425
|
+
message: 'Signing Key Not Found',
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
getAuthenticatedManagementSubjectMock.mockRestore();
|
|
429
|
+
});
|
|
400
430
|
|
|
401
431
|
it.each([
|
|
402
432
|
{
|
|
@@ -614,50 +644,75 @@ describe('parse-jwt-token', () => {
|
|
|
614
644
|
getAuthenticatedEndUserMock.mockRestore();
|
|
615
645
|
});
|
|
616
646
|
|
|
617
|
-
it.
|
|
618
|
-
{
|
|
619
|
-
tenantId,
|
|
620
|
-
environmentId,
|
|
647
|
+
it('When authType is END_USER and Could not find a matching signing key, getAuthenticatedEndUser throws a jwks.SigningKeyNotFoundError, a SIGNING_KEY_NOT_FOUND error is raised', async () => {
|
|
648
|
+
const authenticationConfig = {
|
|
649
|
+
tenantId: tenantId,
|
|
650
|
+
environmentId: environmentId,
|
|
621
651
|
authEndpoint: 'https://id.mosaic.axinom.net',
|
|
622
|
-
}
|
|
623
|
-
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
const getAuthenticatedEndUserMock = jest.spyOn(
|
|
655
|
+
getAuthenticatedSubject,
|
|
656
|
+
'getAuthenticatedEndUser',
|
|
657
|
+
);
|
|
658
|
+
|
|
659
|
+
getAuthenticatedEndUserMock.mockImplementation((_token, _authParams) => {
|
|
660
|
+
throw new SigningKeyNotFoundError('Signing Key Not Found');
|
|
661
|
+
});
|
|
662
|
+
const authContext = await parseJwtToken(
|
|
663
|
+
RS256EndUserToken,
|
|
664
|
+
authenticationConfig,
|
|
665
|
+
'END_USER',
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
expect(authContext.authErrorInfo).toBeDefined();
|
|
669
|
+
expect(authContext.subject).toBeUndefined();
|
|
670
|
+
expect(getAuthenticatedEndUserMock).toHaveBeenCalledTimes(1);
|
|
671
|
+
expect(authContext.authErrorInfo).toMatchObject({
|
|
672
|
+
code: 'SIGNING_KEY_NOT_FOUND',
|
|
673
|
+
message: `Could not find a matching signing key to verify the token used in the request. The token's signing key may have been revoked. Please try again with a new token.`,
|
|
674
|
+
error: {
|
|
675
|
+
name: 'SigningKeyNotFoundError',
|
|
676
|
+
message: 'Signing Key Not Found',
|
|
677
|
+
},
|
|
678
|
+
});
|
|
679
|
+
getAuthenticatedEndUserMock.mockRestore();
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
it('When authType is END_USER and Tenant ID/Environment ID is different, getAuthenticatedEndUser throws a jwks.SigningKeyNotFoundError, a SIGNING_KEY_NOT_FOUND error is raised', async () => {
|
|
683
|
+
const authenticationConfig = {
|
|
624
684
|
tenantId: '',
|
|
625
685
|
environmentId: '',
|
|
626
686
|
authEndpoint: 'https://id.mosaic.axinom.net',
|
|
627
|
-
}
|
|
628
|
-
])(
|
|
629
|
-
'When authType is END_USER and getAuthenticatedEndUser throws a jwks.SigningKeyNotFoundError, a SIGNING_KEY_NOT_FOUND error is raised',
|
|
630
|
-
async (authenticationConfig) => {
|
|
631
|
-
const getAuthenticatedEndUserMock = jest.spyOn(
|
|
632
|
-
getAuthenticatedSubject,
|
|
633
|
-
'getAuthenticatedEndUser',
|
|
634
|
-
);
|
|
687
|
+
};
|
|
635
688
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
);
|
|
641
|
-
const authContext = await parseJwtToken(
|
|
642
|
-
RS256EndUserToken,
|
|
643
|
-
authenticationConfig,
|
|
644
|
-
'END_USER',
|
|
645
|
-
);
|
|
689
|
+
const getAuthenticatedEndUserMock = jest.spyOn(
|
|
690
|
+
getAuthenticatedSubject,
|
|
691
|
+
'getAuthenticatedEndUser',
|
|
692
|
+
);
|
|
646
693
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
694
|
+
getAuthenticatedEndUserMock.mockImplementation((_token, _authParams) => {
|
|
695
|
+
throw new SigningKeyNotFoundError('Signing Key Not Found');
|
|
696
|
+
});
|
|
697
|
+
const authContext = await parseJwtToken(
|
|
698
|
+
RS256EndUserToken,
|
|
699
|
+
authenticationConfig,
|
|
700
|
+
'END_USER',
|
|
701
|
+
);
|
|
702
|
+
|
|
703
|
+
expect(authContext.authErrorInfo).toBeDefined();
|
|
704
|
+
expect(authContext.subject).toBeUndefined();
|
|
705
|
+
expect(getAuthenticatedEndUserMock).toHaveBeenCalledTimes(1);
|
|
706
|
+
expect(authContext.authErrorInfo).toMatchObject({
|
|
707
|
+
code: 'SIGNING_KEY_NOT_FOUND',
|
|
708
|
+
message: `The service is configured to work with a different Tenant ID/Environment ID than found in the token.`,
|
|
709
|
+
error: {
|
|
710
|
+
name: 'SigningKeyNotFoundError',
|
|
711
|
+
message: 'Signing Key Not Found',
|
|
712
|
+
},
|
|
713
|
+
});
|
|
714
|
+
getAuthenticatedEndUserMock.mockRestore();
|
|
715
|
+
});
|
|
661
716
|
|
|
662
717
|
it.each([
|
|
663
718
|
{
|
|
@@ -37,6 +37,7 @@ export const parseJwtToken = async (
|
|
|
37
37
|
let code: string | undefined;
|
|
38
38
|
let message: string | undefined;
|
|
39
39
|
let originalError: Error | undefined;
|
|
40
|
+
let details: string | Record<string, unknown> | undefined;
|
|
40
41
|
let subject:
|
|
41
42
|
| AuthenticatedManagementSubject
|
|
42
43
|
| AuthenticatedEndUser
|
|
@@ -71,10 +72,11 @@ export const parseJwtToken = async (
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
} catch (err) {
|
|
74
|
-
[code, message, originalError] = handleJwtParseError(
|
|
75
|
+
[code, message, originalError, details] = handleJwtParseError(
|
|
75
76
|
err,
|
|
76
77
|
authType,
|
|
77
78
|
token,
|
|
79
|
+
authConfig,
|
|
78
80
|
);
|
|
79
81
|
}
|
|
80
82
|
} else {
|
|
@@ -92,6 +94,7 @@ export const parseJwtToken = async (
|
|
|
92
94
|
code,
|
|
93
95
|
message,
|
|
94
96
|
error: originalError,
|
|
97
|
+
details: { details },
|
|
95
98
|
};
|
|
96
99
|
}
|
|
97
100
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BasicConfig } from '@axinom/mosaic-service-common';
|
|
1
2
|
import { Plugin } from 'graphile-build';
|
|
2
3
|
import { makePluginByCombiningPlugins } from 'graphile-utils';
|
|
3
4
|
import { PermissionDefinitionExporterPlugin } from './generate-permissions-file-plugin';
|
|
@@ -29,10 +30,11 @@ import { SubscriptionGuardPlugin } from './subscription-guard-plugin';
|
|
|
29
30
|
* @returns
|
|
30
31
|
*/
|
|
31
32
|
export const AxGuardPlugin = (
|
|
33
|
+
config?: BasicConfig,
|
|
32
34
|
permissionDefinitionExportPath?: string,
|
|
33
35
|
): Plugin => {
|
|
34
36
|
return makePluginByCombiningPlugins(
|
|
35
|
-
PermissionDefinitionExporterPlugin(permissionDefinitionExportPath),
|
|
37
|
+
PermissionDefinitionExporterPlugin(config, permissionDefinitionExportPath),
|
|
36
38
|
QueryMutationGuardPlugin,
|
|
37
39
|
SubscriptionGuardPlugin,
|
|
38
40
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
+
import { BasicConfig } from 'libs/service-common/dist';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import { Plugin } from 'postgraphile';
|
|
4
5
|
|
|
@@ -8,21 +9,24 @@ import { Plugin } from 'postgraphile';
|
|
|
8
9
|
* @returns
|
|
9
10
|
*/
|
|
10
11
|
export function PermissionDefinitionExporterPlugin(
|
|
12
|
+
config?: BasicConfig,
|
|
11
13
|
permissionDefinitionExportPath?: string,
|
|
12
14
|
): Plugin {
|
|
13
15
|
return (builder, options) => {
|
|
14
16
|
// Write permissions to file when the schema is built.
|
|
15
17
|
builder.hook('finalize', (schema, _build, _context) => {
|
|
16
|
-
if (
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
if (config?.isDev) {
|
|
19
|
+
if (permissionDefinitionExportPath !== undefined) {
|
|
20
|
+
if (options.permissionDefinition === undefined) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
'When a permissionDefinitionExportPath is provided to AxGuard Plugin, permissionDefinition must be defined in the Postgraphile options.',
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
writeSourceFile(
|
|
26
|
+
permissionDefinitionExportPath,
|
|
27
|
+
JSON.stringify(options.permissionDefinition, null, 2),
|
|
20
28
|
);
|
|
21
29
|
}
|
|
22
|
-
writeSourceFile(
|
|
23
|
-
permissionDefinitionExportPath,
|
|
24
|
-
JSON.stringify(options.permissionDefinition, null, 2),
|
|
25
|
-
);
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
return schema;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import 'jest-extended';
|
|
3
|
+
import { GuardedTransactionalInboxMessageHandler } from './guarded-transactional-inbox-message-handler';
|
|
4
|
+
|
|
5
|
+
class TestTransactionalInboxMessageHandler extends GuardedTransactionalInboxMessageHandler<
|
|
6
|
+
any,
|
|
7
|
+
any
|
|
8
|
+
> {
|
|
9
|
+
override handleMessage(): Promise<void> {
|
|
10
|
+
throw new Error('Method not implemented.');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
override setPgSettings(): Promise<void> {
|
|
14
|
+
throw new Error('Method not implemented.');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe('GuardedTransactionalInboxMessageHandler', () => {
|
|
19
|
+
const handler = new TestTransactionalInboxMessageHandler(
|
|
20
|
+
{} as any,
|
|
21
|
+
[],
|
|
22
|
+
{} as any,
|
|
23
|
+
{} as any,
|
|
24
|
+
{} as any,
|
|
25
|
+
) as any; // To access protected method for testing
|
|
26
|
+
|
|
27
|
+
describe('updateErrorDetails', () => {
|
|
28
|
+
it('Update error details with empty message object -> returns original error', () => {
|
|
29
|
+
// Arrange
|
|
30
|
+
const originalError = new Error('Test Message');
|
|
31
|
+
const message = {} as any;
|
|
32
|
+
|
|
33
|
+
// Act
|
|
34
|
+
handler.updateErrorDetails(originalError, message);
|
|
35
|
+
|
|
36
|
+
// Assert
|
|
37
|
+
expect(originalError).toMatchObject({
|
|
38
|
+
message: 'Test Message',
|
|
39
|
+
stack: expect.toStartWith('Error: Test Message'),
|
|
40
|
+
});
|
|
41
|
+
expect((originalError as any).details).toBeUndefined();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it.each([undefined, null])(
|
|
45
|
+
'Update error details with %p routingKey -> returns original error',
|
|
46
|
+
(falsyKey) => {
|
|
47
|
+
// Arrange
|
|
48
|
+
const originalError = new Error('Test Message');
|
|
49
|
+
const message = {
|
|
50
|
+
metadata: { fields: { routingKey: falsyKey } },
|
|
51
|
+
} as any;
|
|
52
|
+
|
|
53
|
+
// Act
|
|
54
|
+
handler.updateErrorDetails(originalError, message);
|
|
55
|
+
|
|
56
|
+
// Assert
|
|
57
|
+
expect(originalError).toMatchObject({
|
|
58
|
+
message: 'Test Message',
|
|
59
|
+
stack: expect.toStartWith('Error: Test Message'),
|
|
60
|
+
});
|
|
61
|
+
expect((originalError as any).details).toBeUndefined();
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
it('Update error details with valid routingKey -> returns extended error', () => {
|
|
66
|
+
// Arrange
|
|
67
|
+
const tenantId = '00000000-0000-0000-0000-000000000001';
|
|
68
|
+
const environmentId = '00000000-0000-0000-0000-000000000002';
|
|
69
|
+
const originalError = new Error('Test Message');
|
|
70
|
+
const message = {
|
|
71
|
+
metadata: {
|
|
72
|
+
fields: {
|
|
73
|
+
routingKey: `ax-image-service.${tenantId}.${environmentId}.image_types.declare`,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
} as any;
|
|
77
|
+
|
|
78
|
+
// Act
|
|
79
|
+
handler.updateErrorDetails(originalError, message);
|
|
80
|
+
|
|
81
|
+
// Assert
|
|
82
|
+
expect(originalError).toMatchObject({
|
|
83
|
+
message: 'Test Message',
|
|
84
|
+
stack: expect.toStartWith('Error: Test Message'),
|
|
85
|
+
details: {
|
|
86
|
+
tenantId,
|
|
87
|
+
environmentId,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('Update error details with valid routingKey and existing details -> returns extended error preserving details', () => {
|
|
93
|
+
// Arrange
|
|
94
|
+
const tenantId = '00000000-0000-0000-0000-000000000001';
|
|
95
|
+
const environmentId = '00000000-0000-0000-0000-000000000002';
|
|
96
|
+
const originalError = new Error('Test Message') as Error & {
|
|
97
|
+
details?: Record<string, string>;
|
|
98
|
+
};
|
|
99
|
+
originalError.details = { custom: 'custom details property' };
|
|
100
|
+
const message = {
|
|
101
|
+
metadata: {
|
|
102
|
+
fields: {
|
|
103
|
+
routingKey: `ax-image-service.${tenantId}.${environmentId}.image_types.declare`,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
} as any;
|
|
107
|
+
|
|
108
|
+
// Act
|
|
109
|
+
handler.updateErrorDetails(originalError, message);
|
|
110
|
+
|
|
111
|
+
// Assert
|
|
112
|
+
expect(originalError).toMatchObject({
|
|
113
|
+
message: 'Test Message',
|
|
114
|
+
stack: expect.toStartWith('Error: Test Message'),
|
|
115
|
+
details: {
|
|
116
|
+
tenantId,
|
|
117
|
+
environmentId,
|
|
118
|
+
custom: 'custom details property',
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('Update error details with empty routingKey and existing details -> returns original error preserving details', () => {
|
|
124
|
+
// Arrange
|
|
125
|
+
const originalError = new Error('Test Message') as Error & {
|
|
126
|
+
details?: Record<string, string>;
|
|
127
|
+
};
|
|
128
|
+
originalError.details = { custom: 'custom details property' };
|
|
129
|
+
const message = { metadata: { fields: {} } } as any;
|
|
130
|
+
|
|
131
|
+
// Act
|
|
132
|
+
handler.updateErrorDetails(originalError, message);
|
|
133
|
+
|
|
134
|
+
// Assert
|
|
135
|
+
expect(originalError).toMatchObject({
|
|
136
|
+
message: 'Test Message',
|
|
137
|
+
stack: expect.toStartWith('Error: Test Message'),
|
|
138
|
+
details: {
|
|
139
|
+
custom: 'custom details property',
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('Update error details with empty routingKey, existing details, and context having subject -> returns extended error preserving details', () => {
|
|
145
|
+
// Arrange
|
|
146
|
+
const tenantId = '00000000-0000-0000-0000-000000000001';
|
|
147
|
+
const environmentId = '00000000-0000-0000-0000-000000000002';
|
|
148
|
+
const originalError = new Error('Test Message') as Error & {
|
|
149
|
+
details?: Record<string, string>;
|
|
150
|
+
};
|
|
151
|
+
originalError.details = { custom: 'custom details property' };
|
|
152
|
+
const message = { metadata: { fields: {} } } as any;
|
|
153
|
+
const context = { subject: { tenantId, environmentId } } as any;
|
|
154
|
+
|
|
155
|
+
// Act
|
|
156
|
+
handler.updateErrorDetails(originalError, message, context);
|
|
157
|
+
|
|
158
|
+
// Assert
|
|
159
|
+
expect(originalError).toMatchObject({
|
|
160
|
+
message: 'Test Message',
|
|
161
|
+
stack: expect.toStartWith('Error: Test Message'),
|
|
162
|
+
details: {
|
|
163
|
+
tenantId,
|
|
164
|
+
environmentId,
|
|
165
|
+
custom: 'custom details property',
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
TransactionalInboxMessageHandler,
|
|
11
11
|
} from '@axinom/mosaic-transactional-inbox-outbox';
|
|
12
12
|
import { ClientBase } from 'pg';
|
|
13
|
+
import { InboxMessage } from 'pg-transactional-outbox';
|
|
13
14
|
import {
|
|
14
15
|
AuthenticatedManagementSubject,
|
|
15
16
|
AuthenticationConfig,
|
|
@@ -89,4 +90,23 @@ export abstract class GuardedTransactionalInboxMessageHandler<
|
|
|
89
90
|
override mapError(error: Error): Error {
|
|
90
91
|
return getMappedError(error);
|
|
91
92
|
}
|
|
93
|
+
|
|
94
|
+
protected override updateErrorDetails(
|
|
95
|
+
error: Error & { details?: Record<string, unknown> },
|
|
96
|
+
message: InboxMessage,
|
|
97
|
+
context?: GuardedContext,
|
|
98
|
+
): void {
|
|
99
|
+
super.updateErrorDetails(error, message, context);
|
|
100
|
+
if (error.details?.tenantId && error.details?.environmentId) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (context?.subject?.tenantId && context?.subject?.environmentId) {
|
|
105
|
+
error.details = {
|
|
106
|
+
tenantId: context.subject.tenantId,
|
|
107
|
+
environmentId: context.subject.environmentId,
|
|
108
|
+
...(error.details ?? {}),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
92
112
|
}
|