@node-c/domain-iam 1.0.0-alpha9 → 1.0.0-beta1

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.
Files changed (104) hide show
  1. package/dist/common/definitions/common.constants.d.ts +7 -1
  2. package/dist/common/definitions/common.constants.js +6 -0
  3. package/dist/common/definitions/common.constants.js.map +1 -1
  4. package/dist/module/iam.module.js.map +1 -1
  5. package/dist/services/authentication/iam.authentication.definitions.d.ts +79 -16
  6. package/dist/services/authentication/iam.authentication.definitions.js +6 -9
  7. package/dist/services/authentication/iam.authentication.definitions.js.map +1 -1
  8. package/dist/services/authentication/iam.authentication.service.d.ts +13 -5
  9. package/dist/services/authentication/iam.authentication.service.js +32 -3
  10. package/dist/services/authentication/iam.authentication.service.js.map +1 -1
  11. package/dist/services/authenticationOAuth2/iam.authenticationOAuth2.definitions.d.ts +38 -0
  12. package/dist/services/{authenticationLocal/iam.authenticationLocal.definitions.js → authenticationOAuth2/iam.authenticationOAuth2.definitions.js} +1 -1
  13. package/dist/services/authenticationOAuth2/iam.authenticationOAuth2.definitions.js.map +1 -0
  14. package/dist/services/authenticationOAuth2/iam.authenticationOAuth2.service.d.ts +25 -0
  15. package/dist/services/authenticationOAuth2/iam.authenticationOAuth2.service.js +300 -0
  16. package/dist/services/authenticationOAuth2/iam.authenticationOAuth2.service.js.map +1 -0
  17. package/dist/services/authenticationOAuth2/index.d.ts +2 -0
  18. package/dist/services/authenticationOAuth2/index.js +19 -0
  19. package/dist/services/authenticationOAuth2/index.js.map +1 -0
  20. package/dist/services/authenticationUserLocal/iam.authenticationUserLocal.definitions.d.ts +12 -0
  21. package/dist/services/authenticationUserLocal/iam.authenticationUserLocal.definitions.js +3 -0
  22. package/dist/services/authenticationUserLocal/iam.authenticationUserLocal.definitions.js.map +1 -0
  23. package/dist/services/authenticationUserLocal/iam.authenticationUserLocal.service.d.ts +15 -0
  24. package/dist/services/authenticationUserLocal/iam.authenticationUserLocal.service.js +142 -0
  25. package/dist/services/authenticationUserLocal/iam.authenticationUserLocal.service.js.map +1 -0
  26. package/dist/services/authenticationUserLocal/index.d.ts +2 -0
  27. package/dist/services/{authenticationLocal → authenticationUserLocal}/index.js +2 -2
  28. package/dist/services/authenticationUserLocal/index.js.map +1 -0
  29. package/dist/services/authorization/iam.authorization.definitions.d.ts +33 -23
  30. package/dist/services/authorization/iam.authorization.definitions.js +7 -0
  31. package/dist/services/authorization/iam.authorization.definitions.js.map +1 -1
  32. package/dist/services/authorization/iam.authorization.service.d.ts +29 -13
  33. package/dist/services/authorization/iam.authorization.service.js +233 -125
  34. package/dist/services/authorization/iam.authorization.service.js.map +1 -1
  35. package/dist/services/index.d.ts +4 -2
  36. package/dist/services/index.js +4 -2
  37. package/dist/services/index.js.map +1 -1
  38. package/dist/services/mfa/iam.mfa.definitions.d.ts +21 -0
  39. package/dist/services/mfa/iam.mfa.definitions.js +8 -0
  40. package/dist/services/mfa/iam.mfa.definitions.js.map +1 -0
  41. package/dist/services/mfa/iam.mfa.service.d.ts +10 -0
  42. package/dist/services/mfa/iam.mfa.service.js +32 -0
  43. package/dist/services/mfa/iam.mfa.service.js.map +1 -0
  44. package/dist/services/mfa/index.d.ts +2 -0
  45. package/dist/services/{users → mfa}/index.js +2 -2
  46. package/dist/services/mfa/index.js.map +1 -0
  47. package/dist/services/tokenManager/iam.tokenManager.definitions.d.ts +14 -3
  48. package/dist/services/tokenManager/iam.tokenManager.definitions.js.map +1 -1
  49. package/dist/services/tokenManager/iam.tokenManager.service.d.ts +24 -9
  50. package/dist/services/tokenManager/iam.tokenManager.service.js +113 -44
  51. package/dist/services/tokenManager/iam.tokenManager.service.js.map +1 -1
  52. package/dist/services/userManager/iam.userManager.definitions.d.ts +45 -0
  53. package/dist/services/userManager/iam.userManager.definitions.js +8 -0
  54. package/dist/services/userManager/iam.userManager.definitions.js.map +1 -0
  55. package/dist/services/userManager/iam.userManager.service.d.ts +33 -0
  56. package/dist/services/userManager/iam.userManager.service.js +332 -0
  57. package/dist/services/userManager/iam.userManager.service.js.map +1 -0
  58. package/dist/services/userManager/index.d.ts +2 -0
  59. package/dist/services/userManager/index.js +19 -0
  60. package/dist/services/userManager/index.js.map +1 -0
  61. package/package.json +10 -8
  62. package/src/common/definitions/common.constants.ts +16 -0
  63. package/src/common/definitions/index.ts +1 -0
  64. package/src/index.ts +3 -0
  65. package/src/module/iam.definitions.ts +15 -0
  66. package/src/module/iam.module.ts +29 -0
  67. package/src/module/index.ts +2 -0
  68. package/src/services/authentication/iam.authentication.definitions.ts +100 -0
  69. package/src/services/authentication/iam.authentication.service.ts +105 -0
  70. package/src/services/authentication/index.ts +2 -0
  71. package/src/services/authenticationOAuth2/iam.authenticationOAuth2.definitions.ts +72 -0
  72. package/src/services/authenticationOAuth2/iam.authenticationOAuth2.service.ts +352 -0
  73. package/src/services/authenticationOAuth2/index.ts +2 -0
  74. package/src/services/authenticationUserLocal/iam.authenticationUserLocal.definitions.ts +29 -0
  75. package/src/services/authenticationUserLocal/iam.authenticationUserLocal.service.ts +173 -0
  76. package/src/services/authenticationUserLocal/index.ts +2 -0
  77. package/src/services/authorization/iam.authorization.definitions.ts +55 -0
  78. package/src/services/authorization/iam.authorization.service.ts +387 -0
  79. package/src/services/authorization/index.ts +2 -0
  80. package/src/services/index.ts +7 -0
  81. package/src/services/mfa/iam.mfa.definitions.ts +28 -0
  82. package/src/services/mfa/iam.mfa.service.ts +40 -0
  83. package/src/services/mfa/index.ts +2 -0
  84. package/src/services/tokenManager/iam.tokenManager.definitions.ts +61 -0
  85. package/src/services/tokenManager/iam.tokenManager.service.ts +292 -0
  86. package/src/services/tokenManager/index.ts +2 -0
  87. package/src/services/userManager/iam.userManager.definitions.ts +73 -0
  88. package/src/services/userManager/iam.userManager.service.ts +463 -0
  89. package/src/services/userManager/index.ts +2 -0
  90. package/dist/services/authenticationLocal/iam.authenticationLocal.definitions.d.ts +0 -11
  91. package/dist/services/authenticationLocal/iam.authenticationLocal.definitions.js.map +0 -1
  92. package/dist/services/authenticationLocal/iam.authenticationLocal.service.d.ts +0 -10
  93. package/dist/services/authenticationLocal/iam.authenticationLocal.service.js +0 -70
  94. package/dist/services/authenticationLocal/iam.authenticationLocal.service.js.map +0 -1
  95. package/dist/services/authenticationLocal/index.d.ts +0 -2
  96. package/dist/services/authenticationLocal/index.js.map +0 -1
  97. package/dist/services/users/iam.users.definitions.d.ts +0 -30
  98. package/dist/services/users/iam.users.definitions.js +0 -8
  99. package/dist/services/users/iam.users.definitions.js.map +0 -1
  100. package/dist/services/users/iam.users.service.d.ts +0 -16
  101. package/dist/services/users/iam.users.service.js +0 -93
  102. package/dist/services/users/iam.users.service.js.map +0 -1
  103. package/dist/services/users/index.d.ts +0 -2
  104. package/dist/services/users/index.js.map +0 -1
@@ -0,0 +1,463 @@
1
+ import {
2
+ AppConfigDomainIAM,
3
+ AppConfigDomainIAMAuthenticationStep,
4
+ ApplicationError,
5
+ ConfigProviderService,
6
+ DataDefaultData,
7
+ DataEntityService,
8
+ DataFindOneOptions,
9
+ DomainEntityService,
10
+ DomainEntityServiceDefaultData,
11
+ GenericObject,
12
+ LoggerService,
13
+ getNested,
14
+ setNested
15
+ } from '@node-c/core';
16
+
17
+ import ld from 'lodash';
18
+
19
+ import {
20
+ IAMUserManagerCreateAccessTokenOptions,
21
+ IAMUserManagerCreateAccessTokenReturnData,
22
+ IAMUserManagerExecuteStepData,
23
+ IAMUserManagerExecuteStepOptions,
24
+ IAMUserManagerExecuteStepResult,
25
+ IAMUserManagerGetUserWithPermissionsDataOptions,
26
+ IAMUserManagerUserTokenEnityFields,
27
+ IAMUserManagerUserTokenUserIdentifier,
28
+ IAMUserManagerUserWithPermissionsData
29
+ } from './iam.userManager.definitions';
30
+
31
+ import {
32
+ IAMAuthenticationCompleteData,
33
+ IAMAuthenticationCompleteOptions,
34
+ IAMAuthenticationGetUserDataFromExternalTokenPayloadsData,
35
+ IAMAuthenticationService,
36
+ IAMAuthenticationType
37
+ } from '../authentication';
38
+ import { IAMAuthenticationOAuth2CompleteResult, IAMAuthenticationOAuth2Service } from '../authenticationOAuth2';
39
+ import {
40
+ IAMAuthenticationUserLocalCompleteResult,
41
+ IAMAuthenticationUserLocalService
42
+ } from '../authenticationUserLocal';
43
+ import { IAMTokenManagerService, TokenType } from '../tokenManager';
44
+
45
+ // TODO: create user (signup); this should include password hashing
46
+ // TODO: update password (incl. hashing)
47
+ // TODO: reset password
48
+ // TODO: periodic checking of external access tokens and their revoking
49
+ export class IAMUserManagerService<
50
+ User extends object,
51
+ Data extends DomainEntityServiceDefaultData<Partial<User>> = DomainEntityServiceDefaultData<Partial<User>>,
52
+ DataEntityServiceData extends DataDefaultData<Partial<User>> = DataDefaultData<Partial<User>>
53
+ > {
54
+ constructor(
55
+ // eslint-disable-next-line no-unused-vars
56
+ protected authServices: {
57
+ [IAMAuthenticationType.OAuth2]?: IAMAuthenticationOAuth2Service<object, object>;
58
+ [IAMAuthenticationType.UserLocal]?: IAMAuthenticationUserLocalService<object, object>;
59
+ } & { [serviceName: string]: IAMAuthenticationService<object, object> },
60
+ // eslint-disable-next-line no-unused-vars
61
+ protected configProvider: ConfigProviderService,
62
+ // eslint-disable-next-line no-unused-vars
63
+ protected dataUsersAuthCacheService: DataEntityService<GenericObject>,
64
+ // eslint-disable-next-line no-unused-vars
65
+ protected domainUsersEntityService: DomainEntityService<
66
+ User,
67
+ DataEntityService<User, DataEntityServiceData>,
68
+ Data,
69
+ Record<string, DataEntityService<Partial<User>, DataDefaultData<object>>> | undefined
70
+ >,
71
+ // eslint-disable-next-line no-unused-vars
72
+ protected logger: LoggerService,
73
+ // eslint-disable-next-line no-unused-vars
74
+ protected moduleName: string,
75
+ // eslint-disable-next-line no-unused-vars
76
+ protected tokenManager: IAMTokenManagerService<IAMUserManagerUserTokenEnityFields>
77
+ ) {}
78
+
79
+ // TODO: clear the cache from the previous steps
80
+ // TODO: make the issuing of local tokens work with purgeOldFromStore = false
81
+ async createAccessToken<AuthData = unknown>(
82
+ options: IAMUserManagerCreateAccessTokenOptions<AuthData>
83
+ ): Promise<IAMUserManagerCreateAccessTokenReturnData<User>> {
84
+ const { configProvider, logger, moduleName } = this;
85
+ const moduleConfig = configProvider.config.domain[moduleName] as AppConfigDomainIAM;
86
+ const { accessTokenExpiryTimeInMinutes, defaultUserIdentifierField, refreshTokenExpiryTimeInMinutes } =
87
+ moduleConfig;
88
+ const {
89
+ auth: { type: authType },
90
+ rememberUser
91
+ } = options;
92
+ logger.info(
93
+ `[Domain.${moduleName}.UserManager]: Login attempt started${options.step ? ` for step ${options.step}` : ''}.`
94
+ );
95
+ // 1. Make sure the auth service actually exists - local, oauth2, etc.
96
+ const authService = this.authServices[authType] as IAMAuthenticationService<object, object>;
97
+ if (!authService) {
98
+ logger.info(`[Domain.${moduleName}.UserManager]: No authService ${authType} found.`);
99
+ throw new ApplicationError('Authentication failed.');
100
+ }
101
+ // 2. Get the user-specific configuration from the authService.
102
+ const authServiceBehaviorConfig = authService.getUserCreateAccessTokenConfig();
103
+ let externalAccessToken: string | undefined;
104
+ let externalRefreshToken: string | undefined;
105
+ let issueTokens = false;
106
+ let step: AppConfigDomainIAMAuthenticationStep;
107
+ let userFilterField: string | undefined;
108
+ let userFilterValue: unknown | undefined;
109
+ // 3. Prepare the step behavior based on the configuration.
110
+ // 3.1. Complete step
111
+ if (options.step === AppConfigDomainIAMAuthenticationStep.Complete) {
112
+ issueTokens = true;
113
+ step = AppConfigDomainIAMAuthenticationStep.Complete;
114
+ }
115
+ // 3.2. Initiate step - assumed implicitly.
116
+ else {
117
+ step = AppConfigDomainIAMAuthenticationStep.Initiate;
118
+ }
119
+ let stepConfig = authServiceBehaviorConfig[step];
120
+ // 3. Run the authentication method itself.
121
+ // eslint-disable-next-line prefer-const
122
+ let { stepResult, user, ...otherStepData } = await this.executeStep(options, {
123
+ authService,
124
+ name: step,
125
+ stepConfig
126
+ });
127
+ // 4. Run the final step, if this is the first step no mfa has been used.
128
+ if (step === AppConfigDomainIAMAuthenticationStep.Initiate && !stepResult.mfaUsed) {
129
+ issueTokens = true;
130
+ step = AppConfigDomainIAMAuthenticationStep.Complete;
131
+ stepConfig = authServiceBehaviorConfig[step];
132
+ const finalStepData = await this.executeStep(options, {
133
+ authService,
134
+ name: step,
135
+ stepConfig: ld.omit(stepConfig, 'cache')
136
+ });
137
+ stepResult = finalStepData.stepResult;
138
+ user = user ?? finalStepData.user;
139
+ userFilterField = finalStepData.userFilterField;
140
+ userFilterValue = finalStepData.userFilterValue;
141
+ }
142
+ // 5. Process the external access, refresh and, optionally, id tokens that are returned by the step execution.
143
+ const actualStepResult = stepResult as
144
+ | IAMAuthenticationOAuth2CompleteResult
145
+ | IAMAuthenticationUserLocalCompleteResult;
146
+ if (!userFilterField && otherStepData.userFilterField) {
147
+ userFilterField = otherStepData.userFilterField;
148
+ }
149
+ if (!userFilterValue && otherStepData.userFilterValue) {
150
+ userFilterValue = otherStepData.userFilterValue;
151
+ }
152
+ if ('useReturnedTokens' in stepConfig && stepConfig.useReturnedTokens && stepConfig.authReturnsTokens) {
153
+ // Make sure we have an accessToken in the response and set the access and refresh tokens in variables for later use.
154
+ if (!actualStepResult.accessToken) {
155
+ logger.info(
156
+ `[Domain.${moduleName}.UserManager]: Login attempt failed for ${userFilterField} ${userFilterValue} - no accessToken returned from the authService and useReturnedTokens is set to true.`
157
+ );
158
+ throw new ApplicationError('Authentication failed.');
159
+ }
160
+ externalAccessToken = actualStepResult.accessToken;
161
+ if (actualStepResult.refreshToken) {
162
+ externalRefreshToken = actualStepResult.refreshToken;
163
+ }
164
+ }
165
+ // 6. Token management. In this case, we will definitely have the user, or will be force to create it.
166
+ if (issueTokens) {
167
+ if (!user) {
168
+ logger.info(
169
+ `[Domain.${moduleName}.UserManager]: Login attempt failed at step ${step} - user is required when issueTokens is set to true.`
170
+ );
171
+ throw new ApplicationError('Authentication failed.');
172
+ }
173
+ let refreshToken: string | undefined;
174
+ // 6.1. Create a local refresh token and save it. The payload contains the external refresh token, if it exists.
175
+ const userIdentifierValue = user[defaultUserIdentifierField as keyof User];
176
+ if (externalRefreshToken || !externalAccessToken) {
177
+ const {
178
+ result: { token: localRefreshToken }
179
+ } = await this.tokenManager.create(
180
+ {
181
+ type: TokenType.Refresh,
182
+ [IAMUserManagerUserTokenUserIdentifier.FieldName]: userIdentifierValue,
183
+ ...(externalRefreshToken
184
+ ? {
185
+ externalToken: externalRefreshToken,
186
+ externalTokenAuthService: authType as IAMAuthenticationType
187
+ }
188
+ : {})
189
+ },
190
+ {
191
+ expiresInMinutes:
192
+ (externalRefreshToken &&
193
+ 'refreshTokenExpiresIn' in actualStepResult &&
194
+ actualStepResult.refreshTokenExpiresIn) ||
195
+ (rememberUser ? undefined : refreshTokenExpiryTimeInMinutes),
196
+ identifierDataField: IAMUserManagerUserTokenUserIdentifier.FieldName,
197
+ persist: true,
198
+ purgeOldFromData: true,
199
+ tokenContentOnlyFields: ['externalToken']
200
+ }
201
+ );
202
+ refreshToken = localRefreshToken;
203
+ }
204
+ // 6.2. Create a local access token and save it. The payload contains the external access token, if it exists.
205
+ const {
206
+ result: { token: accessToken }
207
+ } = await this.tokenManager.create(
208
+ {
209
+ refreshToken,
210
+ type: TokenType.Access,
211
+ user,
212
+ [IAMUserManagerUserTokenUserIdentifier.FieldName]: userIdentifierValue,
213
+ ...(externalAccessToken
214
+ ? {
215
+ externalToken: externalAccessToken,
216
+ externalTokenAuthService: authType as IAMAuthenticationType
217
+ }
218
+ : {})
219
+ },
220
+ {
221
+ expiresInMinutes:
222
+ (externalAccessToken &&
223
+ 'accessTokenExpiresIn' in actualStepResult &&
224
+ actualStepResult.accessTokenExpiresIn) ||
225
+ accessTokenExpiryTimeInMinutes,
226
+ identifierDataField: IAMUserManagerUserTokenUserIdentifier.FieldName,
227
+ persist: true,
228
+ purgeOldFromData: true,
229
+ tokenContentOnlyFields: ['externalToken', 'refreshToken', 'user']
230
+ }
231
+ );
232
+ logger.info(
233
+ `[Domain.${moduleName}.UserManager]: Login attempt successful for ${userFilterField} ${userFilterValue}.`
234
+ );
235
+ return { accessToken, refreshToken, user };
236
+ }
237
+ const returnData: IAMUserManagerCreateAccessTokenReturnData<User> = { nextStepsRequired: true };
238
+ if (stepConfig.stepResultPublicFields?.length) {
239
+ stepConfig.stepResultPublicFields.forEach(fieldName => {
240
+ setNested(
241
+ returnData,
242
+ fieldName,
243
+ getNested(stepResult, fieldName, { removeNestedFieldEscapeSign: true }).unifiedValue
244
+ );
245
+ });
246
+ }
247
+ return returnData;
248
+ }
249
+
250
+ private async executeStep<AuthData>(
251
+ data: IAMUserManagerExecuteStepData<AuthData>,
252
+ options: IAMUserManagerExecuteStepOptions<User>
253
+ ): Promise<IAMUserManagerExecuteStepResult<User>> {
254
+ const { configProvider, domainUsersEntityService, logger, moduleName } = this;
255
+ const { defaultUserIdentifierField } = configProvider.config.domain[moduleName] as AppConfigDomainIAM;
256
+ const {
257
+ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
258
+ auth: { type: _authType, ...authData },
259
+ filters: userFilters,
260
+ mainFilterField
261
+ } = data;
262
+ const { authService, stepConfig, name: stepName } = options;
263
+ const { cache: cacheSettings, findUser, findUserBeforeAuth, validWithoutUser } = stepConfig;
264
+ const hasFilters = userFilters && Object.keys(userFilters).length;
265
+ const stepInputData: { data: unknown; options?: unknown } = { data: ld.cloneDeep(authData) };
266
+ let user: IAMUserManagerUserWithPermissionsData<User, unknown> | null = null;
267
+ let userFilterField: string | undefined;
268
+ let userFilterValue: unknown | undefined;
269
+ // 1. Find the user based on the provided filters, if enabled.
270
+ if (findUser && findUserBeforeAuth) {
271
+ if (!hasFilters) {
272
+ logger.info(`[Domain.${moduleName}.UserManager]: No filters provided for findUserBeforeToken=true.`);
273
+ throw new ApplicationError('Authentication failed.');
274
+ }
275
+ userFilterField = mainFilterField;
276
+ userFilterValue = userFilters[userFilterField];
277
+ user = await this.getUserForStepExecution({ filters: userFilters, mainFilterField: userFilterField });
278
+ if (!user) {
279
+ logger.info(
280
+ `[Domain.${moduleName}.UserManager]: Login attempt failed for ${userFilterField} ${userFilterValue} - user not found.`
281
+ );
282
+ throw new ApplicationError('Authentication failed.');
283
+ }
284
+ }
285
+ stepInputData.options = {
286
+ context: user || ({} as IAMUserManagerUserWithPermissionsData<User, unknown>),
287
+ contextIdentifierField: defaultUserIdentifierField
288
+ };
289
+ // 2. Restore the cache, if configured
290
+ if (cacheSettings && 'use' in cacheSettings && cacheSettings.use) {
291
+ const cacheInput: { data: unknown; options: unknown } = {
292
+ data: stepInputData.data,
293
+ options: stepInputData.options
294
+ };
295
+ const cacheResult = await this.dataUsersAuthCacheService.findOne({
296
+ filters: {
297
+ [cacheSettings.settings.cacheFieldName]: getNested(cacheInput, cacheSettings.settings.inputFieldName)
298
+ .unifiedValue
299
+ }
300
+ });
301
+ if (cacheResult) {
302
+ for (const inputName in cacheSettings.use) {
303
+ const { overwrite, use } = cacheSettings.use[inputName as keyof typeof cacheSettings.use]!;
304
+ if (!use) {
305
+ continue;
306
+ }
307
+ const valueFromCache =
308
+ getNested(cacheResult, inputName, { removeNestedFieldEscapeSign: true }).unifiedValue || {};
309
+ const inputNameKey = inputName as keyof typeof stepInputData;
310
+ if (overwrite) {
311
+ stepInputData[inputNameKey] = ld.merge(stepInputData[inputNameKey], valueFromCache);
312
+ continue;
313
+ }
314
+ stepInputData[inputNameKey] = ld.merge(valueFromCache, stepInputData[inputNameKey]);
315
+ }
316
+ }
317
+ }
318
+ // 3. Run the step method itself.
319
+ let stepResult = await authService[stepName as 'complete' | 'initiate'](
320
+ stepInputData.data as IAMAuthenticationCompleteData,
321
+ stepInputData.options as IAMAuthenticationCompleteOptions<User>
322
+ );
323
+ // 4. Process the step result
324
+ if (!stepResult.valid || (stepResult.mfaUsed && !stepResult.mfaValid)) {
325
+ logger.info(`[Domain.${moduleName}.UserManager]: Bad step result:`, stepResult);
326
+ throw new ApplicationError('Authentication failed.');
327
+ }
328
+ // 5. If the step returns tokens and decoding is enabled, decode the reutrned tokens for payloads
329
+ if ('decodeReturnedTokens' in stepConfig && stepConfig.decodeReturnedTokens) {
330
+ const tokensForDecoding: Record<string, string> = {};
331
+ const tokenKeys = ['accessToken', 'idToken', 'refreshToken'];
332
+ tokenKeys.forEach(tokenKey => {
333
+ const resultForKey = stepResult[tokenKey as keyof typeof stepResult] as unknown as string;
334
+ if (!resultForKey) {
335
+ return;
336
+ }
337
+ tokensForDecoding[tokenKey] = resultForKey;
338
+ });
339
+ const externalTokenPayloads = await authService.getPayloadsFromExternalTokens(tokensForDecoding);
340
+ stepResult = { ...stepResult, ...externalTokenPayloads };
341
+ }
342
+ // 6. Find the user based on either the provided filters, or on the stepResult data, if enabled
343
+ if (findUser && !findUserBeforeAuth) {
344
+ if ('findUserInAuthResultBy' in stepConfig && stepConfig.findUserInAuthResultBy) {
345
+ const { userFieldName, resultFieldName } = stepConfig.findUserInAuthResultBy;
346
+ const payloadFilterValue = getNested(stepResult, resultFieldName, {
347
+ removeNestedFieldEscapeSign: true
348
+ }).unifiedValue;
349
+ userFilterField = userFieldName;
350
+ if (typeof payloadFilterValue !== 'undefined') {
351
+ userFilterValue = payloadFilterValue;
352
+ }
353
+ if (typeof userFilterValue !== 'undefined') {
354
+ user = await this.getUserForStepExecution({
355
+ filters: { [userFieldName]: userFilterValue },
356
+ mainFilterField: userFieldName
357
+ });
358
+ }
359
+ } else if (hasFilters) {
360
+ userFilterField = mainFilterField;
361
+ userFilterValue = userFilters[userFilterField];
362
+ user = await this.getUserForStepExecution({
363
+ filters: userFilters,
364
+ mainFilterField: userFilterField
365
+ });
366
+ }
367
+ }
368
+ // 7. Create a user using the data from the tokens returned by the step execution, if enabled and there is no user found.
369
+ if (!user && 'createUser' in stepConfig && stepConfig.createUser) {
370
+ const userData = await authService.getUserDataFromExternalTokenPayloads(
371
+ stepResult as IAMAuthenticationGetUserDataFromExternalTokenPayloadsData
372
+ );
373
+ if (userData) {
374
+ const { result: createdUser } = await domainUsersEntityService.create(userData as unknown as Data['Create']);
375
+ user = await this.getUserWithPermissionsData(
376
+ {
377
+ filters: {
378
+ [defaultUserIdentifierField]: createdUser[defaultUserIdentifierField as keyof typeof createdUser]
379
+ }
380
+ },
381
+ { keepPassword: false }
382
+ );
383
+ }
384
+ }
385
+ if (validWithoutUser !== true && !user) {
386
+ logger.info(
387
+ `[Domain.${moduleName}.UserManager]: Login attempt failed ${userFilterField && userFilterValue ? `for ${userFilterField} ${userFilterValue} ` : ''}- user not found.`
388
+ );
389
+ throw new ApplicationError('Authentication failed.');
390
+ }
391
+ if (user && 'password' in user) {
392
+ delete user.password;
393
+ }
394
+ // 8. Populate the cache, if configured
395
+ if (stepResult.mfaUsed && cacheSettings && 'populate' in cacheSettings && cacheSettings.populate) {
396
+ const cacheInput: GenericObject = {
397
+ data: stepInputData.data,
398
+ options: stepInputData.options,
399
+ result: stepResult
400
+ };
401
+ const cacheData: GenericObject = {};
402
+ for (const inputName in cacheSettings.populate) {
403
+ const inputSettings = cacheSettings.populate[inputName as keyof typeof cacheSettings.populate];
404
+ if (inputSettings instanceof Array) {
405
+ const innerInputItem: GenericObject = {};
406
+ inputSettings.forEach(inputItemSettings => {
407
+ const { cacheFieldName, inputFieldName } = inputItemSettings;
408
+ setNested(
409
+ innerInputItem,
410
+ cacheFieldName,
411
+ getNested(cacheInput, inputFieldName, { removeNestedFieldEscapeSign: true }).unifiedValue
412
+ );
413
+ });
414
+ cacheData[inputName] = innerInputItem;
415
+ continue;
416
+ }
417
+ cacheData[inputName] = cacheInput[inputName];
418
+ }
419
+ await this.dataUsersAuthCacheService.create({
420
+ ...cacheData,
421
+ [cacheSettings.settings.cacheFieldName]: getNested(cacheInput, cacheSettings.settings.inputFieldName)
422
+ .unifiedValue
423
+ });
424
+ }
425
+ return { stepResult, user, userFilterField, userFilterValue };
426
+ }
427
+
428
+ protected async getUserForStepExecution(options: {
429
+ filters: GenericObject;
430
+ mainFilterField: string;
431
+ }): Promise<IAMUserManagerUserWithPermissionsData<User, unknown> | null> {
432
+ const { configProvider, moduleName } = this;
433
+ const { defaultUserIdentifierField } = configProvider.config.domain[moduleName] as AppConfigDomainIAM;
434
+ const { mainFilterField } = options;
435
+ let filters: GenericObject = options.filters;
436
+ let user: IAMUserManagerUserWithPermissionsData<User, unknown> | null = null;
437
+ if (mainFilterField !== defaultUserIdentifierField) {
438
+ const mainFilterFieldResult = await this.domainUsersEntityService.findOne({ filters });
439
+ if (!mainFilterFieldResult.result) {
440
+ return null;
441
+ }
442
+ filters = {
443
+ [defaultUserIdentifierField]:
444
+ mainFilterFieldResult.result[defaultUserIdentifierField as keyof typeof mainFilterFieldResult.result]
445
+ };
446
+ } else {
447
+ filters = options.filters;
448
+ }
449
+ user = await this.getUserWithPermissionsData({ filters }, { keepPassword: true });
450
+ return user;
451
+ }
452
+
453
+ async getUserWithPermissionsData(
454
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
455
+ _options: DataFindOneOptions,
456
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
457
+ _privateOptions?: IAMUserManagerGetUserWithPermissionsDataOptions
458
+ ): Promise<IAMUserManagerUserWithPermissionsData<User, unknown> | null> {
459
+ throw new ApplicationError(
460
+ `Method ${this.moduleName}.IAMUserManagerService.getUserWithPermissionsData not implemented.`
461
+ );
462
+ }
463
+ }
@@ -0,0 +1,2 @@
1
+ export * from './iam.userManager.definitions';
2
+ export * from './iam.userManager.service';
@@ -1,11 +0,0 @@
1
- import { AuthenticateUserAuthData, AuthenticateUserResult, AuthenticateUserUserData } from '../authentication';
2
- export type LocalAuthenticateUserUserData<UserFields extends object> = AuthenticateUserUserData<{
3
- password: string;
4
- } & UserFields>;
5
- export interface LocalAuthenticateUserAuthData extends AuthenticateUserAuthData {
6
- password: string;
7
- }
8
- export type LocalAuthenticateUserResult = AuthenticateUserResult;
9
- export type LocalAuthenticationUserMFAEntity<UserMFAFields extends object | undefined> = {
10
- code: string;
11
- } & UserMFAFields;
@@ -1 +0,0 @@
1
- {"version":3,"file":"iam.authenticationLocal.definitions.js","sourceRoot":"","sources":["../../../src/services/authenticationLocal/iam.authenticationLocal.definitions.ts"],"names":[],"mappings":""}
@@ -1,10 +0,0 @@
1
- import { ConfigProviderService, PersistanceEntityService } from '@node-c/core';
2
- import { LocalAuthenticateUserAuthData, LocalAuthenticateUserResult, LocalAuthenticateUserUserData, LocalAuthenticationUserMFAEntity } from './iam.authenticationLocal.definitions';
3
- import { IAMAuthenticationService } from '../authentication';
4
- export declare class IAMAuthenticationLocalService<AuthenticationUserFields extends object, UserMFAEntityFields extends object | undefined = undefined> extends IAMAuthenticationService<AuthenticationUserFields> {
5
- protected configProvider: ConfigProviderService;
6
- protected moduleName: string;
7
- protected persistanceUsersMFAService?: PersistanceEntityService<LocalAuthenticationUserMFAEntity<UserMFAEntityFields>> | undefined;
8
- constructor(configProvider: ConfigProviderService, moduleName: string, persistanceUsersMFAService?: PersistanceEntityService<LocalAuthenticationUserMFAEntity<UserMFAEntityFields>> | undefined);
9
- authenticateUser(userData: LocalAuthenticateUserUserData<AuthenticationUserFields>, authData: LocalAuthenticateUserAuthData): Promise<LocalAuthenticateUserResult>;
10
- }
@@ -1,70 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.IAMAuthenticationLocalService = void 0;
16
- const crypto_1 = __importDefault(require("crypto"));
17
- const core_1 = require("@node-c/core");
18
- const authentication_1 = require("../authentication");
19
- class IAMAuthenticationLocalService extends authentication_1.IAMAuthenticationService {
20
- constructor(configProvider, moduleName, persistanceUsersMFAService) {
21
- super(configProvider, moduleName);
22
- this.configProvider = configProvider;
23
- this.moduleName = moduleName;
24
- this.persistanceUsersMFAService = persistanceUsersMFAService;
25
- }
26
- authenticateUser(userData, authData) {
27
- return __awaiter(this, void 0, void 0, function* () {
28
- const { configProvider, moduleName, persistanceUsersMFAService } = this;
29
- const { defaultUserIdentifierField, userPasswordHMACAlgorithm, userPasswordSecret } = configProvider.config.domain[moduleName];
30
- const { mfaEnabled, password: userPassword } = userData;
31
- const { mfaCode, mfaType, password: authPassword } = authData;
32
- const userIdentifierField = authData.userIdentifierField || defaultUserIdentifierField;
33
- const userIdentifierValue = userData[userIdentifierField];
34
- const userMFAIdentifierField = authData.userMFAIdentifierField || userIdentifierField;
35
- let wrongPassword = false;
36
- if (!userPasswordHMACAlgorithm || !userPasswordSecret || !userPassword) {
37
- wrongPassword = true;
38
- }
39
- else {
40
- const computedPassword = crypto_1.default
41
- .createHmac(userPasswordHMACAlgorithm, userPasswordSecret)
42
- .update(`${authPassword}`)
43
- .digest('hex')
44
- .toString();
45
- if (computedPassword !== userPassword) {
46
- wrongPassword = true;
47
- }
48
- }
49
- if (wrongPassword) {
50
- console.info(`[IAMAuthenticationLocalService]: Login attempt failed for user "${userIdentifierValue}" - wrong password.`);
51
- throw new core_1.ApplicationError('Invalid user identifier or password.');
52
- }
53
- if (mfaEnabled) {
54
- if (!mfaCode || mfaType !== authentication_1.UserMFAKnownType.Local || !persistanceUsersMFAService) {
55
- throw new core_1.ApplicationError('Invalid MFA code.');
56
- }
57
- const storedCodeData = yield persistanceUsersMFAService.findOne({
58
- filters: { [userMFAIdentifierField]: userIdentifierValue }
59
- });
60
- if (!(storedCodeData === null || storedCodeData === void 0 ? void 0 : storedCodeData.code) || mfaCode !== (storedCodeData === null || storedCodeData === void 0 ? void 0 : storedCodeData.code)) {
61
- console.info(`[IAMAuthenticationLocalService]: Login attempt failed for user ${userIdentifierValue} - missing or wrong mfa code.`);
62
- throw new core_1.ApplicationError('Invalid MFA code.');
63
- }
64
- }
65
- return { valid: true };
66
- });
67
- }
68
- }
69
- exports.IAMAuthenticationLocalService = IAMAuthenticationLocalService;
70
- //# sourceMappingURL=iam.authenticationLocal.service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"iam.authenticationLocal.service.js","sourceRoot":"","sources":["../../../src/services/authenticationLocal/iam.authenticationLocal.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,oDAA4B;AAE5B,uCAAqH;AASrH,sDAA+E;AAE/E,MAAa,6BAGX,SAAQ,yCAAkD;IAC1D,YACY,cAAqC,EACrC,UAAkB,EAElB,0BAET;QAED,KAAK,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;QAPxB,mBAAc,GAAd,cAAc,CAAuB;QACrC,eAAU,GAAV,UAAU,CAAQ;QAElB,+BAA0B,GAA1B,0BAA0B,CAEnC;IAGH,CAAC;IAEK,gBAAgB,CACpB,QAAiE,EACjE,QAAuC;;YAEvC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,0BAA0B,EAAE,GAAG,IAAI,CAAC;YACxE,MAAM,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,MAAM,CAChH,UAAU,CACW,CAAC;YACxB,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC;YACxD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC;YAC9D,MAAM,mBAAmB,GAAG,QAAQ,CAAC,mBAAmB,IAAI,0BAA0B,CAAC;YACvF,MAAM,mBAAmB,GAAG,QAAQ,CAAC,mBAAqD,CAAC,CAAC;YAC5F,MAAM,sBAAsB,GAAG,QAAQ,CAAC,sBAAsB,IAAI,mBAAmB,CAAC;YACtF,IAAI,aAAa,GAAG,KAAK,CAAC;YAC1B,IAAI,CAAC,yBAAyB,IAAI,CAAC,kBAAkB,IAAI,CAAC,YAAY,EAAE,CAAC;gBACvE,aAAa,GAAG,IAAI,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,MAAM,gBAAgB,GAAG,gBAAM;qBAC5B,UAAU,CAAC,yBAAyB,EAAE,kBAAkB,CAAC;qBACzD,MAAM,CAAC,GAAG,YAAY,EAAE,CAAC;qBACzB,MAAM,CAAC,KAAK,CAAC;qBACb,QAAQ,EAAE,CAAC;gBACd,IAAI,gBAAgB,KAAK,YAAY,EAAE,CAAC;oBACtC,aAAa,GAAG,IAAI,CAAC;gBACvB,CAAC;YACH,CAAC;YACD,IAAI,aAAa,EAAE,CAAC;gBAClB,OAAO,CAAC,IAAI,CACV,mEAAmE,mBAAmB,qBAAqB,CAC5G,CAAC;gBACF,MAAM,IAAI,uBAAgB,CAAC,sCAAsC,CAAC,CAAC;YACrE,CAAC;YAED,IAAI,UAAU,EAAE,CAAC;gBACf,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,iCAAgB,CAAC,KAAK,IAAI,CAAC,0BAA0B,EAAE,CAAC;oBAClF,MAAM,IAAI,uBAAgB,CAAC,mBAAmB,CAAC,CAAC;gBAClD,CAAC;gBACD,MAAM,cAAc,GAAG,MAAM,0BAA0B,CAAC,OAAO,CAAC;oBAC9D,OAAO,EAAE,EAAE,CAAC,sBAAsB,CAAC,EAAE,mBAAmB,EAAE;iBAC3D,CAAC,CAAC;gBACH,IAAI,CAAC,CAAA,cAAc,aAAd,cAAc,uBAAd,cAAc,CAAE,IAAI,CAAA,IAAI,OAAO,MAAK,cAAc,aAAd,cAAc,uBAAd,cAAc,CAAE,IAAI,CAAA,EAAE,CAAC;oBAC9D,OAAO,CAAC,IAAI,CACV,kEAAkE,mBAAmB,+BAA+B,CACrH,CAAC;oBACF,MAAM,IAAI,uBAAgB,CAAC,mBAAmB,CAAC,CAAC;gBAClD,CAAC;YACH,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;KAAA;CACF;AAhED,sEAgEC"}
@@ -1,2 +0,0 @@
1
- export * from './iam.authenticationLocal.definitions';
2
- export * from './iam.authenticationLocal.service';
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/authenticationLocal/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wEAAsD;AACtD,oEAAkD"}
@@ -1,30 +0,0 @@
1
- import { GenericObject } from '@node-c/core';
2
- import { UserAuthType, UserMFAType } from '../authentication';
3
- import { AuthorizationPoint } from '../authorization';
4
- export interface CreateAccessTokenOptions<AuthData = unknown> {
5
- auth: {
6
- mfaType?: UserMFAType;
7
- type: UserAuthType;
8
- } & AuthData;
9
- filters: GenericObject;
10
- mainFilterField: string;
11
- rememberUser?: boolean;
12
- }
13
- export interface CreateAccessTokenReturnData<UserData> {
14
- accessToken: string;
15
- refreshToken: string;
16
- user: UserData;
17
- }
18
- export interface GetUserWithPermissionsDataOptions {
19
- keepPassword?: boolean;
20
- }
21
- export type UserWithPermissionsData<UserData, AuthorizationPointId> = {
22
- currentAuthorizationPoints: GenericObject<AuthorizationPoint<AuthorizationPointId>>;
23
- } & UserData;
24
- export interface UserTokenEnityFields<UserId = unknown> {
25
- refreshToken?: string;
26
- userId: UserId;
27
- }
28
- export declare enum UserTokenUserIdentifier {
29
- FieldName = "userId"
30
- }
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UserTokenUserIdentifier = void 0;
4
- var UserTokenUserIdentifier;
5
- (function (UserTokenUserIdentifier) {
6
- UserTokenUserIdentifier["FieldName"] = "userId";
7
- })(UserTokenUserIdentifier || (exports.UserTokenUserIdentifier = UserTokenUserIdentifier = {}));
8
- //# sourceMappingURL=iam.users.definitions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"iam.users.definitions.js","sourceRoot":"","sources":["../../../src/services/users/iam.users.definitions.ts"],"names":[],"mappings":";;;AAkCA,IAAY,uBAGX;AAHD,WAAY,uBAAuB;IAEjC,+CAAoB,CAAA;AACtB,CAAC,EAHW,uBAAuB,uCAAvB,uBAAuB,QAGlC"}
@@ -1,16 +0,0 @@
1
- import { ConfigProviderService, DomainEntityService, DomainEntityServiceDefaultData, PersistanceEntityService, PersistanceFindOneOptions } from '@node-c/core';
2
- import { CreateAccessTokenOptions, CreateAccessTokenReturnData, GetUserWithPermissionsDataOptions, UserTokenEnityFields, UserWithPermissionsData } from './iam.users.definitions';
3
- import { IAMAuthenticationService, UserAuthType } from '../authentication';
4
- import { IAMTokenManagerService } from '../tokenManager';
5
- export declare class IAMUsersService<User extends object, Data extends DomainEntityServiceDefaultData<Partial<User>> = DomainEntityServiceDefaultData<Partial<User>>> extends DomainEntityService<User, PersistanceEntityService<User>, Data, Record<string, PersistanceEntityService<Partial<User>>> | undefined> {
6
- protected configProvider: ConfigProviderService;
7
- protected moduleName: string;
8
- protected persistanceUsersService: PersistanceEntityService<User>;
9
- protected tokenManager: IAMTokenManagerService<UserTokenEnityFields>;
10
- protected userAuthServices: Record<UserAuthType, IAMAuthenticationService<User>>;
11
- protected defaultMethods: string[];
12
- protected additionalPersistanceEntityServices?: Record<string, PersistanceEntityService<Partial<User>>> | undefined;
13
- constructor(configProvider: ConfigProviderService, moduleName: string, persistanceUsersService: PersistanceEntityService<User>, tokenManager: IAMTokenManagerService<UserTokenEnityFields>, userAuthServices: Record<UserAuthType, IAMAuthenticationService<User>>, defaultMethods?: string[], additionalPersistanceEntityServices?: Record<string, PersistanceEntityService<Partial<User>>> | undefined);
14
- createAccessToken(options: CreateAccessTokenOptions): Promise<CreateAccessTokenReturnData<User>>;
15
- getUserWithPermissionsData(_options: PersistanceFindOneOptions, _privateOptions?: GetUserWithPermissionsDataOptions): Promise<UserWithPermissionsData<User, unknown> | null>;
16
- }