emilsoftware-utilities 2.0.0-dev.67 → 2.0.0-dev.69
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/accessi/resource-server/errors.d.ts +1 -1
- package/dist/accessi/resource-server/errors.js.map +1 -1
- package/dist/accessi/resource-server/express.js +21 -0
- package/dist/accessi/resource-server/express.js.map +1 -1
- package/dist/accessi/resource-server/nest.js +13 -0
- package/dist/accessi/resource-server/nest.js.map +1 -1
- package/dist/accessi/resource-server/runtime.js +11 -1
- package/dist/accessi/resource-server/runtime.js.map +1 -1
- package/dist/accessi/resource-server/types.d.ts +7 -0
- package/dist/accessi/resource-server/types.js.map +1 -1
- package/dist/accessi/server/index.d.ts +1 -0
- package/dist/accessi/server/index.js +1 -0
- package/dist/accessi/server/index.js.map +1 -1
- package/dist/accessi/server/standalone.d.ts +41 -0
- package/dist/accessi/server/standalone.js +264 -0
- package/dist/accessi/server/standalone.js.map +1 -0
- package/dist/accessi-module/AccessiModule.d.ts +53 -2
- package/dist/accessi-module/AccessiModule.js +5 -2
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/accessiFetch.d.ts +5 -0
- package/dist/accessi-module/Console/accessiFetch.js +7 -4
- package/dist/accessi-module/Console/accessiFetch.js.map +1 -1
- package/dist/accessi-module/Console/console.js +21 -7
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.d.ts +31 -1
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.js +28 -3
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/exchangeFederatedIdentityRequest.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/exchangeFederatedIdentityRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/exchangeFederatedIdentityRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedAuthenticationResultDto.d.ts +15 -0
- package/dist/accessi-module/Console/generated/model/federatedAuthenticationResultDto.js +3 -0
- package/dist/accessi-module/Console/generated/model/federatedAuthenticationResultDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/federatedExchangeResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/federatedExchangeResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/federatedExchangeResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/index.d.ts +6 -0
- package/dist/accessi-module/Console/generated/model/index.js +6 -0
- package/dist/accessi-module/Console/generated/model/index.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/loginResult.d.ts +2 -0
- package/dist/accessi-module/Console/generated/model/loginResult.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/refreshTokenRequest.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResult.d.ts +13 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResult.js +3 -0
- package/dist/accessi-module/Console/generated/model/refreshTokenResult.js.map +1 -0
- package/dist/accessi-module/Console/wiki.js +16 -3
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/AccessiConsoleController.d.ts +6 -1
- package/dist/accessi-module/Controllers/AccessiConsoleController.js +24 -1
- package/dist/accessi-module/Controllers/AccessiConsoleController.js.map +1 -1
- package/dist/accessi-module/Controllers/AuthController.d.ts +3 -1
- package/dist/accessi-module/Controllers/AuthController.js +90 -8
- package/dist/accessi-module/Controllers/AuthController.js.map +1 -1
- package/dist/accessi-module/Controllers/ConsoleEntryController.d.ts +2 -0
- package/dist/accessi-module/Controllers/ConsoleEntryController.js +11 -3
- package/dist/accessi-module/Controllers/ConsoleEntryController.js.map +1 -1
- package/dist/accessi-module/Controllers/EmailController.js +1 -1
- package/dist/accessi-module/Controllers/EmailController.js.map +1 -1
- package/dist/accessi-module/Controllers/UserController.js +1 -1
- package/dist/accessi-module/Controllers/UserController.js.map +1 -1
- package/dist/accessi-module/Dtos/FederatedExchangeDtos.d.ts +21 -0
- package/dist/accessi-module/Dtos/FederatedExchangeDtos.js +74 -0
- package/dist/accessi-module/Dtos/FederatedExchangeDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/LoginResponse.d.ts +1 -0
- package/dist/accessi-module/Dtos/LoginResponse.js +6 -0
- package/dist/accessi-module/Dtos/LoginResponse.js.map +1 -1
- package/dist/accessi-module/Dtos/RefreshTokenDtos.d.ts +12 -0
- package/dist/accessi-module/Dtos/RefreshTokenDtos.js +50 -0
- package/dist/accessi-module/Dtos/RefreshTokenDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/index.d.ts +2 -0
- package/dist/accessi-module/Dtos/index.js +2 -0
- package/dist/accessi-module/Dtos/index.js.map +1 -1
- package/dist/accessi-module/Services/AuthService/AuthService.d.ts +14 -0
- package/dist/accessi-module/Services/AuthService/AuthService.js +99 -6
- package/dist/accessi-module/Services/AuthService/AuthService.js.map +1 -1
- package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js +8 -16
- package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js.map +1 -1
- package/dist/accessi-module/federated-auth/FederatedAuthExchangeController.d.ts +15 -0
- package/dist/accessi-module/federated-auth/FederatedAuthExchangeController.js +85 -0
- package/dist/accessi-module/federated-auth/FederatedAuthExchangeController.js.map +1 -0
- package/dist/accessi-module/federated-auth/FederatedAuthService.js +7 -1
- package/dist/accessi-module/federated-auth/FederatedAuthService.js.map +1 -1
- package/dist/accessi-module/index.d.ts +17 -1
- package/dist/accessi-module/index.js +71 -5
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/accessi-module/jwt/jwt.strategy.js +4 -0
- package/dist/accessi-module/jwt/jwt.strategy.js.map +1 -1
- package/dist/accessi-module/middleware/authenticateGen.js +4 -0
- package/dist/accessi-module/middleware/authenticateGen.js.map +1 -1
- package/dist/accessi-module/security/audit.d.ts +7 -0
- package/dist/accessi-module/security/audit.js +14 -0
- package/dist/accessi-module/security/audit.js.map +1 -0
- package/dist/accessi-module/security/authenticatedToken.d.ts +1 -1
- package/dist/accessi-module/security/authenticatedToken.js +3 -3
- package/dist/accessi-module/security/authenticatedToken.js.map +1 -1
- package/dist/accessi-module/security/consoleEntry.d.ts +58 -11
- package/dist/accessi-module/security/consoleEntry.js +181 -31
- package/dist/accessi-module/security/consoleEntry.js.map +1 -1
- package/dist/accessi-module/security/edgeRateLimit.d.ts +33 -0
- package/dist/accessi-module/security/edgeRateLimit.js +81 -0
- package/dist/accessi-module/security/edgeRateLimit.js.map +1 -0
- package/dist/accessi-module/security/jwks.d.ts +33 -0
- package/dist/accessi-module/security/jwks.js +83 -0
- package/dist/accessi-module/security/jwks.js.map +1 -0
- package/dist/accessi-module/security/jwksBootstrap.d.ts +15 -0
- package/dist/accessi-module/security/jwksBootstrap.js +44 -0
- package/dist/accessi-module/security/jwksBootstrap.js.map +1 -0
- package/dist/accessi-module/security/jwtTokenOptions.d.ts +9 -2
- package/dist/accessi-module/security/jwtTokenOptions.js +18 -4
- package/dist/accessi-module/security/jwtTokenOptions.js.map +1 -1
- package/dist/accessi-module/security/passwordResetToken.d.ts +1 -1
- package/dist/accessi-module/security/passwordResetToken.js.map +1 -1
- package/dist/accessi-module/security/publicAuthRateLimit.d.ts +9 -7
- package/dist/accessi-module/security/publicAuthRateLimit.js +55 -78
- package/dist/accessi-module/security/publicAuthRateLimit.js.map +1 -1
- package/dist/accessi-module/security/rateLimitStore.d.ts +34 -0
- package/dist/accessi-module/security/rateLimitStore.js +145 -0
- package/dist/accessi-module/security/rateLimitStore.js.map +1 -0
- package/dist/accessi-module/security/refreshTokenRotation.d.ts +40 -0
- package/dist/accessi-module/security/refreshTokenRotation.js +91 -0
- package/dist/accessi-module/security/refreshTokenRotation.js.map +1 -0
- package/dist/accessi-module/security/serviceTokenGuard.d.ts +3 -1
- package/dist/accessi-module/security/serviceTokenGuard.js +11 -6
- package/dist/accessi-module/security/serviceTokenGuard.js.map +1 -1
- package/dist/accessi-module/security/serviceTokenRateLimit.d.ts +5 -4
- package/dist/accessi-module/security/serviceTokenRateLimit.js +33 -29
- package/dist/accessi-module/security/serviceTokenRateLimit.js.map +1 -1
- package/dist/accessi-module/security/sessionRevocation.d.ts +52 -0
- package/dist/accessi-module/security/sessionRevocation.js +124 -0
- package/dist/accessi-module/security/sessionRevocation.js.map +1 -0
- package/dist/accessi-module/security/validateOptions.d.ts +19 -0
- package/dist/accessi-module/security/validateOptions.js +115 -0
- package/dist/accessi-module/security/validateOptions.js.map +1 -0
- package/dist/emilsoftware-utilities-2.0.0-dev.69.tgz +0 -0
- package/dist/initEmilsoftwareModule.js +39 -3
- package/dist/initEmilsoftwareModule.js.map +1 -1
- package/dist/scripts/startAccessiService.d.ts +1 -0
- package/dist/scripts/startAccessiService.js +11 -0
- package/dist/scripts/startAccessiService.js.map +1 -0
- package/docs/accessi-openapi-fingerprint.json +190 -0
- package/docs/gateway-rate-limit.md +98 -0
- package/docs/standalone-service.md +176 -0
- package/integration-prompt.md +299 -8
- package/package.json +11 -5
- package/dist/emilsoftware-utilities-2.0.0-dev.67.tgz +0 -0
|
@@ -57,6 +57,7 @@ var AuthService_1;
|
|
|
57
57
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
58
|
exports.AuthService = exports.PASSWORD_LOGIN_DISABLED = void 0;
|
|
59
59
|
const common_1 = require("@nestjs/common");
|
|
60
|
+
const crypto_1 = require("crypto");
|
|
60
61
|
const TwoFactorService_1 = require("../TwoFactorService/TwoFactorService");
|
|
61
62
|
const jwt = __importStar(require("jsonwebtoken"));
|
|
62
63
|
const Orm_1 = require("../../../Orm");
|
|
@@ -66,6 +67,8 @@ const UserService_1 = require("../UserService/UserService");
|
|
|
66
67
|
const FiltriService_1 = require("../FiltriService/FiltriService");
|
|
67
68
|
const authenticatedToken_1 = require("../../security/authenticatedToken");
|
|
68
69
|
const passwordResetToken_1 = require("../../security/passwordResetToken");
|
|
70
|
+
const sessionRevocation_1 = require("../../security/sessionRevocation");
|
|
71
|
+
const refreshTokenRotation_1 = require("../../security/refreshTokenRotation");
|
|
69
72
|
const jwtTokenOptions_1 = require("../../security/jwtTokenOptions");
|
|
70
73
|
const passwordPolicy_1 = require("../../security/passwordPolicy");
|
|
71
74
|
const Logger_1 = require("../../../Logger");
|
|
@@ -102,8 +105,7 @@ let AuthService = AuthService_1 = class AuthService {
|
|
|
102
105
|
const nodeEnv = ((_a = process.env.NODE_ENV) !== null && _a !== void 0 ? _a : "production").toLowerCase();
|
|
103
106
|
return nodeEnv !== "production";
|
|
104
107
|
}
|
|
105
|
-
|
|
106
|
-
createAccessiToken(utente, methods = [], tokenOptions = {}) {
|
|
108
|
+
createToken(utente, methods, type, tokenOptions = {}) {
|
|
107
109
|
var _a, _b;
|
|
108
110
|
if (!(utente === null || utente === void 0 ? void 0 : utente.codiceUtente)) {
|
|
109
111
|
throw new Error('Impossibile creare un token senza un utente Accessi valido.');
|
|
@@ -117,10 +119,12 @@ let AuthService = AuthService_1 = class AuthService {
|
|
|
117
119
|
? Number.isFinite(expiresIn) && expiresIn > 0
|
|
118
120
|
: typeof expiresIn === 'string' && expiresIn.trim() !== '';
|
|
119
121
|
if (!expiresInIsValid) {
|
|
120
|
-
throw new Error('
|
|
122
|
+
throw new Error('Durata token non configurata: impossibile emettere token senza scadenza.');
|
|
121
123
|
}
|
|
122
|
-
const signing =
|
|
123
|
-
|
|
124
|
+
const signing = type === 'refresh'
|
|
125
|
+
? (0, jwtTokenOptions_1.getAccessiRefreshTokenSigningConfig)(this.accessiOptions)
|
|
126
|
+
: (0, jwtTokenOptions_1.getAccessiAccessTokenSigningConfig)(this.accessiOptions);
|
|
127
|
+
const token = jwt.sign(Object.assign(Object.assign({}, ((_b = tokenOptions.extraClaims) !== null && _b !== void 0 ? _b : {})), { utente, typ: type, amr: methods, jti: (0, crypto_1.randomUUID)() }), signing.key, Object.assign({ expiresIn: expiresIn, algorithm: signing.algorithm }, signing.signOptions));
|
|
124
128
|
// Difesa in profondita: un `expiresIn` malformato farebbe emettere un token permanente.
|
|
125
129
|
const decoded = jwt.decode(token);
|
|
126
130
|
const decodedPayload = decoded && typeof decoded === 'object' ? decoded : undefined;
|
|
@@ -137,6 +141,23 @@ let AuthService = AuthService_1 = class AuthService {
|
|
|
137
141
|
type: 'Bearer',
|
|
138
142
|
};
|
|
139
143
|
}
|
|
144
|
+
/** Creates the normal internal JWT consumed by all existing Accessi guards. */
|
|
145
|
+
createAccessiToken(utente, methods = [], tokenOptions = {}) {
|
|
146
|
+
return this.createToken(utente, methods, 'access', tokenOptions);
|
|
147
|
+
}
|
|
148
|
+
/** Emette il refresh token quando `jwtOptions.refreshExpiresIn` e configurato. */
|
|
149
|
+
createRefreshToken(utente, methods = []) {
|
|
150
|
+
const expiresIn = this.accessiOptions.jwtOptions.refreshExpiresIn;
|
|
151
|
+
if (!expiresIn)
|
|
152
|
+
return undefined;
|
|
153
|
+
return this.createToken(utente, methods, 'refresh', { expiresIn });
|
|
154
|
+
}
|
|
155
|
+
/** Crea la coppia access + refresh token usata da login, 2FA e SSO. */
|
|
156
|
+
createTokenPair(utente, methods = []) {
|
|
157
|
+
const access = this.createAccessiToken(utente, methods);
|
|
158
|
+
const refresh = this.createRefreshToken(utente, methods);
|
|
159
|
+
return Object.assign({ access }, (refresh ? { refresh } : {}));
|
|
160
|
+
}
|
|
140
161
|
/**
|
|
141
162
|
* Emette l'access token per l'utente target, con l'attore registrato nelle
|
|
142
163
|
* claim `act` e `loginAs`. La durata e' quella standard di jwtOptions.expiresIn.
|
|
@@ -278,6 +299,9 @@ let AuthService = AuthService_1 = class AuthService {
|
|
|
278
299
|
if (!codiceUtente) {
|
|
279
300
|
return { active: false };
|
|
280
301
|
}
|
|
302
|
+
if (yield (0, sessionRevocation_1.isAccessiTokenRevoked)(this.accessiOptions, decoded, codiceUtente)) {
|
|
303
|
+
return { active: false };
|
|
304
|
+
}
|
|
281
305
|
const currentUser = yield this.userService.getAuthenticatedUserSnapshot(codiceUtente);
|
|
282
306
|
if (!currentUser ||
|
|
283
307
|
!(0, authenticatedToken_1.isAuthenticatedUserEnabledForJwt)(currentUser) ||
|
|
@@ -307,6 +331,72 @@ let AuthService = AuthService_1 = class AuthService {
|
|
|
307
331
|
return introspection.payload;
|
|
308
332
|
});
|
|
309
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Scambia un refresh token valido con una nuova coppia access + refresh.
|
|
336
|
+
*
|
|
337
|
+
* Il refresh token non e accettato dai guard API: ha `typ: "refresh"`.
|
|
338
|
+
*/
|
|
339
|
+
refreshAccessToken(refreshToken) {
|
|
340
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
341
|
+
if (!this.accessiOptions.jwtOptions.refreshExpiresIn) {
|
|
342
|
+
throw new common_1.UnauthorizedException('Refresh token non abilitato.');
|
|
343
|
+
}
|
|
344
|
+
if (typeof refreshToken !== 'string' || refreshToken.trim() === '') {
|
|
345
|
+
throw new common_1.UnauthorizedException('Refresh token mancante.');
|
|
346
|
+
}
|
|
347
|
+
const verification = (0, jwtTokenOptions_1.getAccessiRefreshTokenVerificationConfig)(this.accessiOptions);
|
|
348
|
+
let decoded;
|
|
349
|
+
try {
|
|
350
|
+
decoded = jwt.verify(refreshToken.trim(), verification.key, verification.verifyOptions);
|
|
351
|
+
}
|
|
352
|
+
catch (_a) {
|
|
353
|
+
throw new common_1.UnauthorizedException('Refresh token non valido o scaduto.');
|
|
354
|
+
}
|
|
355
|
+
const codiceUtente = (0, authenticatedToken_1.resolveCodiceUtenteFromTokenPayload)(decoded, 'refresh');
|
|
356
|
+
if (!codiceUtente) {
|
|
357
|
+
throw new common_1.UnauthorizedException('Refresh token privo di un utente valido.');
|
|
358
|
+
}
|
|
359
|
+
if (yield (0, sessionRevocation_1.isAccessiTokenRevoked)(this.accessiOptions, decoded, codiceUtente)) {
|
|
360
|
+
throw new common_1.UnauthorizedException('Sessione revocata.');
|
|
361
|
+
}
|
|
362
|
+
const currentUser = yield this.userService.getAuthenticatedUserSnapshot(codiceUtente);
|
|
363
|
+
if (!(0, authenticatedToken_1.isAuthenticatedUserEnabledForJwt)(currentUser) || !(0, authenticatedToken_1.isAccessiTokenAllowedForUser)(decoded, currentUser)) {
|
|
364
|
+
throw new common_1.UnauthorizedException('Utente non piu autorizzato.');
|
|
365
|
+
}
|
|
366
|
+
const rotationStore = (0, refreshTokenRotation_1.getRefreshTokenRotationStore)(this.accessiOptions);
|
|
367
|
+
if (rotationStore) {
|
|
368
|
+
const decodedRecord = decoded;
|
|
369
|
+
const jti = typeof decodedRecord.jti === 'string' ? decodedRecord.jti : undefined;
|
|
370
|
+
const expiresAt = Number(decodedRecord.exp);
|
|
371
|
+
if (!jti || !Number.isFinite(expiresAt)) {
|
|
372
|
+
throw new common_1.UnauthorizedException('Refresh token privo di jti o scadenza.');
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
const consumed = yield rotationStore.consume(jti, expiresAt * 1000);
|
|
376
|
+
if (!consumed) {
|
|
377
|
+
throw new common_1.UnauthorizedException('Refresh token gia utilizzato.');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
if (error instanceof common_1.UnauthorizedException)
|
|
382
|
+
throw error;
|
|
383
|
+
throw new common_1.ServiceUnavailableException({
|
|
384
|
+
code: 'ACCESSI_REFRESH_ROTATION_UNAVAILABLE',
|
|
385
|
+
message: 'Rotazione refresh token non disponibile. Riprova piu tardi.',
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const login = yield this.getLoginResultForUser(codiceUtente);
|
|
390
|
+
const methods = Array.isArray(decoded.amr)
|
|
391
|
+
? (decoded.amr.filter((method) => typeof method === 'string'))
|
|
392
|
+
: [];
|
|
393
|
+
const pair = this.createTokenPair(login.utente, methods);
|
|
394
|
+
login.token = pair.access;
|
|
395
|
+
if (pair.refresh)
|
|
396
|
+
login.refreshToken = pair.refresh;
|
|
397
|
+
return login;
|
|
398
|
+
});
|
|
399
|
+
}
|
|
310
400
|
/** Starts a second-factor challenge after the hosting backend has verified an SSO identity. */
|
|
311
401
|
beginFederatedTwoFactor(codiceUtente, identityKey) {
|
|
312
402
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -342,7 +432,10 @@ let AuthService = AuthService_1 = class AuthService {
|
|
|
342
432
|
const proof = yield this.twoFactorService.consume(challengeId, code);
|
|
343
433
|
yield this.validateTwoFactorProof(proof);
|
|
344
434
|
const result = yield this.getLoginResultForUser(proof.codiceUtente, scope);
|
|
345
|
-
|
|
435
|
+
const tokens = this.createTokenPair(result.utente, [proof.mode, 'otp']);
|
|
436
|
+
result.token = tokens.access;
|
|
437
|
+
if (tokens.refresh)
|
|
438
|
+
result.refreshToken = tokens.refresh;
|
|
346
439
|
yield Orm_1.Orm.execute(this.accessiOptions.databaseOptions, 'UPDATE UTENTI SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE CODUTE = ?', [proof.codiceUtente]);
|
|
347
440
|
if (proof.mode === 'federated') {
|
|
348
441
|
yield Orm_1.Orm.execute(this.accessiOptions.databaseOptions, 'UPDATE UTENTI_IDENTITA_EXT SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE IDNKEY = ?', [proof.identityKey]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthService.js","sourceRoot":"","sources":["../../../../src/accessi-module/Services/AuthService/AuthService.ts"],"names":[],"mappings":"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","sourcesContent":["import { Inject, Injectable, UnauthorizedException } from \"@nestjs/common\";\nimport { TwoFactorService, TwoFactorProof } from '../TwoFactorService/TwoFactorService';\nimport * as jwt from \"jsonwebtoken\";\nimport { Orm } from \"../../../Orm\";\nimport { CryptUtilities, PasswordUtilities, RestUtilities } from \"../../../Utilities\";\nimport type { AccessiOptions } from \"../../AccessiModule\";\nimport { LoginRequest } from \"../../Dtos/LoginRequest\";\nimport { LoginResult } from \"../../Dtos/LoginResponse\";\nimport { StatoRegistrazione } from \"../../Dtos/StatoRegistrazione\";\nimport { UserService } from \"../UserService/UserService\";\nimport { FiltriService } from \"../FiltriService/FiltriService\";\nimport {\n buildAuthenticatedTokenPayload,\n isAuthenticatedUserEnabledForJwt,\n isAccessiTokenAllowedForUser,\n resolveCodiceUtenteFromTokenPayload,\n} from \"../../security/authenticatedToken\";\nimport {\n getAccessiJwtSecret,\n verifyPasswordResetToken,\n} from \"../../security/passwordResetToken\";\nimport {\n getAccessiAccessTokenSigningConfig,\n getAccessiAccessTokenVerificationConfig,\n} from \"../../security/jwtTokenOptions\";\nimport { assertStrongPassword } from '../../security/passwordPolicy';\nimport { Logger } from \"../../../Logger\";\nimport { TokenResult } from '../../Dtos/TokenResult';\n\n/** Error code deliberately returned when a user is configured as SSO-only. */\nexport const PASSWORD_LOGIN_DISABLED = 'PASSWORD_LOGIN_DISABLED';\n\n/** Esito di una verifica token usata dall'endpoint di introspection. */\nexport interface AccessiTokenIntrospectionResult {\n active: boolean;\n codiceUtente?: number;\n payload?: Record<string, unknown>;\n}\n\ninterface AccessiTokenIssueOptions {\n /** Sovrascrive jwtOptions.expiresIn per token a durata ridotta (es. Login as). */\n expiresIn?: string | number;\n /** Claim aggiuntive, per esempio l'attore che ha generato un token di impersonazione. */\n extraClaims?: Record<string, unknown>;\n}\n\n@Injectable()\nexport class AuthService {\n private readonly logger = new Logger(AuthService.name);\n\n constructor(\n private userService: UserService,\n private filtriService: FiltriService,\n @Inject(\"ACCESSI_OPTIONS\") private readonly accessiOptions: AccessiOptions,\n private readonly twoFactorService: TwoFactorService,\n ) {}\n\n private async refreshPasswordExpiration(codiceUtente: number): Promise<void> {\n if (!this.accessiOptions.passwordExpiration) {\n return;\n }\n\n const configuredDays = Number(this.accessiOptions.passwordExpirationDays);\n const expirationDays =\n Number.isFinite(configuredDays) && configuredDays > 0\n ? Math.trunc(configuredDays)\n : 90;\n\n const query = `UPDATE UTENTI SET DATSCAPWD = DATEADD(${expirationDays} DAY TO CURRENT_TIMESTAMP) WHERE CODUTE = ?`;\n await Orm.execute(this.accessiOptions.databaseOptions, query, [codiceUtente]);\n }\n\n private isMockDemoUserEnabled(): boolean {\n if (!this.accessiOptions.mockDemoUser) {\n return false;\n }\n\n // La backdoor mock non e mai attiva in produzione, nemmeno con variabili d'ambiente,\n // perche emette un superutente senza verifica password.\n const nodeEnv = (process.env.NODE_ENV ?? \"production\").toLowerCase();\n return nodeEnv !== \"production\";\n }\n\n /** Creates the normal internal JWT consumed by all existing Accessi guards. */\n public createAccessiToken(\n utente: LoginResult['utente'],\n methods: string[] = [],\n tokenOptions: AccessiTokenIssueOptions = {},\n ): TokenResult {\n if (!utente?.codiceUtente) {\n throw new Error('Impossibile creare un token senza un utente Accessi valido.');\n }\n const loginAs = methods.includes('login_as');\n if ((utente.flagDueFattori === true || Number(utente.flagDueFattori) === 1) && !methods.includes('otp') && !loginAs) {\n throw new UnauthorizedException('Verifica del codice di accesso richiesta.');\n }\n\n const expiresIn = tokenOptions.expiresIn ?? this.accessiOptions.jwtOptions.expiresIn;\n const expiresInIsValid = typeof expiresIn === 'number'\n ? Number.isFinite(expiresIn) && expiresIn > 0\n : typeof expiresIn === 'string' && expiresIn.trim() !== '';\n if (!expiresInIsValid) {\n throw new Error('jwtOptions.expiresIn non configurato: impossibile emettere token senza scadenza.');\n }\n\n const signing = getAccessiAccessTokenSigningConfig(this.accessiOptions);\n const token = jwt.sign(\n { ...(tokenOptions.extraClaims ?? {}), utente, typ: 'access', amr: methods },\n signing.key,\n {\n expiresIn: expiresIn as jwt.SignOptions['expiresIn'],\n algorithm: signing.algorithm,\n ...signing.signOptions,\n },\n );\n\n // Difesa in profondita: un `expiresIn` malformato farebbe emettere un token permanente.\n const decoded = jwt.decode(token);\n const decodedPayload = decoded && typeof decoded === 'object' ? decoded as jwt.JwtPayload : undefined;\n if (typeof decodedPayload?.exp !== 'number') {\n throw new Error('Token emesso senza scadenza: configurazione JWT non valida.');\n }\n\n // Il contratto TokenResult espone sempre la validita in secondi, anche quando\n // jwtOptions.expiresIn usa un formato leggibile come '24h'.\n const issuedAt = typeof decodedPayload.iat === 'number' ? decodedPayload.iat : Math.floor(Date.now() / 1000);\n const expiresInSeconds = Math.max(0, Math.trunc(decodedPayload.exp - issuedAt));\n\n return {\n expiresIn: String(expiresInSeconds),\n value: token,\n type: 'Bearer',\n };\n }\n\n /**\n * Emette l'access token per l'utente target, con l'attore registrato nelle\n * claim `act` e `loginAs`. La durata e' quella standard di jwtOptions.expiresIn.\n */\n public createLoginAsToken(\n utente: LoginResult['utente'],\n actor: { codiceUtente: number; email?: string },\n ): TokenResult {\n return this.createAccessiToken(utente, ['login_as'], {\n extraClaims: {\n loginAs: true,\n act: {\n sub: String(actor.codiceUtente),\n email: actor.email,\n },\n },\n });\n }\n\n /** Builds the standard login response for a user authenticated by a supported method. */\n public async getLoginResultForUser(codiceUtente: number, scope?: string): Promise<LoginResult> {\n const users = await this.userService.getUsers(\n { codiceUtente },\n { includeExtensionFields: true, includeGrants: true, ...(scope ? { scope } : {}) },\n );\n const result = users[0];\n if (!result?.utente) {\n throw new Error('Utente Accessi non trovato.');\n }\n const current = await this.userService.getAuthenticatedUserSnapshot(codiceUtente);\n if (!isAuthenticatedUserEnabledForJwt(current)) throw new UnauthorizedException('Utente non abilitato.');\n result.utente = { ...result.utente, ...current };\n\n return {\n utente: result.utente,\n filtri: await this.filtriService.getFiltriUser(codiceUtente),\n userGrants: result.userGrants,\n extensionFields: result.extensionFields,\n };\n }\n\n /** Users without a row retain the historic password-login enabled default. */\n private async isPasswordLoginEnabled(codiceUtente: number): Promise<boolean> {\n if (this.accessiOptions.federatedAuthentication?.enabled !== true) return true;\n\n const rows = await Orm.query(\n this.accessiOptions.databaseOptions,\n 'SELECT COALESCE(FLGPASSWORD, 1) AS password_login_enabled FROM UTENTI_CONFIG WHERE CODUTE = ?',\n [codiceUtente],\n );\n const policy = rows.map(RestUtilities.convertKeysToCamelCase)[0] as { passwordLoginEnabled?: unknown } | undefined;\n return policy?.passwordLoginEnabled !== false && policy?.passwordLoginEnabled !== 0 && policy?.passwordLoginEnabled !== '0';\n }\n\n /**\n * Autentica con credenziali locali e restituisce profilo, filtri e grant effettivi.\n * Non crea il JWT: il controller o il flusso SSO deve chiamare `createAccessiToken` sul risultato.\n * Per utenti SSO-only genera `PASSWORD_LOGIN_DISABLED`, da trattare come istruzione a usare l'SSO.\n */\n async login(request: LoginRequest): Promise<LoginResult> {\n const mockDemoUserEnabled = this.isMockDemoUserEnabled();\n\n if (\n mockDemoUserEnabled &&\n request.email.toLowerCase() === \"demo\"\n ) {\n return this.getDemoUser();\n }\n\n if (\n mockDemoUserEnabled &&\n request.email.toLowerCase() === \"admin\"\n ) {\n return this.getAdminUser();\n }\n\n const utente = await this.userService.getUserByEmail(\n request.email.trim().toLowerCase()\n );\n if (!utente) {\n if (!request.password) return { passwordRequired: true };\n throw new Error(\"Nome utente o password errata!\");\n }\n\n const currentUser = await this.userService.getAuthenticatedUserSnapshot(utente.codiceUtente);\n if (isAuthenticatedUserEnabledForJwt(currentUser) && currentUser.flagDueFattori && currentUser.passwordlessLoginEnabled) {\n return { challenge: await this.twoFactorService.issue({ codiceUtente: utente.codiceUtente, email: (currentUser.email ?? '').trim(), mode: 'passwordless' }) };\n }\n // The email-only step has the same response for unknown and ordinary local accounts.\n if (!request.password) return { passwordRequired: true };\n\n switch (utente.statoRegistrazione) {\n case undefined:\n throw new Error(\n \"Struttura dati compromessa: Stato Registrazione inesistente.\"\n );\n case StatoRegistrazione.BLOCC:\n case StatoRegistrazione.DELETE:\n throw new Error(\"Utente non abilitato\");\n case StatoRegistrazione.INVIO:\n throw new Error(\"Rinnovo password necessario.\");\n }\n\n if (utente.statoRegistrazione !== StatoRegistrazione.CONF) {\n throw new Error(\n `Errore generico. Stato di registrazione non valido: ${utente.statoRegistrazione}.`\n );\n }\n\n if (!isAuthenticatedUserEnabledForJwt(currentUser)) throw new Error('Utente non abilitato');\n if (!(await this.isPasswordLoginEnabled(utente.codiceUtente))) {\n throw new Error(PASSWORD_LOGIN_DISABLED);\n }\n\n if (typeof request.password !== 'string' || request.password.length === 0) {\n throw new Error('Nome utente o password errata!');\n }\n\n const isPasswordValid = await this.verifyPassword(\n utente.codiceUtente,\n request.password\n );\n if (!isPasswordValid) throw new Error(\"Nome utente o password errata!\");\n\n if (\n this.accessiOptions.passwordExpiration &&\n this.accessiOptions.passwordExpiration == true\n ) {\n const today = new Date();\n const targetDate = utente.dataScadenzaPassword\n ? new Date(utente.dataScadenzaPassword)\n : undefined;\n\n // Legacy users may not have an expiration date. Preserve the former non-expiring behaviour for them.\n if (targetDate && !Number.isNaN(targetDate.getTime()) && today >= targetDate) {\n throw new Error(\"PASSWORD_EXPIRED\");\n }\n }\n\n if (currentUser.flagDueFattori) {\n return { challenge: await this.twoFactorService.issue({ codiceUtente: utente.codiceUtente, email: currentUser.email ?? '', mode: 'password' }) };\n }\n\n const updateLastAccessDateQuery =\n \"UPDATE UTENTI SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE CODUTE = ?\";\n await Orm.query(\n this.accessiOptions.databaseOptions,\n updateLastAccessDateQuery,\n [utente.codiceUtente]\n );\n\n return this.getLoginResultForUser(utente.codiceUtente, request.scope);\n }\n\n /**\n * Verifica un access token Accessi senza sollevare eccezioni per token invalidi.\n *\n * Gli errori di configurazione o database continuano a propagarsi: un problema\n * infrastrutturale non deve essere confuso con un token scaduto.\n */\n public async introspectAccessToken(token: string): Promise<AccessiTokenIntrospectionResult> {\n if (typeof token !== \"string\" || token.trim() === \"\") {\n return { active: false };\n }\n\n const verification = getAccessiAccessTokenVerificationConfig(this.accessiOptions);\n let decoded: unknown;\n try {\n decoded = jwt.verify(token.trim(), verification.key, verification.verifyOptions);\n } catch {\n return { active: false };\n }\n\n const codiceUtente = resolveCodiceUtenteFromTokenPayload(decoded);\n if (!codiceUtente) {\n return { active: false };\n }\n\n const currentUser = await this.userService.getAuthenticatedUserSnapshot(codiceUtente);\n if (\n !currentUser ||\n !isAuthenticatedUserEnabledForJwt(currentUser) ||\n !isAccessiTokenAllowedForUser(decoded, currentUser)\n ) {\n return { active: false };\n }\n\n return {\n active: true,\n codiceUtente,\n payload: buildAuthenticatedTokenPayload(decoded, currentUser),\n };\n }\n\n /**\n * Verifica un JWT Accessi e ricostruisce il profilo corrente dal database.\n * Questo evita che privilegi, stato utente o flag amministrativi presenti in un token vecchio restino validi.\n */\n public async getAuthenticatedTokenPayload(token: string): Promise<Record<string, unknown>> {\n if (typeof token !== \"string\" || token.trim() === \"\") {\n throw new Error(\"Token non fornito.\");\n }\n\n const introspection = await this.introspectAccessToken(token);\n if (!introspection.active || !introspection.payload) {\n throw new Error(\"Token non valido o utente non autorizzato.\");\n }\n\n return introspection.payload;\n }\n\n /** Starts a second-factor challenge after the hosting backend has verified an SSO identity. */\n public async beginFederatedTwoFactor(codiceUtente: number, identityKey: string): Promise<LoginResult> {\n const user = await this.userService.getAuthenticatedUserSnapshot(codiceUtente);\n if (!isAuthenticatedUserEnabledForJwt(user) || !user.flagDueFattori) throw new UnauthorizedException();\n return { challenge: await this.twoFactorService.issue({ codiceUtente, email: user.email ?? '', mode: 'federated', identityKey }) };\n }\n\n private async validateTwoFactorProof(proof: TwoFactorProof): Promise<void> {\n const user = await this.userService.getAuthenticatedUserSnapshot(proof.codiceUtente);\n if (!isAuthenticatedUserEnabledForJwt(user) || !user.flagDueFattori || user.email?.trim().toLowerCase() !== proof.email.trim().toLowerCase()) {\n throw new UnauthorizedException('Profilo modificato o utente non abilitato. Ripeti l accesso.');\n }\n if (proof.mode === 'passwordless' && !user.passwordlessLoginEnabled) throw new UnauthorizedException('Accesso senza password disabilitato.');\n if (proof.mode === 'password' && !(await this.isPasswordLoginEnabled(proof.codiceUtente))) throw new UnauthorizedException('Login locale disabilitato.');\n if (proof.mode === 'federated') {\n if (!this.accessiOptions.federatedAuthentication?.enabled) throw new UnauthorizedException();\n const rows = await Orm.query(this.accessiOptions.databaseOptions,\n 'SELECT I.IDNKEY FROM UTENTI_IDENTITA_EXT I INNER JOIN SSO_PROVIDER P ON P.PROVIDER = I.PROVIDER WHERE I.IDNKEY = ? AND I.CODUTE = ? AND I.FLGATTIVO = 1 AND P.FLGATTIVO = 1',\n [proof.identityKey, proof.codiceUtente], false);\n if (!rows.length) throw new UnauthorizedException('Identita SSO non piu abilitata.');\n }\n }\n\n public async verifyTwoFactor(challengeId: string, code: string, scope?: string): Promise<LoginResult> {\n const proof = await this.twoFactorService.consume(challengeId, code);\n await this.validateTwoFactorProof(proof);\n const result = await this.getLoginResultForUser(proof.codiceUtente, scope);\n result.token = this.createAccessiToken(result.utente, [proof.mode, 'otp']);\n await Orm.execute(this.accessiOptions.databaseOptions, 'UPDATE UTENTI SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE CODUTE = ?', [proof.codiceUtente]);\n if (proof.mode === 'federated') {\n await Orm.execute(this.accessiOptions.databaseOptions, 'UPDATE UTENTI_IDENTITA_EXT SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE IDNKEY = ?', [proof.identityKey]);\n }\n return result;\n }\n\n public async resendTwoFactor(challengeId: string): Promise<LoginResult> {\n await this.validateTwoFactorProof(await this.twoFactorService.describe(challengeId));\n return { challenge: await this.twoFactorService.resend(challengeId) };\n }\n\n /**\n * Persiste una password hashata e aggiorna la scadenza, se la policy password e attiva. Non invia email.\n * Con `enforcePolicy` (default true) valida la password secondo la policy moderna; i flussi di\n * migrazione delle password legacy passano `enforcePolicy: false` per non bloccare password storiche.\n */\n public async setPassword(\n codiceUtente: number,\n nuovaPassword: string,\n options?: { enforcePolicy?: boolean },\n ) {\n if (options?.enforcePolicy !== false) {\n assertStrongPassword(nuovaPassword);\n }\n try {\n const query = `UPDATE OR INSERT INTO UTENTI_PWD (CODUTE, PWD) VALUES (?, ?)`;\n const hashedPassword = PasswordUtilities.hashPassword(nuovaPassword);\n\n const result = await Orm.execute(this.accessiOptions.databaseOptions, query, [\n codiceUtente,\n hashedPassword,\n ]);\n await this.refreshPasswordExpiration(codiceUtente);\n return result;\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Converte le password legacy cifrate nel formato hash compatibile, senza conoscere le password in chiaro.\n * E idempotente: hash moderni e gia migrati vengono ignorati.\n */\n public async migrateLegacyEncryptedPasswords(): Promise<void> {\n const startedAt = performance.now();\n this.logger.info(\"Avvio migrazione password legacy accessi.\");\n const results = await Orm.query(\n this.accessiOptions.databaseOptions,\n \"SELECT CODUTE AS codice_utente, PWD AS password FROM UTENTI_PWD WHERE PWD IS NOT NULL\",\n []\n );\n\n const rows = results.map(RestUtilities.convertKeysToCamelCase) as {\n codiceUtente?: number;\n password?: string;\n }[];\n let migratedCount = 0;\n let skippedCount = 0;\n\n for (const row of rows) {\n const codiceUtente = Number(row.codiceUtente);\n const storedPassword = typeof row.password === \"string\" ? row.password : null;\n\n if (\n !codiceUtente ||\n !storedPassword ||\n PasswordUtilities.isPasswordHash(storedPassword) ||\n PasswordUtilities.isLegacyPasswordHash(storedPassword)\n ) {\n skippedCount += 1;\n continue;\n }\n\n const protectedLegacyPassword =\n PasswordUtilities.hashLegacyEncryptedPassword(storedPassword);\n\n await Orm.execute(\n this.accessiOptions.databaseOptions,\n \"UPDATE UTENTI_PWD SET PWD = ? WHERE CODUTE = ? AND PWD = ?\",\n [protectedLegacyPassword, codiceUtente, storedPassword]\n );\n migratedCount += 1;\n }\n\n this.logger.info(\n `Migrazione password legacy accessi completata. Letti=${rows.length}, migrati=${migratedCount}, ignorati=${skippedCount}, durataMs=${(performance.now() - startedAt).toFixed(2)}`\n );\n }\n\n /** Verifica una password locale e migra automaticamente il formato legacy dopo una verifica positiva. */\n async verifyPassword(\n codiceUtente: number,\n plainPassword: string\n ): Promise<boolean> {\n const query = `SELECT PWD AS password FROM UTENTI_PWD WHERE CODUTE = ?`;\n const result = (await Orm.query(\n this.accessiOptions.databaseOptions,\n query,\n [codiceUtente]\n ).then((results) => results.map(RestUtilities.convertKeysToCamelCase))) as {\n password: string;\n }[];\n\n const stored = result[0];\n if (!stored || typeof stored.password !== \"string\") {\n return false;\n }\n\n const storedPassword = stored.password;\n\n if (PasswordUtilities.isPasswordHash(storedPassword)) {\n return PasswordUtilities.verifyPassword(plainPassword, storedPassword);\n }\n\n const legacyEncryptedPassword = CryptUtilities.encrypt(\n plainPassword,\n this.accessiOptions.encryptionKey\n );\n\n if (PasswordUtilities.isLegacyPasswordHash(storedPassword)) {\n const isMigratedLegacyPasswordValid =\n PasswordUtilities.verifyLegacyEncryptedPassword(\n legacyEncryptedPassword,\n storedPassword\n );\n\n if (isMigratedLegacyPasswordValid) {\n await this.setPassword(codiceUtente, plainPassword, { enforcePolicy: false });\n }\n\n return isMigratedLegacyPasswordValid;\n }\n\n const isLegacyPasswordValid = PasswordUtilities.timingSafeStringEquals(\n storedPassword,\n legacyEncryptedPassword,\n );\n\n if (isLegacyPasswordValid) {\n await this.setPassword(codiceUtente, plainPassword, { enforcePolicy: false });\n }\n\n return isLegacyPasswordValid;\n }\n\n /** Restituisce l'utente fittizio amministratore; usabile solo con `mockDemoUser` esplicitamente abilitato. */\n async getAdminUser(): Promise<LoginResult> {\n return {\n utente: {\n codiceUtente: 6789,\n email: \"admin\",\n statoRegistrazione: StatoRegistrazione.CONF,\n cognome: \"Admin\",\n nome: \"Admin\",\n flagGdpr: true,\n avatar: \"/path/to/avatar.jpg\",\n flagDueFattori: false,\n codiceLingua: \"IT\",\n cellulare: \"+391234567890\",\n flagSuper: true,\n roles: [],\n permissions: [],\n },\n filtri: null,\n userGrants: {\n abilitazioni: [],\n grants: [],\n ruoli: [],\n },\n };\n }\n\n /** Restituisce l'utente demo fittizio; non contiene dati o grant reali. */\n getDemoUser(): LoginResult {\n return {\n utente: {\n codiceUtente: 12345,\n email: \"jdoe\",\n statoRegistrazione: StatoRegistrazione.CONF,\n cognome: \"Doe\",\n nome: \"John\",\n flagGdpr: true,\n avatar: \"/path/to/avatar.jpg\",\n flagDueFattori: false,\n codiceLingua: \"IT\",\n cellulare: \"+391234567890\",\n flagSuper: false,\n roles: [],\n permissions: [],\n },\n filtri: null,\n userGrants: {\n abilitazioni: [],\n grants: [],\n ruoli: [],\n },\n };\n }\n\n /**\n * Consuma un token monouso di reset, riporta l'utente allo stato confermato e salva la nuova password.\n * Il nonce in `UTENTI.KEYREG` viene annullato prima di impostare la password, impedendo il riuso del token.\n */\n public async confirmResetPassword(\n token: string,\n newPassword: string\n ): Promise<void> {\n try {\n if (typeof token !== \"string\" || token.trim() === \"\") {\n throw new Error(\"Token non valido.\");\n }\n\n assertStrongPassword(newPassword);\n\n const secret = getAccessiJwtSecret(this.accessiOptions, 'reset');\n const { codiceUtente, nonce } = verifyPasswordResetToken(token.trim(), secret);\n\n const hashedPassword = PasswordUtilities.hashPassword(newPassword);\n\n await Orm.withTransaction(this.accessiOptions.databaseOptions, async (transaction) => {\n // A conditional write claims the nonce under the database row lock. A second\n // concurrent reset cannot also consume it; failures roll the whole reset back.\n const claimed = await Orm.transactionQuery<unknown>(\n transaction,\n 'UPDATE UTENTI SET KEYREG = NULL, STAREG = ? WHERE CODUTE = ? AND KEYREG = ? AND STAREG IN (?, ?) RETURNING CODUTE',\n [StatoRegistrazione.CONF, codiceUtente, nonce, StatoRegistrazione.CONF, StatoRegistrazione.INVIO],\n );\n const row = (Array.isArray(claimed) ? claimed[0] : claimed) as Record<string, unknown> | undefined;\n if (Number(row?.CODUTE ?? row?.codute) !== codiceUtente) {\n throw new Error('Token non valido, gia usato o utente non autorizzato.');\n }\n\n await Orm.transactionQuery(\n transaction,\n 'UPDATE OR INSERT INTO UTENTI_PWD (CODUTE, PWD) VALUES (?, ?) MATCHING (CODUTE)',\n [codiceUtente, hashedPassword],\n );\n\n if (this.accessiOptions.passwordExpiration) {\n const days = Number(this.accessiOptions.passwordExpirationDays);\n const expirationDays = Number.isFinite(days) && days > 0 ? Math.trunc(days) : 90;\n await Orm.transactionQuery(\n transaction,\n `UPDATE UTENTI SET DATSCAPWD = DATEADD(${expirationDays} DAY TO CURRENT_TIMESTAMP) WHERE CODUTE = ?`,\n [codiceUtente],\n );\n }\n });\n } catch (error) {\n throw error;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AuthService.js","sourceRoot":"","sources":["../../../../src/accessi-module/Services/AuthService/AuthService.ts"],"names":[],"mappings":"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","sourcesContent":["import { Inject, Injectable, ServiceUnavailableException, UnauthorizedException } from \"@nestjs/common\";\nimport { randomUUID } from \"crypto\";\nimport { TwoFactorService, TwoFactorProof } from '../TwoFactorService/TwoFactorService';\nimport * as jwt from \"jsonwebtoken\";\nimport { Orm } from \"../../../Orm\";\nimport { CryptUtilities, PasswordUtilities, RestUtilities } from \"../../../Utilities\";\nimport type { AccessiOptions } from \"../../AccessiModule\";\nimport { LoginRequest } from \"../../Dtos/LoginRequest\";\nimport { LoginResult } from \"../../Dtos/LoginResponse\";\nimport { StatoRegistrazione } from \"../../Dtos/StatoRegistrazione\";\nimport { UserService } from \"../UserService/UserService\";\nimport { FiltriService } from \"../FiltriService/FiltriService\";\nimport {\n buildAuthenticatedTokenPayload,\n isAuthenticatedUserEnabledForJwt,\n isAccessiTokenAllowedForUser,\n resolveCodiceUtenteFromTokenPayload,\n} from \"../../security/authenticatedToken\";\nimport {\n getAccessiJwtSecret,\n verifyPasswordResetToken,\n} from \"../../security/passwordResetToken\";\nimport { isAccessiTokenRevoked } from \"../../security/sessionRevocation\";\nimport { getRefreshTokenRotationStore } from \"../../security/refreshTokenRotation\";\nimport {\n getAccessiAccessTokenSigningConfig,\n getAccessiAccessTokenVerificationConfig,\n getAccessiRefreshTokenSigningConfig,\n getAccessiRefreshTokenVerificationConfig,\n} from \"../../security/jwtTokenOptions\";\nimport { assertStrongPassword } from '../../security/passwordPolicy';\nimport { Logger } from \"../../../Logger\";\nimport { TokenResult } from '../../Dtos/TokenResult';\n\n/** Error code deliberately returned when a user is configured as SSO-only. */\nexport const PASSWORD_LOGIN_DISABLED = 'PASSWORD_LOGIN_DISABLED';\n\n/** Esito di una verifica token usata dall'endpoint di introspection. */\nexport interface AccessiTokenIntrospectionResult {\n active: boolean;\n codiceUtente?: number;\n payload?: Record<string, unknown>;\n}\n\ninterface AccessiTokenIssueOptions {\n /** Sovrascrive jwtOptions.expiresIn per token a durata ridotta (es. Login as). */\n expiresIn?: string | number;\n /** Claim aggiuntive, per esempio l'attore che ha generato un token di impersonazione. */\n extraClaims?: Record<string, unknown>;\n}\n\n@Injectable()\nexport class AuthService {\n private readonly logger = new Logger(AuthService.name);\n\n constructor(\n private userService: UserService,\n private filtriService: FiltriService,\n @Inject(\"ACCESSI_OPTIONS\") private readonly accessiOptions: AccessiOptions,\n private readonly twoFactorService: TwoFactorService,\n ) {}\n\n private async refreshPasswordExpiration(codiceUtente: number): Promise<void> {\n if (!this.accessiOptions.passwordExpiration) {\n return;\n }\n\n const configuredDays = Number(this.accessiOptions.passwordExpirationDays);\n const expirationDays =\n Number.isFinite(configuredDays) && configuredDays > 0\n ? Math.trunc(configuredDays)\n : 90;\n\n const query = `UPDATE UTENTI SET DATSCAPWD = DATEADD(${expirationDays} DAY TO CURRENT_TIMESTAMP) WHERE CODUTE = ?`;\n await Orm.execute(this.accessiOptions.databaseOptions, query, [codiceUtente]);\n }\n\n private isMockDemoUserEnabled(): boolean {\n if (!this.accessiOptions.mockDemoUser) {\n return false;\n }\n\n // La backdoor mock non e mai attiva in produzione, nemmeno con variabili d'ambiente,\n // perche emette un superutente senza verifica password.\n const nodeEnv = (process.env.NODE_ENV ?? \"production\").toLowerCase();\n return nodeEnv !== \"production\";\n }\n\n private createToken(\n utente: LoginResult['utente'],\n methods: string[],\n type: 'access' | 'refresh',\n tokenOptions: AccessiTokenIssueOptions = {},\n ): TokenResult {\n if (!utente?.codiceUtente) {\n throw new Error('Impossibile creare un token senza un utente Accessi valido.');\n }\n const loginAs = methods.includes('login_as');\n if ((utente.flagDueFattori === true || Number(utente.flagDueFattori) === 1) && !methods.includes('otp') && !loginAs) {\n throw new UnauthorizedException('Verifica del codice di accesso richiesta.');\n }\n\n const expiresIn = tokenOptions.expiresIn ?? this.accessiOptions.jwtOptions.expiresIn;\n const expiresInIsValid = typeof expiresIn === 'number'\n ? Number.isFinite(expiresIn) && expiresIn > 0\n : typeof expiresIn === 'string' && expiresIn.trim() !== '';\n if (!expiresInIsValid) {\n throw new Error('Durata token non configurata: impossibile emettere token senza scadenza.');\n }\n\n const signing = type === 'refresh'\n ? getAccessiRefreshTokenSigningConfig(this.accessiOptions)\n : getAccessiAccessTokenSigningConfig(this.accessiOptions);\n const token = jwt.sign(\n {\n ...(tokenOptions.extraClaims ?? {}),\n utente,\n typ: type,\n amr: methods,\n jti: randomUUID(),\n },\n signing.key,\n {\n expiresIn: expiresIn as jwt.SignOptions['expiresIn'],\n algorithm: signing.algorithm,\n ...signing.signOptions,\n },\n );\n\n // Difesa in profondita: un `expiresIn` malformato farebbe emettere un token permanente.\n const decoded = jwt.decode(token);\n const decodedPayload = decoded && typeof decoded === 'object' ? decoded as jwt.JwtPayload : undefined;\n if (typeof decodedPayload?.exp !== 'number') {\n throw new Error('Token emesso senza scadenza: configurazione JWT non valida.');\n }\n\n // Il contratto TokenResult espone sempre la validita in secondi, anche quando\n // jwtOptions.expiresIn usa un formato leggibile come '24h'.\n const issuedAt = typeof decodedPayload.iat === 'number' ? decodedPayload.iat : Math.floor(Date.now() / 1000);\n const expiresInSeconds = Math.max(0, Math.trunc(decodedPayload.exp - issuedAt));\n\n return {\n expiresIn: String(expiresInSeconds),\n value: token,\n type: 'Bearer',\n };\n }\n\n /** Creates the normal internal JWT consumed by all existing Accessi guards. */\n public createAccessiToken(\n utente: LoginResult['utente'],\n methods: string[] = [],\n tokenOptions: AccessiTokenIssueOptions = {},\n ): TokenResult {\n return this.createToken(utente, methods, 'access', tokenOptions);\n }\n\n /** Emette il refresh token quando `jwtOptions.refreshExpiresIn` e configurato. */\n public createRefreshToken(\n utente: LoginResult['utente'],\n methods: string[] = [],\n ): TokenResult | undefined {\n const expiresIn = this.accessiOptions.jwtOptions.refreshExpiresIn;\n if (!expiresIn) return undefined;\n return this.createToken(utente, methods, 'refresh', { expiresIn });\n }\n\n /** Crea la coppia access + refresh token usata da login, 2FA e SSO. */\n public createTokenPair(\n utente: LoginResult['utente'],\n methods: string[] = [],\n ): { access: TokenResult; refresh?: TokenResult } {\n const access = this.createAccessiToken(utente, methods);\n const refresh = this.createRefreshToken(utente, methods);\n return { access, ...(refresh ? { refresh } : {}) };\n }\n\n /**\n * Emette l'access token per l'utente target, con l'attore registrato nelle\n * claim `act` e `loginAs`. La durata e' quella standard di jwtOptions.expiresIn.\n */\n public createLoginAsToken(\n utente: LoginResult['utente'],\n actor: { codiceUtente: number; email?: string },\n ): TokenResult {\n return this.createAccessiToken(utente, ['login_as'], {\n extraClaims: {\n loginAs: true,\n act: {\n sub: String(actor.codiceUtente),\n email: actor.email,\n },\n },\n });\n }\n\n /** Builds the standard login response for a user authenticated by a supported method. */\n public async getLoginResultForUser(codiceUtente: number, scope?: string): Promise<LoginResult> {\n const users = await this.userService.getUsers(\n { codiceUtente },\n { includeExtensionFields: true, includeGrants: true, ...(scope ? { scope } : {}) },\n );\n const result = users[0];\n if (!result?.utente) {\n throw new Error('Utente Accessi non trovato.');\n }\n const current = await this.userService.getAuthenticatedUserSnapshot(codiceUtente);\n if (!isAuthenticatedUserEnabledForJwt(current)) throw new UnauthorizedException('Utente non abilitato.');\n result.utente = { ...result.utente, ...current };\n\n return {\n utente: result.utente,\n filtri: await this.filtriService.getFiltriUser(codiceUtente),\n userGrants: result.userGrants,\n extensionFields: result.extensionFields,\n };\n }\n\n /** Users without a row retain the historic password-login enabled default. */\n private async isPasswordLoginEnabled(codiceUtente: number): Promise<boolean> {\n if (this.accessiOptions.federatedAuthentication?.enabled !== true) return true;\n\n const rows = await Orm.query(\n this.accessiOptions.databaseOptions,\n 'SELECT COALESCE(FLGPASSWORD, 1) AS password_login_enabled FROM UTENTI_CONFIG WHERE CODUTE = ?',\n [codiceUtente],\n );\n const policy = rows.map(RestUtilities.convertKeysToCamelCase)[0] as { passwordLoginEnabled?: unknown } | undefined;\n return policy?.passwordLoginEnabled !== false && policy?.passwordLoginEnabled !== 0 && policy?.passwordLoginEnabled !== '0';\n }\n\n /**\n * Autentica con credenziali locali e restituisce profilo, filtri e grant effettivi.\n * Non crea il JWT: il controller o il flusso SSO deve chiamare `createAccessiToken` sul risultato.\n * Per utenti SSO-only genera `PASSWORD_LOGIN_DISABLED`, da trattare come istruzione a usare l'SSO.\n */\n async login(request: LoginRequest): Promise<LoginResult> {\n const mockDemoUserEnabled = this.isMockDemoUserEnabled();\n\n if (\n mockDemoUserEnabled &&\n request.email.toLowerCase() === \"demo\"\n ) {\n return this.getDemoUser();\n }\n\n if (\n mockDemoUserEnabled &&\n request.email.toLowerCase() === \"admin\"\n ) {\n return this.getAdminUser();\n }\n\n const utente = await this.userService.getUserByEmail(\n request.email.trim().toLowerCase()\n );\n if (!utente) {\n if (!request.password) return { passwordRequired: true };\n throw new Error(\"Nome utente o password errata!\");\n }\n\n const currentUser = await this.userService.getAuthenticatedUserSnapshot(utente.codiceUtente);\n if (isAuthenticatedUserEnabledForJwt(currentUser) && currentUser.flagDueFattori && currentUser.passwordlessLoginEnabled) {\n return { challenge: await this.twoFactorService.issue({ codiceUtente: utente.codiceUtente, email: (currentUser.email ?? '').trim(), mode: 'passwordless' }) };\n }\n // The email-only step has the same response for unknown and ordinary local accounts.\n if (!request.password) return { passwordRequired: true };\n\n switch (utente.statoRegistrazione) {\n case undefined:\n throw new Error(\n \"Struttura dati compromessa: Stato Registrazione inesistente.\"\n );\n case StatoRegistrazione.BLOCC:\n case StatoRegistrazione.DELETE:\n throw new Error(\"Utente non abilitato\");\n case StatoRegistrazione.INVIO:\n throw new Error(\"Rinnovo password necessario.\");\n }\n\n if (utente.statoRegistrazione !== StatoRegistrazione.CONF) {\n throw new Error(\n `Errore generico. Stato di registrazione non valido: ${utente.statoRegistrazione}.`\n );\n }\n\n if (!isAuthenticatedUserEnabledForJwt(currentUser)) throw new Error('Utente non abilitato');\n if (!(await this.isPasswordLoginEnabled(utente.codiceUtente))) {\n throw new Error(PASSWORD_LOGIN_DISABLED);\n }\n\n if (typeof request.password !== 'string' || request.password.length === 0) {\n throw new Error('Nome utente o password errata!');\n }\n\n const isPasswordValid = await this.verifyPassword(\n utente.codiceUtente,\n request.password\n );\n if (!isPasswordValid) throw new Error(\"Nome utente o password errata!\");\n\n if (\n this.accessiOptions.passwordExpiration &&\n this.accessiOptions.passwordExpiration == true\n ) {\n const today = new Date();\n const targetDate = utente.dataScadenzaPassword\n ? new Date(utente.dataScadenzaPassword)\n : undefined;\n\n // Legacy users may not have an expiration date. Preserve the former non-expiring behaviour for them.\n if (targetDate && !Number.isNaN(targetDate.getTime()) && today >= targetDate) {\n throw new Error(\"PASSWORD_EXPIRED\");\n }\n }\n\n if (currentUser.flagDueFattori) {\n return { challenge: await this.twoFactorService.issue({ codiceUtente: utente.codiceUtente, email: currentUser.email ?? '', mode: 'password' }) };\n }\n\n const updateLastAccessDateQuery =\n \"UPDATE UTENTI SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE CODUTE = ?\";\n await Orm.query(\n this.accessiOptions.databaseOptions,\n updateLastAccessDateQuery,\n [utente.codiceUtente]\n );\n\n return this.getLoginResultForUser(utente.codiceUtente, request.scope);\n }\n\n /**\n * Verifica un access token Accessi senza sollevare eccezioni per token invalidi.\n *\n * Gli errori di configurazione o database continuano a propagarsi: un problema\n * infrastrutturale non deve essere confuso con un token scaduto.\n */\n public async introspectAccessToken(token: string): Promise<AccessiTokenIntrospectionResult> {\n if (typeof token !== \"string\" || token.trim() === \"\") {\n return { active: false };\n }\n\n const verification = getAccessiAccessTokenVerificationConfig(this.accessiOptions);\n let decoded: unknown;\n try {\n decoded = jwt.verify(token.trim(), verification.key, verification.verifyOptions);\n } catch {\n return { active: false };\n }\n\n const codiceUtente = resolveCodiceUtenteFromTokenPayload(decoded);\n if (!codiceUtente) {\n return { active: false };\n }\n if (await isAccessiTokenRevoked(this.accessiOptions, decoded as Record<string, unknown>, codiceUtente)) {\n return { active: false };\n }\n\n const currentUser = await this.userService.getAuthenticatedUserSnapshot(codiceUtente);\n if (\n !currentUser ||\n !isAuthenticatedUserEnabledForJwt(currentUser) ||\n !isAccessiTokenAllowedForUser(decoded, currentUser)\n ) {\n return { active: false };\n }\n\n return {\n active: true,\n codiceUtente,\n payload: buildAuthenticatedTokenPayload(decoded, currentUser),\n };\n }\n\n /**\n * Verifica un JWT Accessi e ricostruisce il profilo corrente dal database.\n * Questo evita che privilegi, stato utente o flag amministrativi presenti in un token vecchio restino validi.\n */\n public async getAuthenticatedTokenPayload(token: string): Promise<Record<string, unknown>> {\n if (typeof token !== \"string\" || token.trim() === \"\") {\n throw new Error(\"Token non fornito.\");\n }\n\n const introspection = await this.introspectAccessToken(token);\n if (!introspection.active || !introspection.payload) {\n throw new Error(\"Token non valido o utente non autorizzato.\");\n }\n\n return introspection.payload;\n }\n\n /**\n * Scambia un refresh token valido con una nuova coppia access + refresh.\n *\n * Il refresh token non e accettato dai guard API: ha `typ: \"refresh\"`.\n */\n public async refreshAccessToken(refreshToken: string): Promise<LoginResult> {\n if (!this.accessiOptions.jwtOptions.refreshExpiresIn) {\n throw new UnauthorizedException('Refresh token non abilitato.');\n }\n if (typeof refreshToken !== 'string' || refreshToken.trim() === '') {\n throw new UnauthorizedException('Refresh token mancante.');\n }\n\n const verification = getAccessiRefreshTokenVerificationConfig(this.accessiOptions);\n let decoded: unknown;\n try {\n decoded = jwt.verify(refreshToken.trim(), verification.key, verification.verifyOptions);\n } catch {\n throw new UnauthorizedException('Refresh token non valido o scaduto.');\n }\n\n const codiceUtente = resolveCodiceUtenteFromTokenPayload(decoded, 'refresh');\n if (!codiceUtente) {\n throw new UnauthorizedException('Refresh token privo di un utente valido.');\n }\n if (await isAccessiTokenRevoked(this.accessiOptions, decoded as Record<string, unknown>, codiceUtente)) {\n throw new UnauthorizedException('Sessione revocata.');\n }\n\n const currentUser = await this.userService.getAuthenticatedUserSnapshot(codiceUtente);\n if (!isAuthenticatedUserEnabledForJwt(currentUser) || !isAccessiTokenAllowedForUser(decoded, currentUser)) {\n throw new UnauthorizedException('Utente non piu autorizzato.');\n }\n\n const rotationStore = getRefreshTokenRotationStore(this.accessiOptions);\n if (rotationStore) {\n const decodedRecord = decoded as { jti?: unknown; exp?: unknown };\n const jti = typeof decodedRecord.jti === 'string' ? decodedRecord.jti : undefined;\n const expiresAt = Number(decodedRecord.exp);\n if (!jti || !Number.isFinite(expiresAt)) {\n throw new UnauthorizedException('Refresh token privo di jti o scadenza.');\n }\n try {\n const consumed = await rotationStore.consume(jti, expiresAt * 1000);\n if (!consumed) {\n throw new UnauthorizedException('Refresh token gia utilizzato.');\n }\n } catch (error) {\n if (error instanceof UnauthorizedException) throw error;\n throw new ServiceUnavailableException({\n code: 'ACCESSI_REFRESH_ROTATION_UNAVAILABLE',\n message: 'Rotazione refresh token non disponibile. Riprova piu tardi.',\n });\n }\n }\n\n const login = await this.getLoginResultForUser(codiceUtente);\n const methods = Array.isArray((decoded as { amr?: unknown }).amr)\n ? ((decoded as { amr: unknown[] }).amr.filter((method): method is string => typeof method === 'string'))\n : [];\n const pair = this.createTokenPair(login.utente, methods);\n login.token = pair.access;\n if (pair.refresh) login.refreshToken = pair.refresh;\n return login;\n }\n\n /** Starts a second-factor challenge after the hosting backend has verified an SSO identity. */\n public async beginFederatedTwoFactor(codiceUtente: number, identityKey: string): Promise<LoginResult> {\n const user = await this.userService.getAuthenticatedUserSnapshot(codiceUtente);\n if (!isAuthenticatedUserEnabledForJwt(user) || !user.flagDueFattori) throw new UnauthorizedException();\n return { challenge: await this.twoFactorService.issue({ codiceUtente, email: user.email ?? '', mode: 'federated', identityKey }) };\n }\n\n private async validateTwoFactorProof(proof: TwoFactorProof): Promise<void> {\n const user = await this.userService.getAuthenticatedUserSnapshot(proof.codiceUtente);\n if (!isAuthenticatedUserEnabledForJwt(user) || !user.flagDueFattori || user.email?.trim().toLowerCase() !== proof.email.trim().toLowerCase()) {\n throw new UnauthorizedException('Profilo modificato o utente non abilitato. Ripeti l accesso.');\n }\n if (proof.mode === 'passwordless' && !user.passwordlessLoginEnabled) throw new UnauthorizedException('Accesso senza password disabilitato.');\n if (proof.mode === 'password' && !(await this.isPasswordLoginEnabled(proof.codiceUtente))) throw new UnauthorizedException('Login locale disabilitato.');\n if (proof.mode === 'federated') {\n if (!this.accessiOptions.federatedAuthentication?.enabled) throw new UnauthorizedException();\n const rows = await Orm.query(this.accessiOptions.databaseOptions,\n 'SELECT I.IDNKEY FROM UTENTI_IDENTITA_EXT I INNER JOIN SSO_PROVIDER P ON P.PROVIDER = I.PROVIDER WHERE I.IDNKEY = ? AND I.CODUTE = ? AND I.FLGATTIVO = 1 AND P.FLGATTIVO = 1',\n [proof.identityKey, proof.codiceUtente], false);\n if (!rows.length) throw new UnauthorizedException('Identita SSO non piu abilitata.');\n }\n }\n\n public async verifyTwoFactor(challengeId: string, code: string, scope?: string): Promise<LoginResult> {\n const proof = await this.twoFactorService.consume(challengeId, code);\n await this.validateTwoFactorProof(proof);\n const result = await this.getLoginResultForUser(proof.codiceUtente, scope);\n const tokens = this.createTokenPair(result.utente, [proof.mode, 'otp']);\n result.token = tokens.access;\n if (tokens.refresh) result.refreshToken = tokens.refresh;\n await Orm.execute(this.accessiOptions.databaseOptions, 'UPDATE UTENTI SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE CODUTE = ?', [proof.codiceUtente]);\n if (proof.mode === 'federated') {\n await Orm.execute(this.accessiOptions.databaseOptions, 'UPDATE UTENTI_IDENTITA_EXT SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE IDNKEY = ?', [proof.identityKey]);\n }\n return result;\n }\n\n public async resendTwoFactor(challengeId: string): Promise<LoginResult> {\n await this.validateTwoFactorProof(await this.twoFactorService.describe(challengeId));\n return { challenge: await this.twoFactorService.resend(challengeId) };\n }\n\n /**\n * Persiste una password hashata e aggiorna la scadenza, se la policy password e attiva. Non invia email.\n * Con `enforcePolicy` (default true) valida la password secondo la policy moderna; i flussi di\n * migrazione delle password legacy passano `enforcePolicy: false` per non bloccare password storiche.\n */\n public async setPassword(\n codiceUtente: number,\n nuovaPassword: string,\n options?: { enforcePolicy?: boolean },\n ) {\n if (options?.enforcePolicy !== false) {\n assertStrongPassword(nuovaPassword);\n }\n try {\n const query = `UPDATE OR INSERT INTO UTENTI_PWD (CODUTE, PWD) VALUES (?, ?)`;\n const hashedPassword = PasswordUtilities.hashPassword(nuovaPassword);\n\n const result = await Orm.execute(this.accessiOptions.databaseOptions, query, [\n codiceUtente,\n hashedPassword,\n ]);\n await this.refreshPasswordExpiration(codiceUtente);\n return result;\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * Converte le password legacy cifrate nel formato hash compatibile, senza conoscere le password in chiaro.\n * E idempotente: hash moderni e gia migrati vengono ignorati.\n */\n public async migrateLegacyEncryptedPasswords(): Promise<void> {\n const startedAt = performance.now();\n this.logger.info(\"Avvio migrazione password legacy accessi.\");\n const results = await Orm.query(\n this.accessiOptions.databaseOptions,\n \"SELECT CODUTE AS codice_utente, PWD AS password FROM UTENTI_PWD WHERE PWD IS NOT NULL\",\n []\n );\n\n const rows = results.map(RestUtilities.convertKeysToCamelCase) as {\n codiceUtente?: number;\n password?: string;\n }[];\n let migratedCount = 0;\n let skippedCount = 0;\n\n for (const row of rows) {\n const codiceUtente = Number(row.codiceUtente);\n const storedPassword = typeof row.password === \"string\" ? row.password : null;\n\n if (\n !codiceUtente ||\n !storedPassword ||\n PasswordUtilities.isPasswordHash(storedPassword) ||\n PasswordUtilities.isLegacyPasswordHash(storedPassword)\n ) {\n skippedCount += 1;\n continue;\n }\n\n const protectedLegacyPassword =\n PasswordUtilities.hashLegacyEncryptedPassword(storedPassword);\n\n await Orm.execute(\n this.accessiOptions.databaseOptions,\n \"UPDATE UTENTI_PWD SET PWD = ? WHERE CODUTE = ? AND PWD = ?\",\n [protectedLegacyPassword, codiceUtente, storedPassword]\n );\n migratedCount += 1;\n }\n\n this.logger.info(\n `Migrazione password legacy accessi completata. Letti=${rows.length}, migrati=${migratedCount}, ignorati=${skippedCount}, durataMs=${(performance.now() - startedAt).toFixed(2)}`\n );\n }\n\n /** Verifica una password locale e migra automaticamente il formato legacy dopo una verifica positiva. */\n async verifyPassword(\n codiceUtente: number,\n plainPassword: string\n ): Promise<boolean> {\n const query = `SELECT PWD AS password FROM UTENTI_PWD WHERE CODUTE = ?`;\n const result = (await Orm.query(\n this.accessiOptions.databaseOptions,\n query,\n [codiceUtente]\n ).then((results) => results.map(RestUtilities.convertKeysToCamelCase))) as {\n password: string;\n }[];\n\n const stored = result[0];\n if (!stored || typeof stored.password !== \"string\") {\n return false;\n }\n\n const storedPassword = stored.password;\n\n if (PasswordUtilities.isPasswordHash(storedPassword)) {\n return PasswordUtilities.verifyPassword(plainPassword, storedPassword);\n }\n\n const legacyEncryptedPassword = CryptUtilities.encrypt(\n plainPassword,\n this.accessiOptions.encryptionKey\n );\n\n if (PasswordUtilities.isLegacyPasswordHash(storedPassword)) {\n const isMigratedLegacyPasswordValid =\n PasswordUtilities.verifyLegacyEncryptedPassword(\n legacyEncryptedPassword,\n storedPassword\n );\n\n if (isMigratedLegacyPasswordValid) {\n await this.setPassword(codiceUtente, plainPassword, { enforcePolicy: false });\n }\n\n return isMigratedLegacyPasswordValid;\n }\n\n const isLegacyPasswordValid = PasswordUtilities.timingSafeStringEquals(\n storedPassword,\n legacyEncryptedPassword,\n );\n\n if (isLegacyPasswordValid) {\n await this.setPassword(codiceUtente, plainPassword, { enforcePolicy: false });\n }\n\n return isLegacyPasswordValid;\n }\n\n /** Restituisce l'utente fittizio amministratore; usabile solo con `mockDemoUser` esplicitamente abilitato. */\n async getAdminUser(): Promise<LoginResult> {\n return {\n utente: {\n codiceUtente: 6789,\n email: \"admin\",\n statoRegistrazione: StatoRegistrazione.CONF,\n cognome: \"Admin\",\n nome: \"Admin\",\n flagGdpr: true,\n avatar: \"/path/to/avatar.jpg\",\n flagDueFattori: false,\n codiceLingua: \"IT\",\n cellulare: \"+391234567890\",\n flagSuper: true,\n roles: [],\n permissions: [],\n },\n filtri: null,\n userGrants: {\n abilitazioni: [],\n grants: [],\n ruoli: [],\n },\n };\n }\n\n /** Restituisce l'utente demo fittizio; non contiene dati o grant reali. */\n getDemoUser(): LoginResult {\n return {\n utente: {\n codiceUtente: 12345,\n email: \"jdoe\",\n statoRegistrazione: StatoRegistrazione.CONF,\n cognome: \"Doe\",\n nome: \"John\",\n flagGdpr: true,\n avatar: \"/path/to/avatar.jpg\",\n flagDueFattori: false,\n codiceLingua: \"IT\",\n cellulare: \"+391234567890\",\n flagSuper: false,\n roles: [],\n permissions: [],\n },\n filtri: null,\n userGrants: {\n abilitazioni: [],\n grants: [],\n ruoli: [],\n },\n };\n }\n\n /**\n * Consuma un token monouso di reset, riporta l'utente allo stato confermato e salva la nuova password.\n * Il nonce in `UTENTI.KEYREG` viene annullato prima di impostare la password, impedendo il riuso del token.\n */\n public async confirmResetPassword(\n token: string,\n newPassword: string\n ): Promise<void> {\n try {\n if (typeof token !== \"string\" || token.trim() === \"\") {\n throw new Error(\"Token non valido.\");\n }\n\n assertStrongPassword(newPassword);\n\n const secret = getAccessiJwtSecret(this.accessiOptions, 'reset');\n const { codiceUtente, nonce } = verifyPasswordResetToken(token.trim(), secret);\n\n const hashedPassword = PasswordUtilities.hashPassword(newPassword);\n\n await Orm.withTransaction(this.accessiOptions.databaseOptions, async (transaction) => {\n // A conditional write claims the nonce under the database row lock. A second\n // concurrent reset cannot also consume it; failures roll the whole reset back.\n const claimed = await Orm.transactionQuery<unknown>(\n transaction,\n 'UPDATE UTENTI SET KEYREG = NULL, STAREG = ? WHERE CODUTE = ? AND KEYREG = ? AND STAREG IN (?, ?) RETURNING CODUTE',\n [StatoRegistrazione.CONF, codiceUtente, nonce, StatoRegistrazione.CONF, StatoRegistrazione.INVIO],\n );\n const row = (Array.isArray(claimed) ? claimed[0] : claimed) as Record<string, unknown> | undefined;\n if (Number(row?.CODUTE ?? row?.codute) !== codiceUtente) {\n throw new Error('Token non valido, gia usato o utente non autorizzato.');\n }\n\n await Orm.transactionQuery(\n transaction,\n 'UPDATE OR INSERT INTO UTENTI_PWD (CODUTE, PWD) VALUES (?, ?) MATCHING (CODUTE)',\n [codiceUtente, hashedPassword],\n );\n\n if (this.accessiOptions.passwordExpiration) {\n const days = Number(this.accessiOptions.passwordExpirationDays);\n const expirationDays = Number.isFinite(days) && days > 0 ? Math.trunc(days) : 90;\n await Orm.transactionQuery(\n transaction,\n `UPDATE UTENTI SET DATSCAPWD = DATEADD(${expirationDays} DAY TO CURRENT_TIMESTAMP) WHERE CODUTE = ?`,\n [codiceUtente],\n );\n }\n });\n } catch (error) {\n throw error;\n }\n }\n}\n"]}
|
|
@@ -54,18 +54,7 @@ function createAccessiOptionsFromEnv() {
|
|
|
54
54
|
databaseOptions.wireCrypt = wireCrypt;
|
|
55
55
|
if (authPlugin)
|
|
56
56
|
databaseOptions.pluginName = authPlugin;
|
|
57
|
-
return {
|
|
58
|
-
databaseOptions,
|
|
59
|
-
confirmationEmailUrl: getEnv("ACCESSI_CONFIRMATION_EMAIL_URL", "http://localhost"),
|
|
60
|
-
confirmationEmailReturnUrl: getEnv("ACCESSI_CONFIRMATION_RETURN_EMAIL_URL", "http://localhost"),
|
|
61
|
-
confirmationEmailPrefix: process.env.ACCESSI_CONFIRMATION_EMAIL_PREFIX,
|
|
62
|
-
customResetPage: process.env.ACCESSI_CUSTOM_RESET_PAGE,
|
|
63
|
-
encryptionKey: getEnv("ACCESSI_ENCRYPTION_KEY", "1234567890ABCDEF"),
|
|
64
|
-
mockDemoUser: getOptionalBoolean("ACCESSI_MOCK_DEMO_USER", false),
|
|
65
|
-
passwordExpiration: getOptionalBoolean("ACCESSI_PASSWORD_EXPIRATION", false),
|
|
66
|
-
autoUpdateDatabase: true,
|
|
67
|
-
jwtOptions: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ secret: getEnv("ACCESSI_JWT_SECRET", "local-accessi-update"), expiresIn: getEnv("ACCESSI_JWT_EXPIRES", "24h") }, (process.env.ACCESSI_JWT_ISSUER ? { issuer: process.env.ACCESSI_JWT_ISSUER } : {})), (process.env.ACCESSI_JWT_AUDIENCE ? { audience: process.env.ACCESSI_JWT_AUDIENCE } : {})), (getJwtAlgorithm() ? { algorithm: getJwtAlgorithm() } : {})), (process.env.ACCESSI_JWT_PRIVATE_KEY ? { privateKey: process.env.ACCESSI_JWT_PRIVATE_KEY } : {})), (process.env.ACCESSI_JWT_PUBLIC_KEY ? { publicKey: process.env.ACCESSI_JWT_PUBLIC_KEY } : {})), (process.env.ACCESSI_JWT_KEY_ID ? { keyId: process.env.ACCESSI_JWT_KEY_ID } : {})),
|
|
68
|
-
emailOptions: {
|
|
57
|
+
return Object.assign(Object.assign({ databaseOptions, confirmationEmailUrl: getEnv("ACCESSI_CONFIRMATION_EMAIL_URL", "http://localhost"), confirmationEmailReturnUrl: getEnv("ACCESSI_CONFIRMATION_RETURN_EMAIL_URL", "http://localhost"), confirmationEmailPrefix: process.env.ACCESSI_CONFIRMATION_EMAIL_PREFIX, customResetPage: process.env.ACCESSI_CUSTOM_RESET_PAGE, consoleApiBaseUrl: process.env.ACCESSI_CONSOLE_API_BASE_URL, publicBaseUrl: process.env.ACCESSI_PUBLIC_BASE_URL, encryptionKey: getEnv("ACCESSI_ENCRYPTION_KEY", "1234567890ABCDEF"), mockDemoUser: getOptionalBoolean("ACCESSI_MOCK_DEMO_USER", false), passwordExpiration: getOptionalBoolean("ACCESSI_PASSWORD_EXPIRATION", false), autoUpdateDatabase: true, jwtOptions: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ secret: getEnv("ACCESSI_JWT_SECRET", "local-accessi-update"), expiresIn: getEnv("ACCESSI_JWT_EXPIRES", "24h") }, (process.env.ACCESSI_JWT_REFRESH_EXPIRES ? { refreshExpiresIn: process.env.ACCESSI_JWT_REFRESH_EXPIRES } : {})), (process.env.ACCESSI_JWT_ISSUER ? { issuer: process.env.ACCESSI_JWT_ISSUER } : {})), (process.env.ACCESSI_JWT_AUDIENCE ? { audience: process.env.ACCESSI_JWT_AUDIENCE } : {})), (getJwtAlgorithm() ? { algorithm: getJwtAlgorithm() } : {})), (process.env.ACCESSI_JWT_PRIVATE_KEY ? { privateKey: process.env.ACCESSI_JWT_PRIVATE_KEY } : {})), (process.env.ACCESSI_JWT_PUBLIC_KEY ? { publicKey: process.env.ACCESSI_JWT_PUBLIC_KEY } : {})), (process.env.ACCESSI_JWT_KEY_ID ? { keyId: process.env.ACCESSI_JWT_KEY_ID } : {})), (process.env.ACCESSI_JWKS_PATH ? { jwksPath: process.env.ACCESSI_JWKS_PATH } : {})), emailOptions: {
|
|
69
58
|
host: getEnv("ACCESSI_EMAIL_HOST", "localhost"),
|
|
70
59
|
port: Number(getEnv("ACCESSI_EMAIL_PORT", "25")),
|
|
71
60
|
secure: getOptionalBoolean("ACCESSI_EMAIL_SECURE", false),
|
|
@@ -78,9 +67,12 @@ function createAccessiOptionsFromEnv() {
|
|
|
78
67
|
user: getEnv("ACCESSI_EMAIL_USER", "local-user"),
|
|
79
68
|
pass: getEnv("ACCESSI_EMAIL_PASSWORD", "local-password"),
|
|
80
69
|
},
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
70
|
+
} }, (process.env.ACCESSI_CONSOLE_ENTRY_TTL_MS
|
|
71
|
+
? {
|
|
72
|
+
consoleEntry: {
|
|
73
|
+
ttlMs: Number(process.env.ACCESSI_CONSOLE_ENTRY_TTL_MS),
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
: {})), { extensionFieldsOptions: [], catalogScripts: createCatalogScriptsOptionsFromEnv() });
|
|
85
77
|
}
|
|
86
78
|
//# sourceMappingURL=accessiOptionsFromEnv.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accessiOptionsFromEnv.js","sourceRoot":"","sources":["../../../src/accessi-module/database-updates/accessiOptionsFromEnv.ts"],"names":[],"mappings":";;AAgCA,gFAeC;AAGD,
|
|
1
|
+
{"version":3,"file":"accessiOptionsFromEnv.js","sourceRoot":"","sources":["../../../src/accessi-module/database-updates/accessiOptionsFromEnv.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccessiOptions, CatalogScriptsOptions } from '../AccessiModule';\nimport { DatabaseUtilities } from '../../Utilities';\n\nfunction getEnv(names: string | string[], fallback?: string): string {\n const candidates = Array.isArray(names) ? names : [names];\n const value = candidates.map((name) => process.env[name]).find((candidate) => candidate !== undefined && candidate !== \"\") ?? fallback;\n if (!value) {\n throw new Error(`Variabile ambiente mancante: ${candidates.join(\" oppure \")}`);\n }\n return value;\n}\n\nfunction getOptionalBoolean(name: string, fallback: boolean): boolean {\n const value = process.env[name];\n if (value === undefined) {\n return fallback;\n }\n return value.toLowerCase() === \"true\";\n}\n\nconst JWT_ALGORITHMS = [\n \"HS256\", \"HS384\", \"HS512\",\n \"RS256\", \"RS384\", \"RS512\",\n \"ES256\", \"ES384\", \"ES512\",\n] as const;\n\nfunction getJwtAlgorithm(): (typeof JWT_ALGORITHMS)[number] | undefined {\n const value = process.env.ACCESSI_JWT_ALGORITHM?.trim().toUpperCase();\n return JWT_ALGORITHMS.find((algorithm) => algorithm === value);\n}\n\n/** Catalog migrations lette dall'ambiente: cartella in ACCESSI_CATALOG_FOLDER. */\nexport function createCatalogScriptsOptionsFromEnv(): CatalogScriptsOptions | undefined {\n const folder = process.env.ACCESSI_CATALOG_FOLDER;\n if (!folder) {\n return undefined;\n }\n\n const policy = process.env.ACCESSI_CATALOG_CHECKSUM_POLICY;\n const checksumPolicy = policy === 'warn' || policy === 'reapply' || policy === 'error' ? policy : undefined;\n\n return {\n enabled: true,\n folder,\n onChecksumMismatch: checksumPolicy,\n stopOnError: getOptionalBoolean('ACCESSI_CATALOG_STOP_ON_ERROR', true),\n };\n}\n\n/** Costruisce `AccessiOptions` dalle variabili ambiente (stesse di runAccessiDbUpdate). */\nexport function createAccessiOptionsFromEnv(): AccessiOptions {\n const databaseOptions = DatabaseUtilities.createOption(\n getEnv([\"ACCESSI_DB_HOST\", \"ACCESSI_FIREBIRD_HOST\"]),\n Number(getEnv([\"ACCESSI_DB_PORT\", \"ACCESSI_FIREBIRD_PORT\"], \"3050\")),\n getEnv([\"ACCESSI_DB_DATABASE\", \"ACCESSI_FIREBIRD_DATABASE\"]),\n getEnv([\"ACCESSI_DB_USER\", \"ACCESSI_FIREBIRD_USER\"], \"SYSDBA\"),\n getEnv([\"ACCESSI_DB_PASSWORD\", \"ACCESSI_FIREBIRD_PASSWORD\"], \"masterkey\")\n );\n\n // Firebird 2.5 richiede Legacy_Auth e non supporta la cifratura del wire: override opzionale via env.\n const wireCrypt = process.env.ACCESSI_DB_WIRE_CRYPT;\n const authPlugin = process.env.ACCESSI_DB_AUTH_PLUGIN;\n if (wireCrypt) (databaseOptions as { wireCrypt?: string }).wireCrypt = wireCrypt;\n if (authPlugin) (databaseOptions as { pluginName?: string }).pluginName = authPlugin;\n\n return {\n databaseOptions,\n confirmationEmailUrl: getEnv(\"ACCESSI_CONFIRMATION_EMAIL_URL\", \"http://localhost\"),\n confirmationEmailReturnUrl: getEnv(\"ACCESSI_CONFIRMATION_RETURN_EMAIL_URL\", \"http://localhost\"),\n confirmationEmailPrefix: process.env.ACCESSI_CONFIRMATION_EMAIL_PREFIX,\n customResetPage: process.env.ACCESSI_CUSTOM_RESET_PAGE,\n consoleApiBaseUrl: process.env.ACCESSI_CONSOLE_API_BASE_URL,\n publicBaseUrl: process.env.ACCESSI_PUBLIC_BASE_URL,\n encryptionKey: getEnv(\"ACCESSI_ENCRYPTION_KEY\", \"1234567890ABCDEF\"),\n mockDemoUser: getOptionalBoolean(\"ACCESSI_MOCK_DEMO_USER\", false),\n passwordExpiration: getOptionalBoolean(\"ACCESSI_PASSWORD_EXPIRATION\", false),\n autoUpdateDatabase: true,\n jwtOptions: {\n secret: getEnv(\"ACCESSI_JWT_SECRET\", \"local-accessi-update\"),\n expiresIn: getEnv(\"ACCESSI_JWT_EXPIRES\", \"24h\"),\n ...(process.env.ACCESSI_JWT_REFRESH_EXPIRES ? { refreshExpiresIn: process.env.ACCESSI_JWT_REFRESH_EXPIRES } : {}),\n ...(process.env.ACCESSI_JWT_ISSUER ? { issuer: process.env.ACCESSI_JWT_ISSUER } : {}),\n ...(process.env.ACCESSI_JWT_AUDIENCE ? { audience: process.env.ACCESSI_JWT_AUDIENCE } : {}),\n ...(getJwtAlgorithm() ? { algorithm: getJwtAlgorithm() } : {}),\n ...(process.env.ACCESSI_JWT_PRIVATE_KEY ? { privateKey: process.env.ACCESSI_JWT_PRIVATE_KEY } : {}),\n ...(process.env.ACCESSI_JWT_PUBLIC_KEY ? { publicKey: process.env.ACCESSI_JWT_PUBLIC_KEY } : {}),\n ...(process.env.ACCESSI_JWT_KEY_ID ? { keyId: process.env.ACCESSI_JWT_KEY_ID } : {}),\n ...(process.env.ACCESSI_JWKS_PATH ? { jwksPath: process.env.ACCESSI_JWKS_PATH } : {}),\n },\n emailOptions: {\n host: getEnv(\"ACCESSI_EMAIL_HOST\", \"localhost\"),\n port: Number(getEnv(\"ACCESSI_EMAIL_PORT\", \"25\")),\n secure: getOptionalBoolean(\"ACCESSI_EMAIL_SECURE\", false),\n requireTLS: getOptionalBoolean(\"ACCESSI_EMAIL_REQUIRE_TLS\", false),\n tls: {\n rejectUnauthorized: getOptionalBoolean(\"ACCESSI_EMAIL_TLS_REJECT_UNAUTHORIZED\", false),\n },\n from: getEnv(\"ACCESSI_EMAIL_FROM\", \"noreply@example.local\"),\n auth: {\n user: getEnv(\"ACCESSI_EMAIL_USER\", \"local-user\"),\n pass: getEnv(\"ACCESSI_EMAIL_PASSWORD\", \"local-password\"),\n },\n },\n ...(process.env.ACCESSI_CONSOLE_ENTRY_TTL_MS\n ? {\n consoleEntry: {\n ttlMs: Number(process.env.ACCESSI_CONSOLE_ENTRY_TTL_MS),\n },\n }\n : {}),\n extensionFieldsOptions: [],\n catalogScripts: createCatalogScriptsOptionsFromEnv(),\n };\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Response } from 'express';
|
|
2
|
+
import { ExchangeFederatedIdentityRequest } from '../Dtos';
|
|
3
|
+
import { FederatedAuthService } from './FederatedAuthService';
|
|
4
|
+
/**
|
|
5
|
+
* Scambio service-to-service di un'identita SSO gia verificata.
|
|
6
|
+
*
|
|
7
|
+
* Il backend fratello valida il token del provider e chiama questo endpoint con
|
|
8
|
+
* `{ provider, subject }`; Accessi restituisce la sessione interna e il JWT.
|
|
9
|
+
* Non e un endpoint browser: richiede un service token con scope dedicato.
|
|
10
|
+
*/
|
|
11
|
+
export declare class FederatedAuthExchangeController {
|
|
12
|
+
private readonly federatedAuthService;
|
|
13
|
+
constructor(federatedAuthService: FederatedAuthService);
|
|
14
|
+
exchange(body: ExchangeFederatedIdentityRequest, res: Response): Promise<Response>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
15
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
16
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
17
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
18
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
19
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
20
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
var FederatedAuthExchangeController_1;
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.FederatedAuthExchangeController = void 0;
|
|
26
|
+
const common_1 = require("@nestjs/common");
|
|
27
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
28
|
+
const Utilities_1 = require("../../Utilities");
|
|
29
|
+
const Dtos_1 = require("../Dtos");
|
|
30
|
+
const serviceTokenGuard_1 = require("../security/serviceTokenGuard");
|
|
31
|
+
const FederatedAuthService_1 = require("./FederatedAuthService");
|
|
32
|
+
/**
|
|
33
|
+
* Scambio service-to-service di un'identita SSO gia verificata.
|
|
34
|
+
*
|
|
35
|
+
* Il backend fratello valida il token del provider e chiama questo endpoint con
|
|
36
|
+
* `{ provider, subject }`; Accessi restituisce la sessione interna e il JWT.
|
|
37
|
+
* Non e un endpoint browser: richiede un service token con scope dedicato.
|
|
38
|
+
*/
|
|
39
|
+
let FederatedAuthExchangeController = FederatedAuthExchangeController_1 = class FederatedAuthExchangeController {
|
|
40
|
+
constructor(federatedAuthService) {
|
|
41
|
+
this.federatedAuthService = federatedAuthService;
|
|
42
|
+
}
|
|
43
|
+
exchange(body, res) {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
try {
|
|
46
|
+
const result = yield this.federatedAuthService.authenticate({
|
|
47
|
+
provider: body.provider,
|
|
48
|
+
subject: body.subject,
|
|
49
|
+
});
|
|
50
|
+
return Utilities_1.RestUtilities.sendBaseResponse(res, result);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return Utilities_1.RestUtilities.sendErrorMessage(res, error, FederatedAuthExchangeController_1.name);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
exports.FederatedAuthExchangeController = FederatedAuthExchangeController;
|
|
59
|
+
__decorate([
|
|
60
|
+
(0, common_1.Post)('exchange'),
|
|
61
|
+
(0, serviceTokenGuard_1.RequireServiceTokenScopes)('accessi:federated:exchange'),
|
|
62
|
+
(0, swagger_1.ApiOperation)({
|
|
63
|
+
summary: 'Scambia un identita esterna verificata con una sessione Accessi',
|
|
64
|
+
operationId: 'exchangeFederatedIdentity',
|
|
65
|
+
description: 'Richiede un service token con scope accessi:federated:exchange. Il backend chiamante deve avere gia verificato il token del provider.',
|
|
66
|
+
}),
|
|
67
|
+
(0, swagger_1.ApiBody)({ type: Dtos_1.ExchangeFederatedIdentityRequest }),
|
|
68
|
+
(0, swagger_1.ApiOkResponse)({ type: Dtos_1.FederatedExchangeResponse }),
|
|
69
|
+
(0, swagger_1.ApiResponse)({ status: 401, type: Dtos_1.ErrorResponse, description: 'Service token mancante o non valido.' }),
|
|
70
|
+
(0, swagger_1.ApiResponse)({ status: 403, type: Dtos_1.ErrorResponse, description: 'Scope mancante o identita non abilitata.' }),
|
|
71
|
+
(0, swagger_1.ApiResponse)({ status: 404, type: Dtos_1.ErrorResponse, description: 'Identita non collegata a un utente Accessi.' }),
|
|
72
|
+
__param(0, (0, common_1.Body)()),
|
|
73
|
+
__param(1, (0, common_1.Res)()),
|
|
74
|
+
__metadata("design:type", Function),
|
|
75
|
+
__metadata("design:paramtypes", [Dtos_1.ExchangeFederatedIdentityRequest, Object]),
|
|
76
|
+
__metadata("design:returntype", Promise)
|
|
77
|
+
], FederatedAuthExchangeController.prototype, "exchange", null);
|
|
78
|
+
exports.FederatedAuthExchangeController = FederatedAuthExchangeController = FederatedAuthExchangeController_1 = __decorate([
|
|
79
|
+
(0, swagger_1.ApiTags)('Federated authentication'),
|
|
80
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
81
|
+
(0, common_1.Controller)('accessi/federated-auth'),
|
|
82
|
+
(0, common_1.UseGuards)(serviceTokenGuard_1.ServiceTokenGuard),
|
|
83
|
+
__metadata("design:paramtypes", [FederatedAuthService_1.FederatedAuthService])
|
|
84
|
+
], FederatedAuthExchangeController);
|
|
85
|
+
//# sourceMappingURL=FederatedAuthExchangeController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FederatedAuthExchangeController.js","sourceRoot":"","sources":["../../../src/accessi-module/federated-auth/FederatedAuthExchangeController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAwE;AACxE,6CAOyB;AAEzB,+CAAgD;AAChD,kCAIiB;AACjB,qEAA6F;AAC7F,iEAA8D;AAE9D;;;;;;GAMG;AAKI,IAAM,+BAA+B,uCAArC,MAAM,+BAA+B;IAC1C,YAA6B,oBAA0C;QAA1C,yBAAoB,GAApB,oBAAoB,CAAsB;IAAG,CAAC;IAerE,QAAQ,CACJ,IAAsC,EACvC,GAAa;;YAEpB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC;oBAC1D,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,OAAO,EAAE,IAAI,CAAC,OAAO;iBACtB,CAAC,CAAC;gBACH,OAAO,yBAAa,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACrD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,yBAAa,CAAC,gBAAgB,CAAC,GAAG,EAAE,KAAK,EAAE,iCAA+B,CAAC,IAAI,CAAC,CAAC;YAC1F,CAAC;QACH,CAAC;KAAA;CACF,CAAA;AA9BY,0EAA+B;AAgBpC;IAbL,IAAA,aAAI,EAAC,UAAU,CAAC;IAChB,IAAA,6CAAyB,EAAC,4BAA4B,CAAC;IACvD,IAAA,sBAAY,EAAC;QACZ,OAAO,EAAE,iEAAiE;QAC1E,WAAW,EAAE,2BAA2B;QACxC,WAAW,EACT,uIAAuI;KAC1I,CAAC;IACD,IAAA,iBAAO,EAAC,EAAE,IAAI,EAAE,uCAAgC,EAAE,CAAC;IACnD,IAAA,uBAAa,EAAC,EAAE,IAAI,EAAE,gCAAyB,EAAE,CAAC;IAClD,IAAA,qBAAW,EAAC,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,oBAAa,EAAE,WAAW,EAAE,sCAAsC,EAAE,CAAC;IACtG,IAAA,qBAAW,EAAC,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,oBAAa,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC;IAC1G,IAAA,qBAAW,EAAC,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,oBAAa,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;IAE3G,WAAA,IAAA,aAAI,GAAE,CAAA;IACN,WAAA,IAAA,YAAG,GAAE,CAAA;;qCADQ,uCAAgC;;+DAY/C;0CA7BU,+BAA+B;IAJ3C,IAAA,iBAAO,EAAC,0BAA0B,CAAC;IACnC,IAAA,uBAAa,GAAE;IACf,IAAA,mBAAU,EAAC,wBAAwB,CAAC;IACpC,IAAA,kBAAS,EAAC,qCAAiB,CAAC;qCAEwB,2CAAoB;GAD5D,+BAA+B,CA8B3C","sourcesContent":["import { Body, Controller, Post, Res, UseGuards } from '@nestjs/common';\nimport {\n ApiBearerAuth,\n ApiBody,\n ApiOkResponse,\n ApiOperation,\n ApiResponse,\n ApiTags,\n} from '@nestjs/swagger';\nimport { Response } from 'express';\nimport { RestUtilities } from '../../Utilities';\nimport {\n ErrorResponse,\n ExchangeFederatedIdentityRequest,\n FederatedExchangeResponse,\n} from '../Dtos';\nimport { RequireServiceTokenScopes, ServiceTokenGuard } from '../security/serviceTokenGuard';\nimport { FederatedAuthService } from './FederatedAuthService';\n\n/**\n * Scambio service-to-service di un'identita SSO gia verificata.\n *\n * Il backend fratello valida il token del provider e chiama questo endpoint con\n * `{ provider, subject }`; Accessi restituisce la sessione interna e il JWT.\n * Non e un endpoint browser: richiede un service token con scope dedicato.\n */\n@ApiTags('Federated authentication')\n@ApiBearerAuth()\n@Controller('accessi/federated-auth')\n@UseGuards(ServiceTokenGuard)\nexport class FederatedAuthExchangeController {\n constructor(private readonly federatedAuthService: FederatedAuthService) {}\n\n @Post('exchange')\n @RequireServiceTokenScopes('accessi:federated:exchange')\n @ApiOperation({\n summary: 'Scambia un identita esterna verificata con una sessione Accessi',\n operationId: 'exchangeFederatedIdentity',\n description:\n 'Richiede un service token con scope accessi:federated:exchange. Il backend chiamante deve avere gia verificato il token del provider.',\n })\n @ApiBody({ type: ExchangeFederatedIdentityRequest })\n @ApiOkResponse({ type: FederatedExchangeResponse })\n @ApiResponse({ status: 401, type: ErrorResponse, description: 'Service token mancante o non valido.' })\n @ApiResponse({ status: 403, type: ErrorResponse, description: 'Scope mancante o identita non abilitata.' })\n @ApiResponse({ status: 404, type: ErrorResponse, description: 'Identita non collegata a un utente Accessi.' })\n async exchange(\n @Body() body: ExchangeFederatedIdentityRequest,\n @Res() res: Response,\n ): Promise<Response> {\n try {\n const result = await this.federatedAuthService.authenticate({\n provider: body.provider,\n subject: body.subject,\n });\n return RestUtilities.sendBaseResponse(res, result);\n } catch (error) {\n return RestUtilities.sendErrorMessage(res, error, FederatedAuthExchangeController.name);\n }\n }\n}\n"]}
|
|
@@ -77,10 +77,16 @@ let FederatedAuthService = class FederatedAuthService {
|
|
|
77
77
|
yield Orm_1.Orm.execute(this.options.databaseOptions, 'UPDATE UTENTI_IDENTITA_EXT SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE IDNKEY = ?', [linkedIdentity.identityKey]);
|
|
78
78
|
yield Orm_1.Orm.execute(this.options.databaseOptions, 'UPDATE UTENTI SET DATLASTLOGIN = CURRENT_TIMESTAMP WHERE CODUTE = ?', [linkedIdentity.codiceUtente]);
|
|
79
79
|
const login = yield this.authService.getLoginResultForUser(linkedIdentity.codiceUtente);
|
|
80
|
+
const tokens = typeof this.authService.createTokenPair === 'function'
|
|
81
|
+
? this.authService.createTokenPair(login.utente, ['federated'])
|
|
82
|
+
: { access: this.authService.createAccessiToken(login.utente, ['federated']), refresh: undefined };
|
|
83
|
+
login.token = tokens.access;
|
|
84
|
+
if (tokens.refresh)
|
|
85
|
+
login.refreshToken = tokens.refresh;
|
|
80
86
|
return {
|
|
81
87
|
codiceUtente: linkedIdentity.codiceUtente,
|
|
82
88
|
login,
|
|
83
|
-
token:
|
|
89
|
+
token: tokens.access,
|
|
84
90
|
};
|
|
85
91
|
});
|
|
86
92
|
}
|