emilsoftware-utilities 2.0.0-dev.66 → 2.0.0-dev.68
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/EmilsoftwareModule.d.ts +11 -3
- package/dist/EmilsoftwareModule.js +1 -1
- package/dist/EmilsoftwareModule.js.map +1 -1
- package/dist/accessi/client/index.d.ts +26 -0
- package/dist/accessi/client/index.js +49 -0
- package/dist/accessi/client/index.js.map +1 -0
- package/dist/accessi/console/index.d.ts +15 -0
- package/dist/accessi/console/index.js +25 -0
- package/dist/accessi/console/index.js.map +1 -0
- package/dist/accessi/contracts/dtos.d.ts +8 -0
- package/dist/accessi/contracts/dtos.js +25 -0
- package/dist/accessi/contracts/dtos.js.map +1 -0
- package/dist/accessi/contracts/index.d.ts +25 -0
- package/dist/accessi/contracts/index.js +28 -0
- package/dist/accessi/contracts/index.js.map +1 -0
- package/dist/accessi/openapi/index.d.ts +2 -0
- package/dist/accessi/openapi/index.js +19 -0
- package/dist/accessi/openapi/index.js.map +1 -0
- package/dist/accessi/resource-server/core.d.ts +6 -0
- package/dist/accessi/resource-server/core.js +23 -0
- package/dist/accessi/resource-server/core.js.map +1 -0
- package/dist/accessi/resource-server/errors.d.ts +10 -0
- package/dist/accessi/resource-server/errors.js +19 -0
- package/dist/accessi/resource-server/errors.js.map +1 -0
- package/dist/accessi/resource-server/express.d.ts +17 -0
- package/dist/accessi/resource-server/express.js +66 -0
- package/dist/accessi/resource-server/express.js.map +1 -0
- package/dist/accessi/resource-server/index.d.ts +3 -0
- package/dist/accessi/resource-server/index.js +20 -0
- package/dist/accessi/resource-server/index.js.map +1 -0
- package/dist/accessi/resource-server/introspection.d.ts +16 -0
- package/dist/accessi/resource-server/introspection.js +115 -0
- package/dist/accessi/resource-server/introspection.js.map +1 -0
- package/dist/accessi/resource-server/keys.d.ts +11 -0
- package/dist/accessi/resource-server/keys.js +22 -0
- package/dist/accessi/resource-server/keys.js.map +1 -0
- package/dist/accessi/resource-server/nest.d.ts +9 -0
- package/dist/accessi/resource-server/nest.js +62 -0
- package/dist/accessi/resource-server/nest.js.map +1 -0
- package/dist/accessi/resource-server/runtime.d.ts +27 -0
- package/dist/accessi/resource-server/runtime.js +128 -0
- package/dist/accessi/resource-server/runtime.js.map +1 -0
- package/dist/accessi/resource-server/token.d.ts +23 -0
- package/dist/accessi/resource-server/token.js +230 -0
- package/dist/accessi/resource-server/token.js.map +1 -0
- package/dist/accessi/resource-server/types.d.ts +78 -0
- package/dist/accessi/resource-server/types.js +3 -0
- package/dist/accessi/resource-server/types.js.map +1 -0
- package/dist/accessi/server/index.d.ts +10 -0
- package/dist/accessi/server/index.js +29 -0
- package/dist/accessi/server/index.js.map +1 -0
- package/dist/accessi/ui/index.d.ts +13 -0
- package/dist/accessi/ui/index.js +19 -0
- package/dist/accessi/ui/index.js.map +1 -0
- package/dist/accessi-module/AccessiModule.d.ts +52 -2
- package/dist/accessi-module/AccessiModule.js +2 -0
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/accessiFetch.d.ts +4 -0
- package/dist/accessi-module/Console/accessiFetch.js +18 -4
- package/dist/accessi-module/Console/accessiFetch.js.map +1 -1
- package/dist/accessi-module/Console/console.js +122 -11
- package/dist/accessi-module/Console/console.js.map +1 -1
- package/dist/accessi-module/Console/generated/{accessiApi.d.ts → emilsoftware-utilities.d.ts} +11 -1
- package/dist/accessi-module/Console/generated/{accessiApi.js → emilsoftware-utilities.js} +10 -2
- package/dist/accessi-module/Console/generated/emilsoftware-utilities.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/accessiIntrospectionResultDto.d.ts +16 -0
- package/dist/accessi-module/Console/generated/model/accessiIntrospectionResultDto.js +3 -0
- package/dist/accessi-module/Console/generated/model/accessiIntrospectionResultDto.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/index.d.ts +3 -0
- package/dist/accessi-module/Console/generated/model/index.js +3 -0
- package/dist/accessi-module/Console/generated/model/index.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/introspectAccessiTokenRequest.d.ts +10 -0
- package/dist/accessi-module/Console/generated/model/introspectAccessiTokenRequest.js +9 -0
- package/dist/accessi-module/Console/generated/model/introspectAccessiTokenRequest.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/introspectAccessiTokenResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/introspectAccessiTokenResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/introspectAccessiTokenResponse.js.map +1 -0
- package/dist/accessi-module/Console/wiki.js +106 -5
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/AccessiIntrospectionController.d.ts +17 -0
- package/dist/accessi-module/Controllers/AccessiIntrospectionController.js +93 -0
- package/dist/accessi-module/Controllers/AccessiIntrospectionController.js.map +1 -0
- package/dist/accessi-module/Controllers/AuthController.js +6 -6
- 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/IntrospectionDtos.d.ts +16 -0
- package/dist/accessi-module/Dtos/IntrospectionDtos.js +59 -0
- package/dist/accessi-module/Dtos/IntrospectionDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/index.d.ts +1 -0
- package/dist/accessi-module/Dtos/index.js +1 -0
- package/dist/accessi-module/Dtos/index.js.map +1 -1
- package/dist/accessi-module/Services/AuthService/AuthService.d.ts +13 -0
- package/dist/accessi-module/Services/AuthService/AuthService.js +42 -10
- package/dist/accessi-module/Services/AuthService/AuthService.js.map +1 -1
- package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js +18 -19
- package/dist/accessi-module/database-updates/accessiOptionsFromEnv.js.map +1 -1
- package/dist/accessi-module/database-updates/menuScopeSeed.d.ts +2 -2
- package/dist/accessi-module/database-updates/menuScopeSeed.js +101 -53
- package/dist/accessi-module/database-updates/menuScopeSeed.js.map +1 -1
- package/dist/accessi-module/database-updates/menuScopeSeeder.js +1 -1
- package/dist/accessi-module/database-updates/menuScopeSeeder.js.map +1 -1
- package/dist/accessi-module/index.d.ts +25 -4
- package/dist/accessi-module/index.js +47 -21
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/accessi-module/jwt/jwt.strategy.js +5 -5
- package/dist/accessi-module/jwt/jwt.strategy.js.map +1 -1
- package/dist/accessi-module/middleware/authenticateGen.js +5 -5
- package/dist/accessi-module/middleware/authenticateGen.js.map +1 -1
- package/dist/accessi-module/security/consoleEntry.d.ts +56 -11
- package/dist/accessi-module/security/consoleEntry.js +165 -31
- package/dist/accessi-module/security/consoleEntry.js.map +1 -1
- package/dist/accessi-module/security/edgeRateLimit.d.ts +31 -0
- package/dist/accessi-module/security/edgeRateLimit.js +70 -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/jwtTokenOptions.d.ts +15 -0
- package/dist/accessi-module/security/jwtTokenOptions.js +44 -0
- package/dist/accessi-module/security/jwtTokenOptions.js.map +1 -0
- package/dist/accessi-module/security/publicAuthRateLimit.d.ts +8 -6
- package/dist/accessi-module/security/publicAuthRateLimit.js +54 -78
- package/dist/accessi-module/security/publicAuthRateLimit.js.map +1 -1
- package/dist/accessi-module/security/rateLimitStore.d.ts +32 -0
- package/dist/accessi-module/security/rateLimitStore.js +129 -0
- package/dist/accessi-module/security/rateLimitStore.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/startupLog.d.ts +3 -2
- package/dist/accessi-module/startupLog.js +8 -4
- package/dist/accessi-module/startupLog.js.map +1 -1
- package/dist/allegati-module/index.js +2 -2
- package/dist/allegati-module/index.js.map +1 -1
- package/dist/angular-components/aree-disponibili/demo.html +4 -4
- package/dist/emilsoftware-utilities-2.0.0-dev.68.tgz +0 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/initEmilsoftwareModule.d.ts +11 -1
- package/dist/initEmilsoftwareModule.js +29 -23
- package/dist/initEmilsoftwareModule.js.map +1 -1
- package/dist/openapi/OpenApiConfig.d.ts +68 -0
- package/dist/openapi/OpenApiConfig.js +157 -0
- package/dist/openapi/OpenApiConfig.js.map +1 -0
- package/dist/openapi/OpenApiMerge.d.ts +15 -0
- package/dist/openapi/OpenApiMerge.js +119 -0
- package/dist/openapi/OpenApiMerge.js.map +1 -0
- package/docs/gateway-rate-limit.md +98 -0
- package/integration-prompt.md +612 -0
- package/package.json +89 -5
- package/dist/accessi-module/Console/generated/accessiApi.js.map +0 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.66.tgz +0 -0
- package/dist/swagger/SwaggerConfig.d.ts +0 -8
- package/dist/swagger/SwaggerConfig.js +0 -41
- package/dist/swagger/SwaggerConfig.js.map +0 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.createAccessiIntrospectionClient = createAccessiIntrospectionClient;
|
|
13
|
+
const crypto_1 = require("crypto");
|
|
14
|
+
const errors_1 = require("./errors");
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return typeof value === "object" && value !== null;
|
|
17
|
+
}
|
|
18
|
+
function unwrapResult(payload) {
|
|
19
|
+
if (isRecord(payload) && isRecord(payload.Result))
|
|
20
|
+
return payload.Result;
|
|
21
|
+
if (isRecord(payload))
|
|
22
|
+
return payload;
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
function parseResult(payload) {
|
|
26
|
+
var _a;
|
|
27
|
+
const result = unwrapResult(payload);
|
|
28
|
+
const active = result.active === true;
|
|
29
|
+
const user = isRecord(result.user) ? result.user : undefined;
|
|
30
|
+
const grants = isRecord(result.grants) ? result.grants : undefined;
|
|
31
|
+
const rawCode = (_a = user === null || user === void 0 ? void 0 : user.codiceUtente) !== null && _a !== void 0 ? _a : result.codiceUtente;
|
|
32
|
+
const codiceUtente = Number(rawCode);
|
|
33
|
+
return Object.assign(Object.assign(Object.assign({ active }, (user ? { user } : {})), (Number.isSafeInteger(codiceUtente) && codiceUtente > 0 ? { codiceUtente } : {})), (grants ? { grants } : {}));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Crea il client di introspection.
|
|
37
|
+
*
|
|
38
|
+
* Il service token deve avere scope `accessi:introspect`. I risultati attivi
|
|
39
|
+
* sono memorizzati per `cacheTtlMs` (default 30s); i risultati inattivi non
|
|
40
|
+
* vengono cachati per permettere un retry immediato dopo un login.
|
|
41
|
+
*/
|
|
42
|
+
function createAccessiIntrospectionClient(options) {
|
|
43
|
+
var _a, _b, _c;
|
|
44
|
+
if (!(options === null || options === void 0 ? void 0 : options.url) || !(options === null || options === void 0 ? void 0 : options.serviceToken)) {
|
|
45
|
+
throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "introspection.url e introspection.serviceToken sono obbligatori.");
|
|
46
|
+
}
|
|
47
|
+
const fetchImpl = (_a = options.fetch) !== null && _a !== void 0 ? _a : globalThis.fetch;
|
|
48
|
+
if (typeof fetchImpl !== "function") {
|
|
49
|
+
throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "fetch non disponibile per l'introspection.");
|
|
50
|
+
}
|
|
51
|
+
const cacheTtlMs = Math.max(1000, (_b = options.cacheTtlMs) !== null && _b !== void 0 ? _b : 30000);
|
|
52
|
+
const timeoutMs = Math.max(500, (_c = options.timeoutMs) !== null && _c !== void 0 ? _c : 3000);
|
|
53
|
+
const cache = new Map();
|
|
54
|
+
const clearCache = () => {
|
|
55
|
+
cache.clear();
|
|
56
|
+
};
|
|
57
|
+
const introspect = (token_1, ...args_1) => __awaiter(this, [token_1, ...args_1], void 0, function* (token, callOptions = {}) {
|
|
58
|
+
if (typeof token !== "string" || token.trim() === "") {
|
|
59
|
+
return { active: false };
|
|
60
|
+
}
|
|
61
|
+
const cacheKey = (0, crypto_1.createHash)("sha256").update(token).digest("hex");
|
|
62
|
+
const cached = cache.get(cacheKey);
|
|
63
|
+
if (!callOptions.forceRefresh && cached && cached.expiresAt > Date.now()) {
|
|
64
|
+
return cached.result;
|
|
65
|
+
}
|
|
66
|
+
const controller = new AbortController();
|
|
67
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
68
|
+
let response;
|
|
69
|
+
try {
|
|
70
|
+
response = yield fetchImpl(options.url, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: {
|
|
73
|
+
Accept: "application/json",
|
|
74
|
+
"Content-Type": "application/json",
|
|
75
|
+
Authorization: `Bearer ${options.serviceToken}`,
|
|
76
|
+
},
|
|
77
|
+
body: JSON.stringify({ token }),
|
|
78
|
+
signal: controller.signal,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch (_a) {
|
|
82
|
+
cache.delete(cacheKey);
|
|
83
|
+
throw (0, errors_1.accessiAuthError)(503, "AUTH_INTROSPECTION_UNAVAILABLE", "Accessi Service non raggiungibile per l'introspection.");
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
clearTimeout(timeout);
|
|
87
|
+
}
|
|
88
|
+
if (response.status === 401 || response.status === 403) {
|
|
89
|
+
throw (0, errors_1.accessiAuthError)(503, "AUTH_INTROSPECTION_UNAUTHORIZED", "Service token non valido o privo dello scope accessi:introspect.");
|
|
90
|
+
}
|
|
91
|
+
if (response.status >= 500) {
|
|
92
|
+
throw (0, errors_1.accessiAuthError)(503, "AUTH_INTROSPECTION_UNAVAILABLE", `Accessi Service ha risposto ${response.status} all'introspection.`);
|
|
93
|
+
}
|
|
94
|
+
if (response.status === 400 || response.status === 404) {
|
|
95
|
+
return { active: false };
|
|
96
|
+
}
|
|
97
|
+
let payload;
|
|
98
|
+
try {
|
|
99
|
+
payload = yield response.json();
|
|
100
|
+
}
|
|
101
|
+
catch (_b) {
|
|
102
|
+
throw (0, errors_1.accessiAuthError)(503, "AUTH_INTROSPECTION_UNAVAILABLE", "Risposta introspection non JSON.");
|
|
103
|
+
}
|
|
104
|
+
const result = parseResult(payload);
|
|
105
|
+
if (result.active) {
|
|
106
|
+
cache.set(cacheKey, { result, expiresAt: Date.now() + cacheTtlMs });
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
cache.delete(cacheKey);
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
});
|
|
113
|
+
return { introspect, clearCache };
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=introspection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspection.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/introspection.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"crypto\";\nimport { accessiAuthError } from \"./errors\";\nimport type { AccessiIntrospectionOptions, AccessiIntrospectionResult } from \"./types\";\n\ninterface CacheEntry {\n result: AccessiIntrospectionResult;\n expiresAt: number;\n}\n\n/** Client di introspection verso Accessi Service, con cache locale dei risultati attivi. */\nexport interface AccessiIntrospectionClient {\n introspect(token: string, options?: { forceRefresh?: boolean }): Promise<AccessiIntrospectionResult>;\n clearCache(): void;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction unwrapResult(payload: unknown): Record<string, unknown> {\n if (isRecord(payload) && isRecord(payload.Result)) return payload.Result;\n if (isRecord(payload)) return payload;\n return {};\n}\n\nfunction parseResult(payload: unknown): AccessiIntrospectionResult {\n const result = unwrapResult(payload);\n const active = result.active === true;\n const user = isRecord(result.user) ? result.user : undefined;\n const grants = isRecord(result.grants) ? result.grants : undefined;\n const rawCode = user?.codiceUtente ?? result.codiceUtente;\n const codiceUtente = Number(rawCode);\n\n return {\n active,\n ...(user ? { user } : {}),\n ...(Number.isSafeInteger(codiceUtente) && codiceUtente > 0 ? { codiceUtente } : {}),\n ...(grants ? { grants } : {}),\n };\n}\n\n/**\n * Crea il client di introspection.\n *\n * Il service token deve avere scope `accessi:introspect`. I risultati attivi\n * sono memorizzati per `cacheTtlMs` (default 30s); i risultati inattivi non\n * vengono cachati per permettere un retry immediato dopo un login.\n */\nexport function createAccessiIntrospectionClient(\n options: AccessiIntrospectionOptions,\n): AccessiIntrospectionClient {\n if (!options?.url || !options?.serviceToken) {\n throw accessiAuthError(\n 500,\n \"AUTH_CONFIG_INVALID\",\n \"introspection.url e introspection.serviceToken sono obbligatori.\",\n );\n }\n\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"fetch non disponibile per l'introspection.\");\n }\n\n const cacheTtlMs = Math.max(1_000, options.cacheTtlMs ?? 30_000);\n const timeoutMs = Math.max(500, options.timeoutMs ?? 3_000);\n const cache = new Map<string, CacheEntry>();\n\n const clearCache = (): void => {\n cache.clear();\n };\n\n const introspect = async (\n token: string,\n callOptions: { forceRefresh?: boolean } = {},\n ): Promise<AccessiIntrospectionResult> => {\n if (typeof token !== \"string\" || token.trim() === \"\") {\n return { active: false };\n }\n\n const cacheKey = createHash(\"sha256\").update(token).digest(\"hex\");\n const cached = cache.get(cacheKey);\n if (!callOptions.forceRefresh && cached && cached.expiresAt > Date.now()) {\n return cached.result;\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n let response: Response;\n try {\n response = await fetchImpl(options.url, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${options.serviceToken}`,\n },\n body: JSON.stringify({ token }),\n signal: controller.signal,\n });\n } catch {\n cache.delete(cacheKey);\n throw accessiAuthError(\n 503,\n \"AUTH_INTROSPECTION_UNAVAILABLE\",\n \"Accessi Service non raggiungibile per l'introspection.\",\n );\n } finally {\n clearTimeout(timeout);\n }\n\n if (response.status === 401 || response.status === 403) {\n throw accessiAuthError(\n 503,\n \"AUTH_INTROSPECTION_UNAUTHORIZED\",\n \"Service token non valido o privo dello scope accessi:introspect.\",\n );\n }\n if (response.status >= 500) {\n throw accessiAuthError(\n 503,\n \"AUTH_INTROSPECTION_UNAVAILABLE\",\n `Accessi Service ha risposto ${response.status} all'introspection.`,\n );\n }\n if (response.status === 400 || response.status === 404) {\n return { active: false };\n }\n\n let payload: unknown;\n try {\n payload = await response.json();\n } catch {\n throw accessiAuthError(\n 503,\n \"AUTH_INTROSPECTION_UNAVAILABLE\",\n \"Risposta introspection non JSON.\",\n );\n }\n\n const result = parseResult(payload);\n if (result.active) {\n cache.set(cacheKey, { result, expiresAt: Date.now() + cacheTtlMs });\n } else {\n cache.delete(cacheKey);\n }\n return result;\n };\n\n return { introspect, clearCache };\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Derivazione usata dal server Accessi per separare le chiavi JWT per scopo. */
|
|
2
|
+
export declare const ACCESSI_JWT_ACCESS_PURPOSE = "accessi:jwt:access:v1";
|
|
3
|
+
/**
|
|
4
|
+
* Deriva la chiave HMAC degli access token dal segreto configurato in
|
|
5
|
+
* `ACCESSI_JWT_SECRET`.
|
|
6
|
+
*
|
|
7
|
+
* Serve ai resource server che condividono il segreto grezzo con Accessi ma non
|
|
8
|
+
* vogliono replicare la KDF: passare il risultato come `jwt.secret`, oppure
|
|
9
|
+
* usare direttamente `jwt.serverSecret`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function deriveAccessiAccessSecret(serverSecret: string): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ACCESSI_JWT_ACCESS_PURPOSE = void 0;
|
|
4
|
+
exports.deriveAccessiAccessSecret = deriveAccessiAccessSecret;
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
/** Derivazione usata dal server Accessi per separare le chiavi JWT per scopo. */
|
|
7
|
+
exports.ACCESSI_JWT_ACCESS_PURPOSE = "accessi:jwt:access:v1";
|
|
8
|
+
/**
|
|
9
|
+
* Deriva la chiave HMAC degli access token dal segreto configurato in
|
|
10
|
+
* `ACCESSI_JWT_SECRET`.
|
|
11
|
+
*
|
|
12
|
+
* Serve ai resource server che condividono il segreto grezzo con Accessi ma non
|
|
13
|
+
* vogliono replicare la KDF: passare il risultato come `jwt.secret`, oppure
|
|
14
|
+
* usare direttamente `jwt.serverSecret`.
|
|
15
|
+
*/
|
|
16
|
+
function deriveAccessiAccessSecret(serverSecret) {
|
|
17
|
+
if (typeof serverSecret !== "string" || serverSecret.length === 0) {
|
|
18
|
+
throw new Error("serverSecret Accessi non configurato.");
|
|
19
|
+
}
|
|
20
|
+
return (0, crypto_1.createHmac)("sha256", serverSecret).update(exports.ACCESSI_JWT_ACCESS_PURPOSE).digest("hex");
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/keys.ts"],"names":[],"mappings":";;;AAaA,8DAKC;AAlBD,mCAAoC;AAEpC,iFAAiF;AACpE,QAAA,0BAA0B,GAAG,uBAAuB,CAAC;AAElE;;;;;;;GAOG;AACH,SAAgB,yBAAyB,CAAC,YAAoB;IAC5D,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,IAAA,mBAAU,EAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,kCAA0B,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7F,CAAC","sourcesContent":["import { createHmac } from \"crypto\";\n\n/** Derivazione usata dal server Accessi per separare le chiavi JWT per scopo. */\nexport const ACCESSI_JWT_ACCESS_PURPOSE = \"accessi:jwt:access:v1\";\n\n/**\n * Deriva la chiave HMAC degli access token dal segreto configurato in\n * `ACCESSI_JWT_SECRET`.\n *\n * Serve ai resource server che condividono il segreto grezzo con Accessi ma non\n * vogliono replicare la KDF: passare il risultato come `jwt.secret`, oppure\n * usare direttamente `jwt.serverSecret`.\n */\nexport function deriveAccessiAccessSecret(serverSecret: string): string {\n if (typeof serverSecret !== \"string\" || serverSecret.length === 0) {\n throw new Error(\"serverSecret Accessi non configurato.\");\n }\n return createHmac(\"sha256\", serverSecret).update(ACCESSI_JWT_ACCESS_PURPOSE).digest(\"hex\");\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CanActivate, Type } from "@nestjs/common";
|
|
2
|
+
import type { AccessiResourceServerOptions } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Crea un guard Nest configurato con le opzioni del resource server.
|
|
5
|
+
*
|
|
6
|
+
* Uso:
|
|
7
|
+
* `@UseGuards(createAccessiAuthGuard(options))`
|
|
8
|
+
*/
|
|
9
|
+
export declare function createAccessiAuthGuard(options: AccessiResourceServerOptions): Type<CanActivate>;
|
|
@@ -0,0 +1,62 @@
|
|
|
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
9
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
10
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
11
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
12
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
13
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
14
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.createAccessiAuthGuard = createAccessiAuthGuard;
|
|
19
|
+
const common_1 = require("@nestjs/common");
|
|
20
|
+
const errors_1 = require("./errors");
|
|
21
|
+
const runtime_1 = require("./runtime");
|
|
22
|
+
function toNestException(error) {
|
|
23
|
+
const normalized = error instanceof errors_1.AccessiResourceServerError
|
|
24
|
+
? error
|
|
25
|
+
: new errors_1.AccessiResourceServerError(500, "AUTH_INTERNAL_ERROR", "Errore interno durante l'autenticazione.");
|
|
26
|
+
const payload = { code: normalized.code, message: normalized.message };
|
|
27
|
+
if (normalized.status === 401)
|
|
28
|
+
return new common_1.UnauthorizedException(payload);
|
|
29
|
+
if (normalized.status === 403)
|
|
30
|
+
return new common_1.ForbiddenException(payload);
|
|
31
|
+
if (normalized.status === 503)
|
|
32
|
+
return new common_1.ServiceUnavailableException(payload);
|
|
33
|
+
return new common_1.InternalServerErrorException(payload);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Crea un guard Nest configurato con le opzioni del resource server.
|
|
37
|
+
*
|
|
38
|
+
* Uso:
|
|
39
|
+
* `@UseGuards(createAccessiAuthGuard(options))`
|
|
40
|
+
*/
|
|
41
|
+
function createAccessiAuthGuard(options) {
|
|
42
|
+
const runtime = (0, runtime_1.createAccessiResourceServer)(options);
|
|
43
|
+
let ConfiguredAccessiAuthGuard = class ConfiguredAccessiAuthGuard {
|
|
44
|
+
canActivate(context) {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
const request = context.switchToHttp().getRequest();
|
|
47
|
+
try {
|
|
48
|
+
yield (0, runtime_1.authenticateAccessiRequest)(request, runtime);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
throw toNestException(error);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
ConfiguredAccessiAuthGuard = __decorate([
|
|
58
|
+
(0, common_1.Injectable)()
|
|
59
|
+
], ConfiguredAccessiAuthGuard);
|
|
60
|
+
return ConfiguredAccessiAuthGuard;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=nest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nest.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/nest.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAiCA,wDAmBC;AApDD,2CASwB;AAExB,qCAAsD;AACtD,uCAAoF;AAGpF,SAAS,eAAe,CAAC,KAAc;IACrC,MAAM,UAAU,GAAG,KAAK,YAAY,mCAA0B;QAC5D,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAI,mCAA0B,CAAC,GAAG,EAAE,qBAAqB,EAAE,0CAA0C,CAAC,CAAC;IAC3G,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC;IAEvE,IAAI,UAAU,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,8BAAqB,CAAC,OAAO,CAAC,CAAC;IACzE,IAAI,UAAU,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,2BAAkB,CAAC,OAAO,CAAC,CAAC;IACtE,IAAI,UAAU,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,oCAA2B,CAAC,OAAO,CAAC,CAAC;IAC/E,OAAO,IAAI,qCAA4B,CAAC,OAAO,CAAC,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,sBAAsB,CACpC,OAAqC;IAErC,MAAM,OAAO,GAAG,IAAA,qCAA2B,EAAC,OAAO,CAAC,CAAC;IAGrD,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;QACxB,WAAW,CAAC,OAAyB;;gBACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAC;gBAC7D,IAAI,CAAC;oBACH,MAAM,IAAA,oCAA0B,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBACnD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,eAAe,CAAC,KAAK,CAAC,CAAC;gBAC/B,CAAC;YACH,CAAC;SAAA;KACF,CAAA;IAVK,0BAA0B;QAD/B,IAAA,mBAAU,GAAE;OACP,0BAA0B,CAU/B;IAED,OAAO,0BAA0B,CAAC;AACpC,CAAC","sourcesContent":["import {\n CanActivate,\n ExecutionContext,\n ForbiddenException,\n Injectable,\n InternalServerErrorException,\n ServiceUnavailableException,\n Type,\n UnauthorizedException,\n} from \"@nestjs/common\";\nimport type { Request } from \"express\";\nimport { AccessiResourceServerError } from \"./errors\";\nimport { authenticateAccessiRequest, createAccessiResourceServer } from \"./runtime\";\nimport type { AccessiResourceServerOptions } from \"./types\";\n\nfunction toNestException(error: unknown): Error {\n const normalized = error instanceof AccessiResourceServerError\n ? error\n : new AccessiResourceServerError(500, \"AUTH_INTERNAL_ERROR\", \"Errore interno durante l'autenticazione.\");\n const payload = { code: normalized.code, message: normalized.message };\n\n if (normalized.status === 401) return new UnauthorizedException(payload);\n if (normalized.status === 403) return new ForbiddenException(payload);\n if (normalized.status === 503) return new ServiceUnavailableException(payload);\n return new InternalServerErrorException(payload);\n}\n\n/**\n * Crea un guard Nest configurato con le opzioni del resource server.\n *\n * Uso:\n * `@UseGuards(createAccessiAuthGuard(options))`\n */\nexport function createAccessiAuthGuard(\n options: AccessiResourceServerOptions,\n): Type<CanActivate> {\n const runtime = createAccessiResourceServer(options);\n\n @Injectable()\n class ConfiguredAccessiAuthGuard implements CanActivate {\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<Request>();\n try {\n await authenticateAccessiRequest(request, runtime);\n return true;\n } catch (error) {\n throw toNestException(error);\n }\n }\n }\n\n return ConfiguredAccessiAuthGuard;\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Request } from "express";
|
|
2
|
+
import type { GrantsResult } from "../contracts";
|
|
3
|
+
import type { AccessiIntrospectionClient } from "./introspection";
|
|
4
|
+
import type { AccessiTokenVerifier } from "./token";
|
|
5
|
+
import type { AccessiRequestContext, AccessiResourceServerOptions } from "./types";
|
|
6
|
+
/** Request Express arricchita dal resource server. */
|
|
7
|
+
export interface AccessiAuthenticatedRequest extends Request {
|
|
8
|
+
user?: Record<string, unknown>;
|
|
9
|
+
data?: Record<string, unknown>;
|
|
10
|
+
userGrants?: GrantsResult;
|
|
11
|
+
accessi?: AccessiRequestContext;
|
|
12
|
+
}
|
|
13
|
+
/** Runtime creato una volta al bootstrap e riutilizzato a ogni richiesta. */
|
|
14
|
+
export interface AccessiResourceServerRuntime {
|
|
15
|
+
options: AccessiResourceServerOptions;
|
|
16
|
+
verifier?: AccessiTokenVerifier;
|
|
17
|
+
introspectionClient?: AccessiIntrospectionClient;
|
|
18
|
+
}
|
|
19
|
+
/** Valida la configurazione e prepara verificatore e client di introspection. */
|
|
20
|
+
export declare function createAccessiResourceServer(options: AccessiResourceServerOptions): AccessiResourceServerRuntime;
|
|
21
|
+
/**
|
|
22
|
+
* Autentica la request e applica l'eventuale policy di autorizzazione.
|
|
23
|
+
*
|
|
24
|
+
* Non accede mai al database Accessi: la verifica e locale oppure delegata
|
|
25
|
+
* all'introspection di Accessi Service.
|
|
26
|
+
*/
|
|
27
|
+
export declare function authenticateAccessiRequest(request: Request, runtime: AccessiResourceServerRuntime): Promise<AccessiRequestContext>;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.createAccessiResourceServer = createAccessiResourceServer;
|
|
13
|
+
exports.authenticateAccessiRequest = authenticateAccessiRequest;
|
|
14
|
+
const contracts_1 = require("../contracts");
|
|
15
|
+
const errors_1 = require("./errors");
|
|
16
|
+
const introspection_1 = require("./introspection");
|
|
17
|
+
const token_1 = require("./token");
|
|
18
|
+
function resolveMode(options) {
|
|
19
|
+
if (options.mode)
|
|
20
|
+
return options.mode;
|
|
21
|
+
if (options.jwt)
|
|
22
|
+
return "local";
|
|
23
|
+
if (options.introspection)
|
|
24
|
+
return "introspection";
|
|
25
|
+
throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "Configurare jwt o introspection nel resource server Accessi.");
|
|
26
|
+
}
|
|
27
|
+
/** Valida la configurazione e prepara verificatore e client di introspection. */
|
|
28
|
+
function createAccessiResourceServer(options) {
|
|
29
|
+
const mode = resolveMode(options);
|
|
30
|
+
if (mode === "local" && !options.jwt) {
|
|
31
|
+
throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "mode local richiede jwt.");
|
|
32
|
+
}
|
|
33
|
+
if (mode === "introspection" && !options.introspection) {
|
|
34
|
+
throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "mode introspection richiede introspection.");
|
|
35
|
+
}
|
|
36
|
+
return Object.assign(Object.assign({ options: Object.assign(Object.assign({}, options), { mode }) }, (options.jwt ? { verifier: (0, token_1.createAccessiTokenVerifier)(options.jwt) } : {})), (options.introspection
|
|
37
|
+
? { introspectionClient: (0, introspection_1.createAccessiIntrospectionClient)(options.introspection) }
|
|
38
|
+
: {}));
|
|
39
|
+
}
|
|
40
|
+
function mergeIntrospectionUser(payload, user) {
|
|
41
|
+
return Object.assign(Object.assign(Object.assign({}, (payload !== null && payload !== void 0 ? payload : { typ: "access" })), user), { typ: "access", utente: user });
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Autentica la request e applica l'eventuale policy di autorizzazione.
|
|
45
|
+
*
|
|
46
|
+
* Non accede mai al database Accessi: la verifica e locale oppure delegata
|
|
47
|
+
* all'introspection di Accessi Service.
|
|
48
|
+
*/
|
|
49
|
+
function authenticateAccessiRequest(request, runtime) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
var _a, _b;
|
|
52
|
+
const token = (0, contracts_1.extractAccessiBearerToken)(request.headers.authorization);
|
|
53
|
+
if (!token) {
|
|
54
|
+
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_MISSING", "Token Bearer mancante o malformato.");
|
|
55
|
+
}
|
|
56
|
+
const mode = (_a = runtime.options.mode) !== null && _a !== void 0 ? _a : "local";
|
|
57
|
+
let payload;
|
|
58
|
+
let user = {};
|
|
59
|
+
let codiceUtente;
|
|
60
|
+
let grants;
|
|
61
|
+
if (mode === "local") {
|
|
62
|
+
if (!runtime.verifier) {
|
|
63
|
+
throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "Verificatore JWT non configurato.");
|
|
64
|
+
}
|
|
65
|
+
const verification = yield runtime.verifier.verify(token);
|
|
66
|
+
payload = verification.payload;
|
|
67
|
+
user = verification.user;
|
|
68
|
+
codiceUtente = verification.codiceUtente;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
if (!runtime.introspectionClient) {
|
|
72
|
+
throw (0, errors_1.accessiAuthError)(500, "AUTH_CONFIG_INVALID", "Client introspection non configurato.");
|
|
73
|
+
}
|
|
74
|
+
const introspection = yield runtime.introspectionClient.introspect(token);
|
|
75
|
+
if (!introspection.active) {
|
|
76
|
+
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Token non valido, scaduto o revocato.");
|
|
77
|
+
}
|
|
78
|
+
user = (_b = introspection.user) !== null && _b !== void 0 ? _b : {};
|
|
79
|
+
codiceUtente = introspection.codiceUtente;
|
|
80
|
+
grants = introspection.grants;
|
|
81
|
+
payload = mergeIntrospectionUser(undefined, user);
|
|
82
|
+
}
|
|
83
|
+
if (!codiceUtente) {
|
|
84
|
+
throw (0, errors_1.accessiAuthError)(401, "AUTH_USER_CODE_MISSING", "Token privo di un utente valido.");
|
|
85
|
+
}
|
|
86
|
+
const requirementTree = (0, contracts_1.buildRequirementTree)(runtime.options.authorization);
|
|
87
|
+
if (requirementTree) {
|
|
88
|
+
if (!grants) {
|
|
89
|
+
if (!runtime.introspectionClient) {
|
|
90
|
+
throw (0, errors_1.accessiAuthError)(500, "AUTH_GRANTS_SOURCE_MISSING", "La policy richiede grant ma introspection non e configurata.");
|
|
91
|
+
}
|
|
92
|
+
const introspection = yield runtime.introspectionClient.introspect(token);
|
|
93
|
+
if (!introspection.active) {
|
|
94
|
+
throw (0, errors_1.accessiAuthError)(401, "AUTH_TOKEN_INVALID", "Token non valido, scaduto o revocato.");
|
|
95
|
+
}
|
|
96
|
+
grants = introspection.grants;
|
|
97
|
+
if (introspection.user) {
|
|
98
|
+
user = introspection.user;
|
|
99
|
+
payload = mergeIntrospectionUser(payload, user);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const hasPermissions = yield (0, contracts_1.evaluateRequirement)(requirementTree, {
|
|
103
|
+
req: request,
|
|
104
|
+
decodedToken: payload,
|
|
105
|
+
userCode: codiceUtente,
|
|
106
|
+
getGrantsResult: () => __awaiter(this, void 0, void 0, function* () { return grants !== null && grants !== void 0 ? grants : {}; }),
|
|
107
|
+
}, runtime.options.authorization);
|
|
108
|
+
if (!hasPermissions) {
|
|
109
|
+
throw (0, errors_1.accessiAuthError)(403, "AUTH_INSUFFICIENT_PERMISSIONS", "Permessi insufficienti per questa operazione.");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const authenticatedRequest = request;
|
|
113
|
+
const authPayload = payload !== null && payload !== void 0 ? payload : {
|
|
114
|
+
typ: "access",
|
|
115
|
+
codiceUtente,
|
|
116
|
+
utente: user,
|
|
117
|
+
};
|
|
118
|
+
authenticatedRequest.user = authPayload;
|
|
119
|
+
authenticatedRequest.data = authPayload;
|
|
120
|
+
if (grants)
|
|
121
|
+
authenticatedRequest.userGrants = grants;
|
|
122
|
+
authenticatedRequest.accessi = Object.assign(Object.assign({ token,
|
|
123
|
+
user,
|
|
124
|
+
codiceUtente }, (grants ? { grants } : {})), { payload: authPayload });
|
|
125
|
+
return authenticatedRequest.accessi;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/accessi/resource-server/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Request } from \"express\";\nimport {\n buildRequirementTree,\n evaluateRequirement,\n extractAccessiBearerToken,\n} from \"../contracts\";\nimport type {\n AccessiAccessTokenPayload,\n GrantsResult,\n} from \"../contracts\";\nimport { accessiAuthError } from \"./errors\";\nimport { createAccessiIntrospectionClient } from \"./introspection\";\nimport type { AccessiIntrospectionClient } from \"./introspection\";\nimport { createAccessiTokenVerifier } from \"./token\";\nimport type { AccessiTokenVerifier } from \"./token\";\nimport type {\n AccessiRequestContext,\n AccessiResourceServerOptions,\n} from \"./types\";\n\n/** Request Express arricchita dal resource server. */\nexport interface AccessiAuthenticatedRequest extends Request {\n user?: Record<string, unknown>;\n data?: Record<string, unknown>;\n userGrants?: GrantsResult;\n accessi?: AccessiRequestContext;\n}\n\n/** Runtime creato una volta al bootstrap e riutilizzato a ogni richiesta. */\nexport interface AccessiResourceServerRuntime {\n options: AccessiResourceServerOptions;\n verifier?: AccessiTokenVerifier;\n introspectionClient?: AccessiIntrospectionClient;\n}\n\nfunction resolveMode(options: AccessiResourceServerOptions): \"local\" | \"introspection\" {\n if (options.mode) return options.mode;\n if (options.jwt) return \"local\";\n if (options.introspection) return \"introspection\";\n throw accessiAuthError(\n 500,\n \"AUTH_CONFIG_INVALID\",\n \"Configurare jwt o introspection nel resource server Accessi.\",\n );\n}\n\n/** Valida la configurazione e prepara verificatore e client di introspection. */\nexport function createAccessiResourceServer(\n options: AccessiResourceServerOptions,\n): AccessiResourceServerRuntime {\n const mode = resolveMode(options);\n if (mode === \"local\" && !options.jwt) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"mode local richiede jwt.\");\n }\n if (mode === \"introspection\" && !options.introspection) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"mode introspection richiede introspection.\");\n }\n\n return {\n options: { ...options, mode },\n ...(options.jwt ? { verifier: createAccessiTokenVerifier(options.jwt) } : {}),\n ...(options.introspection\n ? { introspectionClient: createAccessiIntrospectionClient(options.introspection) }\n : {}),\n };\n}\n\nfunction mergeIntrospectionUser(\n payload: AccessiAccessTokenPayload | undefined,\n user: Record<string, unknown>,\n): AccessiAccessTokenPayload {\n return {\n ...(payload ?? { typ: \"access\" }),\n ...user,\n typ: \"access\",\n utente: user,\n };\n}\n\n/**\n * Autentica la request e applica l'eventuale policy di autorizzazione.\n *\n * Non accede mai al database Accessi: la verifica e locale oppure delegata\n * all'introspection di Accessi Service.\n */\nexport async function authenticateAccessiRequest(\n request: Request,\n runtime: AccessiResourceServerRuntime,\n): Promise<AccessiRequestContext> {\n const token = extractAccessiBearerToken(request.headers.authorization);\n if (!token) {\n throw accessiAuthError(401, \"AUTH_TOKEN_MISSING\", \"Token Bearer mancante o malformato.\");\n }\n\n const mode = runtime.options.mode ?? \"local\";\n let payload: AccessiAccessTokenPayload | undefined;\n let user: Record<string, unknown> = {};\n let codiceUtente: number | undefined;\n let grants: GrantsResult | undefined;\n\n if (mode === \"local\") {\n if (!runtime.verifier) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"Verificatore JWT non configurato.\");\n }\n const verification = await runtime.verifier.verify(token);\n payload = verification.payload;\n user = verification.user;\n codiceUtente = verification.codiceUtente;\n } else {\n if (!runtime.introspectionClient) {\n throw accessiAuthError(500, \"AUTH_CONFIG_INVALID\", \"Client introspection non configurato.\");\n }\n const introspection = await runtime.introspectionClient.introspect(token);\n if (!introspection.active) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token non valido, scaduto o revocato.\");\n }\n user = introspection.user ?? {};\n codiceUtente = introspection.codiceUtente;\n grants = introspection.grants;\n payload = mergeIntrospectionUser(undefined, user);\n }\n\n if (!codiceUtente) {\n throw accessiAuthError(401, \"AUTH_USER_CODE_MISSING\", \"Token privo di un utente valido.\");\n }\n\n const requirementTree = buildRequirementTree(runtime.options.authorization);\n if (requirementTree) {\n if (!grants) {\n if (!runtime.introspectionClient) {\n throw accessiAuthError(\n 500,\n \"AUTH_GRANTS_SOURCE_MISSING\",\n \"La policy richiede grant ma introspection non e configurata.\",\n );\n }\n const introspection = await runtime.introspectionClient.introspect(token);\n if (!introspection.active) {\n throw accessiAuthError(401, \"AUTH_TOKEN_INVALID\", \"Token non valido, scaduto o revocato.\");\n }\n grants = introspection.grants;\n if (introspection.user) {\n user = introspection.user;\n payload = mergeIntrospectionUser(payload, user);\n }\n }\n\n const hasPermissions = await evaluateRequirement(\n requirementTree,\n {\n req: request,\n decodedToken: payload,\n userCode: codiceUtente,\n getGrantsResult: async () => grants ?? {},\n },\n runtime.options.authorization,\n );\n if (!hasPermissions) {\n throw accessiAuthError(\n 403,\n \"AUTH_INSUFFICIENT_PERMISSIONS\",\n \"Permessi insufficienti per questa operazione.\",\n );\n }\n }\n\n const authenticatedRequest = request as AccessiAuthenticatedRequest;\n const authPayload: Record<string, unknown> = payload ?? {\n typ: \"access\",\n codiceUtente,\n utente: user,\n };\n authenticatedRequest.user = authPayload;\n authenticatedRequest.data = authPayload;\n if (grants) authenticatedRequest.userGrants = grants;\n authenticatedRequest.accessi = {\n token,\n user,\n codiceUtente,\n ...(grants ? { grants } : {}),\n payload: authPayload,\n };\n return authenticatedRequest.accessi;\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AccessiAccessTokenPayload } from "../contracts";
|
|
2
|
+
import type { AccessiResourceServerJwtOptions } from "./types";
|
|
3
|
+
/** Esito della verifica locale di un access token. */
|
|
4
|
+
export interface AccessiTokenVerification {
|
|
5
|
+
token: string;
|
|
6
|
+
payload: AccessiAccessTokenPayload;
|
|
7
|
+
codiceUtente: number;
|
|
8
|
+
user: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
/** Verificatore riutilizzabile: conserva la cache JWKS tra una richiesta e l'altra. */
|
|
11
|
+
export interface AccessiTokenVerifier {
|
|
12
|
+
verify(token: string): Promise<AccessiTokenVerification>;
|
|
13
|
+
verifyAuthorizationHeader(header: unknown): Promise<AccessiTokenVerification>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Crea un verificatore locale riutilizzabile.
|
|
17
|
+
*
|
|
18
|
+
* Supporta HMAC, chiavi pubbliche PEM (RS ed ES) e JWKS remoto. La cache
|
|
19
|
+
* JWKS e legata all'istanza del verificatore.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createAccessiTokenVerifier(options: AccessiResourceServerJwtOptions): AccessiTokenVerifier;
|
|
22
|
+
/** Converte un header `Authorization` in verifica del token, senza cache JWKS condivisa. */
|
|
23
|
+
export declare function verifyAccessiAccessToken(header: unknown, options: AccessiResourceServerJwtOptions): Promise<AccessiTokenVerification>;
|