@jantstack/adonis-authz 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +138 -0
- package/build/commands/main.d.ts +7 -0
- package/build/commands/main.d.ts.map +1 -0
- package/build/commands/main.js +7 -0
- package/build/commands/main.js.map +1 -0
- package/build/commands/openfga_import.d.ts +28 -0
- package/build/commands/openfga_import.d.ts.map +1 -0
- package/build/commands/openfga_import.js +74 -0
- package/build/commands/openfga_import.js.map +1 -0
- package/build/commands/openfga_provision.d.ts +27 -0
- package/build/commands/openfga_provision.d.ts.map +1 -0
- package/build/commands/openfga_provision.js +73 -0
- package/build/commands/openfga_provision.js.map +1 -0
- package/build/configure.d.ts +10 -0
- package/build/configure.d.ts.map +1 -0
- package/build/configure.js +43 -0
- package/build/configure.js.map +1 -0
- package/build/index.d.ts +21 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +18 -0
- package/build/index.js.map +1 -0
- package/build/providers/authz_provider.d.ts +17 -0
- package/build/providers/authz_provider.d.ts.map +1 -0
- package/build/providers/authz_provider.js +21 -0
- package/build/providers/authz_provider.js.map +1 -0
- package/build/services/main.d.ts +10 -0
- package/build/services/main.d.ts.map +1 -0
- package/build/services/main.js +13 -0
- package/build/services/main.js.map +1 -0
- package/build/src/catalog.d.ts +3 -0
- package/build/src/catalog.d.ts.map +1 -0
- package/build/src/catalog.js +97 -0
- package/build/src/catalog.js.map +1 -0
- package/build/src/define_config.d.ts +53 -0
- package/build/src/define_config.d.ts.map +1 -0
- package/build/src/define_config.js +4 -0
- package/build/src/define_config.js.map +1 -0
- package/build/src/drivers/database_driver.d.ts +48 -0
- package/build/src/drivers/database_driver.d.ts.map +1 -0
- package/build/src/drivers/database_driver.js +260 -0
- package/build/src/drivers/database_driver.js.map +1 -0
- package/build/src/drivers/openfga_driver.d.ts +107 -0
- package/build/src/drivers/openfga_driver.d.ts.map +1 -0
- package/build/src/drivers/openfga_driver.js +450 -0
- package/build/src/drivers/openfga_driver.js.map +1 -0
- package/build/src/manager.d.ts +29 -0
- package/build/src/manager.d.ts.map +1 -0
- package/build/src/manager.js +79 -0
- package/build/src/manager.js.map +1 -0
- package/build/src/middleware/app_access_middleware.d.ts +23 -0
- package/build/src/middleware/app_access_middleware.d.ts.map +1 -0
- package/build/src/middleware/app_access_middleware.js +53 -0
- package/build/src/middleware/app_access_middleware.js.map +1 -0
- package/build/src/models/authz_assignment.d.ts +166 -0
- package/build/src/models/authz_assignment.d.ts.map +1 -0
- package/build/src/models/authz_assignment.js +60 -0
- package/build/src/models/authz_assignment.js.map +1 -0
- package/build/src/models/authz_deny.d.ts +161 -0
- package/build/src/models/authz_deny.d.ts.map +1 -0
- package/build/src/models/authz_deny.js +50 -0
- package/build/src/models/authz_deny.js.map +1 -0
- package/build/src/models/authz_permission.d.ts +159 -0
- package/build/src/models/authz_permission.d.ts.map +1 -0
- package/build/src/models/authz_permission.js +42 -0
- package/build/src/models/authz_permission.js.map +1 -0
- package/build/src/models/authz_role.d.ts +166 -0
- package/build/src/models/authz_role.d.ts.map +1 -0
- package/build/src/models/authz_role.js +66 -0
- package/build/src/models/authz_role.js.map +1 -0
- package/build/src/models/authz_role_permission.d.ts +155 -0
- package/build/src/models/authz_role_permission.d.ts.map +1 -0
- package/build/src/models/authz_role_permission.js +35 -0
- package/build/src/models/authz_role_permission.js.map +1 -0
- package/build/src/testing/contract.d.ts +27 -0
- package/build/src/testing/contract.d.ts.map +1 -0
- package/build/src/testing/contract.js +211 -0
- package/build/src/testing/contract.js.map +1 -0
- package/build/src/testing/main.d.ts +11 -0
- package/build/src/testing/main.d.ts.map +1 -0
- package/build/src/testing/main.js +10 -0
- package/build/src/testing/main.js.map +1 -0
- package/build/src/traits/authz_scopes.d.ts +21 -0
- package/build/src/traits/authz_scopes.d.ts.map +1 -0
- package/build/src/traits/authz_scopes.js +45 -0
- package/build/src/traits/authz_scopes.js.map +1 -0
- package/build/src/traits/has_uuid.d.ts +151 -0
- package/build/src/traits/has_uuid.d.ts.map +1 -0
- package/build/src/traits/has_uuid.js +38 -0
- package/build/src/traits/has_uuid.js.map +1 -0
- package/build/src/types.d.ts +153 -0
- package/build/src/types.d.ts.map +1 -0
- package/build/src/types.js +38 -0
- package/build/src/types.js.map +1 -0
- package/build/stubs/config/app_acl.stub +81 -0
- package/build/stubs/config/authorization.stub +74 -0
- package/build/stubs/main.d.ts +3 -0
- package/build/stubs/main.d.ts.map +1 -0
- package/build/stubs/main.js +3 -0
- package/build/stubs/main.js.map +1 -0
- package/build/stubs/migration.stub +124 -0
- package/package.json +94 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import db from '@adonisjs/lucid/services/db';
|
|
2
|
+
import { Exception } from '@adonisjs/core/exceptions';
|
|
3
|
+
import { v7 as uuidv7 } from 'uuid';
|
|
4
|
+
/**
|
|
5
|
+
* Sincroniza un catálogo (roles + permisos + vínculos) a las tablas `authz_*`.
|
|
6
|
+
*
|
|
7
|
+
* Idempotente y aditivo (mismo contrato que el organization_acl_seeder): lo
|
|
8
|
+
* existente se respeta, solo se insertan los diffs nuevos. Quitar algo del
|
|
9
|
+
* catálogo NO lo borra de DB (limpieza explícita vía migración).
|
|
10
|
+
*
|
|
11
|
+
* Lo usan el seeder del nivel app (`app_acl_seeder`) y el harness de la
|
|
12
|
+
* suite de contrato. El catálogo es metadata compartida entre drivers:
|
|
13
|
+
* un driver externo (openfga) materializa aparte solo los hechos.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Slugs válidos del catálogo: minúsculas, dígitos y . _ - con `:` opcional
|
|
17
|
+
* (gramática recurso:accion). Prohibidos `~` y `|`: son los caracteres de
|
|
18
|
+
* encoding/separador del driver openfga — un slug que los contenga
|
|
19
|
+
* corrompería el mapeo de bindings.
|
|
20
|
+
*/
|
|
21
|
+
const CATALOG_SLUG_FORMAT = /^[a-z0-9][a-z0-9_.-]*(:[a-z0-9][a-z0-9_.-]*)?$/;
|
|
22
|
+
function assertValidSlug(kind, slug) {
|
|
23
|
+
if (!CATALOG_SLUG_FORMAT.test(slug)) {
|
|
24
|
+
throw new Exception(`Slug de ${kind} inválido: '${slug}'. Formato: minúsculas/dígitos/._- ` +
|
|
25
|
+
`con ':' único opcional (recurso:accion); '~' y '|' están prohibidos.`, { status: 500 });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function syncAuthzCatalog(catalog) {
|
|
29
|
+
for (const perm of catalog.permissions)
|
|
30
|
+
assertValidSlug('permiso', perm.slug);
|
|
31
|
+
for (const role of catalog.roles)
|
|
32
|
+
assertValidSlug('rol', role.slug);
|
|
33
|
+
// 1. Permisos: upsert por slug.
|
|
34
|
+
for (const perm of catalog.permissions) {
|
|
35
|
+
const existing = await db.from('authz_permissions').where('slug', perm.slug).first();
|
|
36
|
+
if (existing)
|
|
37
|
+
continue;
|
|
38
|
+
await db.table('authz_permissions').insert({
|
|
39
|
+
uuid: uuidv7(),
|
|
40
|
+
slug: perm.slug,
|
|
41
|
+
description: perm.description ?? null,
|
|
42
|
+
created_at: new Date(),
|
|
43
|
+
updated_at: new Date(),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const dbPerms = await db
|
|
47
|
+
.from('authz_permissions')
|
|
48
|
+
.whereIn('slug', catalog.permissions.map((p) => p.slug))
|
|
49
|
+
.select('uuid', 'slug');
|
|
50
|
+
const permUuidBySlug = new Map(dbPerms.map((p) => [p.slug, p.uuid]));
|
|
51
|
+
// 2. Roles: upsert por (slug, scope_type).
|
|
52
|
+
for (const role of catalog.roles) {
|
|
53
|
+
const existing = await db
|
|
54
|
+
.from('authz_roles')
|
|
55
|
+
.where('slug', role.slug)
|
|
56
|
+
.where('scope_type', role.scopeType)
|
|
57
|
+
.first();
|
|
58
|
+
const roleUuid = existing?.uuid ?? role.uuid ?? uuidv7();
|
|
59
|
+
if (!existing) {
|
|
60
|
+
await db.table('authz_roles').insert({
|
|
61
|
+
uuid: roleUuid,
|
|
62
|
+
slug: role.slug,
|
|
63
|
+
name: role.name ?? role.slug,
|
|
64
|
+
description: role.description ?? null,
|
|
65
|
+
scope_type: role.scopeType,
|
|
66
|
+
rank: role.rank ?? 0,
|
|
67
|
+
created_at: new Date(),
|
|
68
|
+
updated_at: new Date(),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
else if (role.rank !== undefined && existing.rank !== role.rank) {
|
|
72
|
+
// El rank es metadata de policy: el config manda (a diferencia de los
|
|
73
|
+
// vínculos, que son aditivos).
|
|
74
|
+
await db.from('authz_roles').where('uuid', roleUuid).update({ rank: role.rank });
|
|
75
|
+
}
|
|
76
|
+
// 3. Vínculos rol→permiso: upsert por par.
|
|
77
|
+
for (const permSlug of role.permissions) {
|
|
78
|
+
const permUuid = permUuidBySlug.get(permSlug);
|
|
79
|
+
if (!permUuid)
|
|
80
|
+
continue;
|
|
81
|
+
const linked = await db
|
|
82
|
+
.from('authz_role_permissions')
|
|
83
|
+
.where('role_uuid', roleUuid)
|
|
84
|
+
.where('permission_uuid', permUuid)
|
|
85
|
+
.first();
|
|
86
|
+
if (linked)
|
|
87
|
+
continue;
|
|
88
|
+
await db.table('authz_role_permissions').insert({
|
|
89
|
+
uuid: uuidv7(),
|
|
90
|
+
role_uuid: roleUuid,
|
|
91
|
+
permission_uuid: permUuid,
|
|
92
|
+
created_at: new Date(),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { AuthorizationDriverFactory, AuthzWriteEvent } from './types.js';
|
|
2
|
+
import type { HolderTypeMap } from './drivers/openfga_driver.js';
|
|
3
|
+
/**
|
|
4
|
+
* Config del sistema de autorización. Todo lo específico del consumidor
|
|
5
|
+
* entra por aquí: qué drivers existen, cuál está activo, cómo se llaman sus
|
|
6
|
+
* holders y qué hacer cuando el motor escribe.
|
|
7
|
+
*
|
|
8
|
+
* export default defineConfig({
|
|
9
|
+
* default: env.get('AUTHZ_DRIVER', 'database'),
|
|
10
|
+
* holderTypes: { users: 'user', admins: 'admin' },
|
|
11
|
+
* drivers: {
|
|
12
|
+
* database: () => new DatabaseAuthorizationDriver({ resolveAncestors }),
|
|
13
|
+
* 'mi-driver': () => new MiDriver(),
|
|
14
|
+
* },
|
|
15
|
+
* hooks: { onWrite: auditarEscritura },
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* Todo driver debe pasar la suite de contrato que publica el paquete
|
|
19
|
+
* (`@jantstack/adonis-authz/testing`).
|
|
20
|
+
*/
|
|
21
|
+
export interface AuthorizationConfig {
|
|
22
|
+
/** Nombre del driver activo (debe existir como key en `drivers`). */
|
|
23
|
+
default: string;
|
|
24
|
+
drivers: Record<string, AuthorizationDriverFactory>;
|
|
25
|
+
/**
|
|
26
|
+
* Holders del consumidor: morph name (`@MorphMap` del modelo) → tipo del
|
|
27
|
+
* modelo FGA. Lo necesitan el driver `openfga` y los comandos
|
|
28
|
+
* `openfga:provision` / `openfga:import`; el driver `database` lo ignora.
|
|
29
|
+
*/
|
|
30
|
+
holderTypes?: HolderTypeMap;
|
|
31
|
+
/**
|
|
32
|
+
* Conexión al servidor OpenFGA para las herramientas de línea de comandos
|
|
33
|
+
* (el driver recibe estos mismos valores en su factory).
|
|
34
|
+
*/
|
|
35
|
+
openfga?: {
|
|
36
|
+
url?: string;
|
|
37
|
+
storeId?: string;
|
|
38
|
+
modelId?: string;
|
|
39
|
+
/** Nombre del store al provisionar. */
|
|
40
|
+
storeName?: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Hooks del consumidor. `onWrite` se llama tras cada escritura del motor
|
|
44
|
+
* (grant/revoke/deny/removeDeny) — el sitio natural para auditar o emitir
|
|
45
|
+
* eventos. No debe lanzar: una escritura ya aplicada no se revierte por un
|
|
46
|
+
* side-effect fallido.
|
|
47
|
+
*/
|
|
48
|
+
hooks?: {
|
|
49
|
+
onWrite?: (event: AuthzWriteEvent) => Promise<void>;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export declare function defineConfig<T extends AuthorizationConfig>(config: T): T;
|
|
53
|
+
//# sourceMappingURL=define_config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define_config.d.ts","sourceRoot":"","sources":["../../src/define_config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAA;IAEnD;;;;OAIG;IACH,WAAW,CAAC,EAAE,aAAa,CAAA;IAE3B;;;OAGG;IACH,OAAO,CAAC,EAAE;QACR,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,uCAAuC;QACvC,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,CAAA;IAED;;;;;OAKG;IACH,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KACpD,CAAA;CACF;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,mBAAmB,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAExE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define_config.js","sourceRoot":"","sources":["../../src/define_config.ts"],"names":[],"mappings":"AAwDA,MAAM,UAAU,YAAY,CAAgC,MAAS;IACnE,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AuthorizationDriver, GrantOptions, ScopeRef, ScopeType, SubjectRef } from '../types.js';
|
|
2
|
+
import type { ScopeAncestorsResolver } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* UUID centinela para el scope 'app' en las columnas scope_uuid (NOT NULL):
|
|
5
|
+
* permite que el unique de assignments/denies cubra también el nivel app
|
|
6
|
+
* (los NULL serían "distintos" para el motor SQL). Detalle de almacenamiento
|
|
7
|
+
* de ESTE driver — la API pública sigue usando uuid null para app.
|
|
8
|
+
*/
|
|
9
|
+
export declare const APP_SCOPE_DB_UUID = "00000000-0000-0000-0000-000000000000";
|
|
10
|
+
/**
|
|
11
|
+
* Driver `database`: motor de autorización propio sobre las tablas `authz_*`.
|
|
12
|
+
* Default autosuficiente del chasis (cero piezas extra en el appliance).
|
|
13
|
+
*
|
|
14
|
+
* Resolución de `authorize`: NO hay deny en la cadena de scopes Y alguna
|
|
15
|
+
* asignación vigente (expires_at null o futuro) en la cadena concede el
|
|
16
|
+
* permiso vía su rol. La cadena es `[scope, ...ancestros]` — herencia solo
|
|
17
|
+
* hacia abajo. Solo SQL estándar vía query builder (regla M6: nada
|
|
18
|
+
* específico de un motor).
|
|
19
|
+
*/
|
|
20
|
+
export declare class DatabaseAuthorizationDriver implements AuthorizationDriver {
|
|
21
|
+
/**
|
|
22
|
+
* Resolutor de jerarquía inyectado por el consumidor (el chasis pasa el
|
|
23
|
+
* suyo, que conoce organizations/units, en `config/authorization.ts`).
|
|
24
|
+
* Default puro sin dominio: todo cuelga directamente de `app`.
|
|
25
|
+
*/
|
|
26
|
+
private resolveAncestors;
|
|
27
|
+
constructor(options?: {
|
|
28
|
+
resolveAncestors?: ScopeAncestorsResolver;
|
|
29
|
+
});
|
|
30
|
+
private chain;
|
|
31
|
+
/** Filtro (scope_type, scope_uuid) ∈ scopes (centinela para el nivel app). */
|
|
32
|
+
private whereScopeIn;
|
|
33
|
+
/** Asignación vigente: sin expiración o con expiración futura. */
|
|
34
|
+
private whereActive;
|
|
35
|
+
private findPermission;
|
|
36
|
+
private findRoleOrFail;
|
|
37
|
+
authorize(subject: SubjectRef, permission: string, scope: ScopeRef): Promise<boolean>;
|
|
38
|
+
grant(subject: SubjectRef, role: string, scope: ScopeRef, options?: GrantOptions): Promise<void>;
|
|
39
|
+
revoke(subject: SubjectRef, role: string, scope: ScopeRef): Promise<void>;
|
|
40
|
+
hasRole(subject: SubjectRef, role: string, scope: ScopeRef): Promise<boolean>;
|
|
41
|
+
deny(subject: SubjectRef, permission: string, scope: ScopeRef): Promise<void>;
|
|
42
|
+
removeDeny(subject: SubjectRef, permission: string, scope: ScopeRef): Promise<void>;
|
|
43
|
+
listSubjects(role: string, scope: ScopeRef): Promise<SubjectRef[]>;
|
|
44
|
+
listRoles(subject: SubjectRef, scope: ScopeRef): Promise<string[]>;
|
|
45
|
+
listRoleScopes(subject: SubjectRef, scopeType: ScopeType): Promise<ScopeRef[]>;
|
|
46
|
+
listScopes(subject: SubjectRef, permission: string): Promise<ScopeRef[]>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=database_driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database_driver.d.ts","sourceRoot":"","sources":["../../../src/drivers/database_driver.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,UAAU,EACX,MAAM,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAIzD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,yCAAyC,CAAA;AAUvE;;;;;;;;;GASG;AACH,qBAAa,2BAA4B,YAAW,mBAAmB;IACrE;;;;OAIG;IACH,OAAO,CAAC,gBAAgB,CAAwB;gBAEpC,OAAO,GAAE;QAAE,gBAAgB,CAAC,EAAE,sBAAsB,CAAA;KAAO;YAKzD,KAAK;IAInB,8EAA8E;IAC9E,OAAO,CAAC,YAAY;IAUpB,kEAAkE;IAClE,OAAO,CAAC,WAAW;YAML,cAAc;YAId,cAAc;IAetB,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAkCrF,KAAK,CACT,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,QAAQ,EACf,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC;IAqDV,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBzE,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAkB7E,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA2C7E,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAenF,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAiBlE,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAgBlE,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAY9E,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;CAkC/E"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import db from '@adonisjs/lucid/services/db';
|
|
2
|
+
import { Exception } from '@adonisjs/core/exceptions';
|
|
3
|
+
import { v7 as uuidv7 } from 'uuid';
|
|
4
|
+
import { APP_SCOPE } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* UUID centinela para el scope 'app' en las columnas scope_uuid (NOT NULL):
|
|
7
|
+
* permite que el unique de assignments/denies cubra también el nivel app
|
|
8
|
+
* (los NULL serían "distintos" para el motor SQL). Detalle de almacenamiento
|
|
9
|
+
* de ESTE driver — la API pública sigue usando uuid null para app.
|
|
10
|
+
*/
|
|
11
|
+
export const APP_SCOPE_DB_UUID = '00000000-0000-0000-0000-000000000000';
|
|
12
|
+
function toDbScopeUuid(scope) {
|
|
13
|
+
return scope.uuid ?? APP_SCOPE_DB_UUID;
|
|
14
|
+
}
|
|
15
|
+
function fromDbScopeUuid(uuid) {
|
|
16
|
+
return uuid === APP_SCOPE_DB_UUID ? null : uuid;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Driver `database`: motor de autorización propio sobre las tablas `authz_*`.
|
|
20
|
+
* Default autosuficiente del chasis (cero piezas extra en el appliance).
|
|
21
|
+
*
|
|
22
|
+
* Resolución de `authorize`: NO hay deny en la cadena de scopes Y alguna
|
|
23
|
+
* asignación vigente (expires_at null o futuro) en la cadena concede el
|
|
24
|
+
* permiso vía su rol. La cadena es `[scope, ...ancestros]` — herencia solo
|
|
25
|
+
* hacia abajo. Solo SQL estándar vía query builder (regla M6: nada
|
|
26
|
+
* específico de un motor).
|
|
27
|
+
*/
|
|
28
|
+
export class DatabaseAuthorizationDriver {
|
|
29
|
+
/**
|
|
30
|
+
* Resolutor de jerarquía inyectado por el consumidor (el chasis pasa el
|
|
31
|
+
* suyo, que conoce organizations/units, en `config/authorization.ts`).
|
|
32
|
+
* Default puro sin dominio: todo cuelga directamente de `app`.
|
|
33
|
+
*/
|
|
34
|
+
resolveAncestors;
|
|
35
|
+
constructor(options = {}) {
|
|
36
|
+
this.resolveAncestors =
|
|
37
|
+
options.resolveAncestors ?? (async (scope) => (scope.type === 'app' ? [] : [APP_SCOPE]));
|
|
38
|
+
}
|
|
39
|
+
async chain(scope) {
|
|
40
|
+
return [scope, ...(await this.resolveAncestors(scope))];
|
|
41
|
+
}
|
|
42
|
+
/** Filtro (scope_type, scope_uuid) ∈ scopes (centinela para el nivel app). */
|
|
43
|
+
whereScopeIn(query, column, scopes) {
|
|
44
|
+
return query.where((outer) => {
|
|
45
|
+
for (const s of scopes) {
|
|
46
|
+
outer.orWhere((inner) => {
|
|
47
|
+
inner.where(`${column}_type`, s.type).where(`${column}_uuid`, toDbScopeUuid(s));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Asignación vigente: sin expiración o con expiración futura. */
|
|
53
|
+
whereActive(query, column = 'expires_at') {
|
|
54
|
+
return query.where((builder) => {
|
|
55
|
+
builder.whereNull(column).orWhere(column, '>', new Date());
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async findPermission(slug) {
|
|
59
|
+
return db.from('authz_permissions').where('slug', slug).select('uuid').first();
|
|
60
|
+
}
|
|
61
|
+
async findRoleOrFail(slug, scopeType) {
|
|
62
|
+
const role = await db
|
|
63
|
+
.from('authz_roles')
|
|
64
|
+
.where('slug', slug)
|
|
65
|
+
.where('scope_type', scopeType)
|
|
66
|
+
.select('uuid')
|
|
67
|
+
.first();
|
|
68
|
+
if (!role) {
|
|
69
|
+
throw new Exception(`Rol '${slug}' no existe en el catálogo para el nivel '${scopeType}'`, {
|
|
70
|
+
status: 422,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return role;
|
|
74
|
+
}
|
|
75
|
+
async authorize(subject, permission, scope) {
|
|
76
|
+
const perm = await this.findPermission(permission);
|
|
77
|
+
if (!perm)
|
|
78
|
+
return false;
|
|
79
|
+
const chain = await this.chain(scope);
|
|
80
|
+
const denied = await this.whereScopeIn(db
|
|
81
|
+
.from('authz_denies')
|
|
82
|
+
.where('holder_type', subject.type)
|
|
83
|
+
.where('holder_uuid', subject.uuid)
|
|
84
|
+
.where('permission_uuid', perm.uuid), 'scope', chain).first();
|
|
85
|
+
if (denied)
|
|
86
|
+
return false;
|
|
87
|
+
const granted = await this.whereActive(this.whereScopeIn(db
|
|
88
|
+
.from('authz_assignments as a')
|
|
89
|
+
.join('authz_role_permissions as rp', 'rp.role_uuid', 'a.role_uuid')
|
|
90
|
+
.where('rp.permission_uuid', perm.uuid)
|
|
91
|
+
.where('a.holder_type', subject.type)
|
|
92
|
+
.where('a.holder_uuid', subject.uuid), 'a.scope', chain), 'a.expires_at').first();
|
|
93
|
+
return Boolean(granted);
|
|
94
|
+
}
|
|
95
|
+
async grant(subject, role, scope, options = {}) {
|
|
96
|
+
const { uuid: roleUuid } = await this.findRoleOrFail(role, scope.type);
|
|
97
|
+
const expiresAt = options.expiresAt ?? null;
|
|
98
|
+
const existing = await this.whereScopeIn(db
|
|
99
|
+
.from('authz_assignments')
|
|
100
|
+
.where('holder_type', subject.type)
|
|
101
|
+
.where('holder_uuid', subject.uuid)
|
|
102
|
+
.where('role_uuid', roleUuid), 'scope', [scope]).first();
|
|
103
|
+
if (existing) {
|
|
104
|
+
// Idempotente: re-grant refresca la expiración (revivir una asignación
|
|
105
|
+
// expirada es un grant nuevo a todos los efectos).
|
|
106
|
+
await db.from('authz_assignments').where('uuid', existing.uuid).update({
|
|
107
|
+
expires_at: expiresAt,
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
await db.table('authz_assignments').insert({
|
|
113
|
+
uuid: uuidv7(),
|
|
114
|
+
holder_type: subject.type,
|
|
115
|
+
holder_uuid: subject.uuid,
|
|
116
|
+
role_uuid: roleUuid,
|
|
117
|
+
scope_type: scope.type,
|
|
118
|
+
scope_uuid: toDbScopeUuid(scope),
|
|
119
|
+
expires_at: expiresAt,
|
|
120
|
+
created_at: new Date(),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
// Carrera check-then-insert: el unique (que cubre también el nivel app
|
|
125
|
+
// vía centinela) la detecta — el perdedor degrada a update (idempotente).
|
|
126
|
+
const raced = await this.whereScopeIn(db
|
|
127
|
+
.from('authz_assignments')
|
|
128
|
+
.where('holder_type', subject.type)
|
|
129
|
+
.where('holder_uuid', subject.uuid)
|
|
130
|
+
.where('role_uuid', roleUuid), 'scope', [scope]).first();
|
|
131
|
+
if (!raced)
|
|
132
|
+
throw error;
|
|
133
|
+
await db.from('authz_assignments').where('uuid', raced.uuid).update({
|
|
134
|
+
expires_at: expiresAt,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async revoke(subject, role, scope) {
|
|
139
|
+
const roleRow = await db
|
|
140
|
+
.from('authz_roles')
|
|
141
|
+
.where('slug', role)
|
|
142
|
+
.where('scope_type', scope.type)
|
|
143
|
+
.select('uuid')
|
|
144
|
+
.first();
|
|
145
|
+
if (!roleRow)
|
|
146
|
+
return;
|
|
147
|
+
await this.whereScopeIn(db
|
|
148
|
+
.from('authz_assignments')
|
|
149
|
+
.where('holder_type', subject.type)
|
|
150
|
+
.where('holder_uuid', subject.uuid)
|
|
151
|
+
.where('role_uuid', roleRow.uuid), 'scope', [scope]).delete();
|
|
152
|
+
}
|
|
153
|
+
async hasRole(subject, role, scope) {
|
|
154
|
+
const chain = await this.chain(scope);
|
|
155
|
+
const found = await this.whereActive(this.whereScopeIn(db
|
|
156
|
+
.from('authz_assignments as a')
|
|
157
|
+
.join('authz_roles as r', 'r.uuid', 'a.role_uuid')
|
|
158
|
+
.where('r.slug', role)
|
|
159
|
+
.where('a.holder_type', subject.type)
|
|
160
|
+
.where('a.holder_uuid', subject.uuid), 'a.scope', chain), 'a.expires_at').first();
|
|
161
|
+
return Boolean(found);
|
|
162
|
+
}
|
|
163
|
+
async deny(subject, permission, scope) {
|
|
164
|
+
const perm = await this.findPermission(permission);
|
|
165
|
+
if (!perm) {
|
|
166
|
+
throw new Exception(`Permiso '${permission}' no existe en el catálogo`, { status: 422 });
|
|
167
|
+
}
|
|
168
|
+
const existing = await this.whereScopeIn(db
|
|
169
|
+
.from('authz_denies')
|
|
170
|
+
.where('holder_type', subject.type)
|
|
171
|
+
.where('holder_uuid', subject.uuid)
|
|
172
|
+
.where('permission_uuid', perm.uuid), 'scope', [scope]).first();
|
|
173
|
+
if (existing)
|
|
174
|
+
return;
|
|
175
|
+
try {
|
|
176
|
+
await db.table('authz_denies').insert({
|
|
177
|
+
uuid: uuidv7(),
|
|
178
|
+
holder_type: subject.type,
|
|
179
|
+
holder_uuid: subject.uuid,
|
|
180
|
+
permission_uuid: perm.uuid,
|
|
181
|
+
scope_type: scope.type,
|
|
182
|
+
scope_uuid: toDbScopeUuid(scope),
|
|
183
|
+
created_at: new Date(),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
// Carrera: si otro proceso insertó el mismo deny, el unique lo detecta
|
|
188
|
+
// y el resultado deseado ya existe.
|
|
189
|
+
const raced = await this.whereScopeIn(db
|
|
190
|
+
.from('authz_denies')
|
|
191
|
+
.where('holder_type', subject.type)
|
|
192
|
+
.where('holder_uuid', subject.uuid)
|
|
193
|
+
.where('permission_uuid', perm.uuid), 'scope', [scope]).first();
|
|
194
|
+
if (!raced)
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async removeDeny(subject, permission, scope) {
|
|
199
|
+
const perm = await this.findPermission(permission);
|
|
200
|
+
if (!perm)
|
|
201
|
+
return;
|
|
202
|
+
await this.whereScopeIn(db
|
|
203
|
+
.from('authz_denies')
|
|
204
|
+
.where('holder_type', subject.type)
|
|
205
|
+
.where('holder_uuid', subject.uuid)
|
|
206
|
+
.where('permission_uuid', perm.uuid), 'scope', [scope]).delete();
|
|
207
|
+
}
|
|
208
|
+
async listSubjects(role, scope) {
|
|
209
|
+
const rows = await this.whereActive(this.whereScopeIn(db
|
|
210
|
+
.from('authz_assignments as a')
|
|
211
|
+
.join('authz_roles as r', 'r.uuid', 'a.role_uuid')
|
|
212
|
+
.where('r.slug', role)
|
|
213
|
+
.where('r.scope_type', scope.type), 'a.scope', [scope]), 'a.expires_at').distinct('a.holder_type', 'a.holder_uuid');
|
|
214
|
+
return rows.map((row) => ({ type: row.holder_type, uuid: row.holder_uuid }));
|
|
215
|
+
}
|
|
216
|
+
async listRoles(subject, scope) {
|
|
217
|
+
const rows = await this.whereActive(this.whereScopeIn(db
|
|
218
|
+
.from('authz_assignments as a')
|
|
219
|
+
.join('authz_roles as r', 'r.uuid', 'a.role_uuid')
|
|
220
|
+
.where('a.holder_type', subject.type)
|
|
221
|
+
.where('a.holder_uuid', subject.uuid), 'a.scope', [scope]), 'a.expires_at').distinct('r.slug');
|
|
222
|
+
return rows.map((row) => row.slug);
|
|
223
|
+
}
|
|
224
|
+
async listRoleScopes(subject, scopeType) {
|
|
225
|
+
const rows = await this.whereActive(db
|
|
226
|
+
.from('authz_assignments as a')
|
|
227
|
+
.where('a.holder_type', subject.type)
|
|
228
|
+
.where('a.holder_uuid', subject.uuid)
|
|
229
|
+
.where('a.scope_type', scopeType), 'a.expires_at').distinct('a.scope_type', 'a.scope_uuid');
|
|
230
|
+
return rows.map((row) => ({ type: row.scope_type, uuid: fromDbScopeUuid(row.scope_uuid) }));
|
|
231
|
+
}
|
|
232
|
+
async listScopes(subject, permission) {
|
|
233
|
+
const perm = await this.findPermission(permission);
|
|
234
|
+
if (!perm)
|
|
235
|
+
return [];
|
|
236
|
+
const rows = await this.whereActive(db
|
|
237
|
+
.from('authz_assignments as a')
|
|
238
|
+
.join('authz_role_permissions as rp', 'rp.role_uuid', 'a.role_uuid')
|
|
239
|
+
.where('rp.permission_uuid', perm.uuid)
|
|
240
|
+
.where('a.holder_type', subject.type)
|
|
241
|
+
.where('a.holder_uuid', subject.uuid), 'a.expires_at').distinct('a.scope_type', 'a.scope_uuid');
|
|
242
|
+
const denies = await db
|
|
243
|
+
.from('authz_denies')
|
|
244
|
+
.where('holder_type', subject.type)
|
|
245
|
+
.where('holder_uuid', subject.uuid)
|
|
246
|
+
.where('permission_uuid', perm.uuid)
|
|
247
|
+
.select('scope_type', 'scope_uuid');
|
|
248
|
+
const deniedKeys = new Set(denies.map((d) => `${d.scope_type}:${fromDbScopeUuid(d.scope_uuid) ?? ''}`));
|
|
249
|
+
const result = [];
|
|
250
|
+
for (const row of rows) {
|
|
251
|
+
const candidate = { type: row.scope_type, uuid: fromDbScopeUuid(row.scope_uuid) };
|
|
252
|
+
const chain = await this.chain(candidate);
|
|
253
|
+
const blocked = chain.some((s) => deniedKeys.has(`${s.type}:${s.uuid ?? ''}`));
|
|
254
|
+
if (!blocked)
|
|
255
|
+
result.push(candidate);
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=database_driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database_driver.js","sourceRoot":"","sources":["../../../src/drivers/database_driver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAA;AAQnC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAKvC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,sCAAsC,CAAA;AAEvE,SAAS,aAAa,CAAC,KAAe;IACpC,OAAO,KAAK,CAAC,IAAI,IAAI,iBAAiB,CAAA;AACxC,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,OAAO,IAAI,KAAK,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;AACjD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,2BAA2B;IACtC;;;;OAIG;IACK,gBAAgB,CAAwB;IAEhD,YAAY,UAAyD,EAAE;QACrE,IAAI,CAAC,gBAAgB;YACnB,OAAO,CAAC,gBAAgB,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;IAC5F,CAAC;IAEO,KAAK,CAAC,KAAK,CAAC,KAAe;QACjC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACzD,CAAC;IAED,8EAA8E;IACtE,YAAY,CAAC,KAAmB,EAAE,MAAc,EAAE,MAAkB;QAC1E,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAC3B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;gBACvB,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;oBACtB,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,MAAM,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;gBACjF,CAAC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,kEAAkE;IAC1D,WAAW,CAAC,KAAmB,EAAE,SAAiB,YAAY;QACpE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAA;QAC5D,CAAC,CAAC,CAAA;IACJ,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,IAAY;QACvC,OAAO,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAA;IAChF,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,IAAY,EAAE,SAAiB;QAC1D,MAAM,IAAI,GAAG,MAAM,EAAE;aAClB,IAAI,CAAC,aAAa,CAAC;aACnB,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;aACnB,KAAK,CAAC,YAAY,EAAE,SAAS,CAAC;aAC9B,MAAM,CAAC,MAAM,CAAC;aACd,KAAK,EAAE,CAAA;QACV,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,SAAS,CAAC,QAAQ,IAAI,6CAA6C,SAAS,GAAG,EAAE;gBACzF,MAAM,EAAE,GAAG;aACZ,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAmB,EAAE,UAAkB,EAAE,KAAe;QACtE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAA;QAClD,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAA;QAEvB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAErC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CACpC,EAAE;aACC,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,EACtC,OAAO,EACP,KAAK,CACN,CAAC,KAAK,EAAE,CAAA;QACT,IAAI,MAAM;YAAE,OAAO,KAAK,CAAA;QAExB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CACpC,IAAI,CAAC,YAAY,CACf,EAAE;aACC,IAAI,CAAC,wBAAwB,CAAC;aAC9B,IAAI,CAAC,8BAA8B,EAAE,cAAc,EAAE,aAAa,CAAC;aACnE,KAAK,CAAC,oBAAoB,EAAE,IAAI,CAAC,IAAI,CAAC;aACtC,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC;aACpC,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,EACvC,SAAS,EACT,KAAK,CACN,EACD,cAAc,CACf,CAAC,KAAK,EAAE,CAAA;QAET,OAAO,OAAO,CAAC,OAAO,CAAC,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,KAAK,CACT,OAAmB,EACnB,IAAY,EACZ,KAAe,EACf,UAAwB,EAAE;QAE1B,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QACtE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAA;QAE3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CACtC,EAAE;aACC,IAAI,CAAC,mBAAmB,CAAC;aACzB,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,EAC/B,OAAO,EACP,CAAC,KAAK,CAAC,CACR,CAAC,KAAK,EAAE,CAAA;QAET,IAAI,QAAQ,EAAE,CAAC;YACb,uEAAuE;YACvE,mDAAmD;YACnD,MAAM,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;gBACrE,UAAU,EAAE,SAAS;aACtB,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC;gBACzC,IAAI,EAAE,MAAM,EAAE;gBACd,WAAW,EAAE,OAAO,CAAC,IAAI;gBACzB,WAAW,EAAE,OAAO,CAAC,IAAI;gBACzB,SAAS,EAAE,QAAQ;gBACnB,UAAU,EAAE,KAAK,CAAC,IAAI;gBACtB,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC;gBAChC,UAAU,EAAE,SAAS;gBACrB,UAAU,EAAE,IAAI,IAAI,EAAE;aACvB,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,uEAAuE;YACvE,0EAA0E;YAC1E,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CACnC,EAAE;iBACC,IAAI,CAAC,mBAAmB,CAAC;iBACzB,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;iBAClC,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;iBAClC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,EAC/B,OAAO,EACP,CAAC,KAAK,CAAC,CACR,CAAC,KAAK,EAAE,CAAA;YACT,IAAI,CAAC,KAAK;gBAAE,MAAM,KAAK,CAAA;YACvB,MAAM,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;gBAClE,UAAU,EAAE,SAAS;aACtB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAmB,EAAE,IAAY,EAAE,KAAe;QAC7D,MAAM,OAAO,GAAG,MAAM,EAAE;aACrB,IAAI,CAAC,aAAa,CAAC;aACnB,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;aACnB,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC;aAC/B,MAAM,CAAC,MAAM,CAAC;aACd,KAAK,EAAE,CAAA;QACV,IAAI,CAAC,OAAO;YAAE,OAAM;QAEpB,MAAM,IAAI,CAAC,YAAY,CACrB,EAAE;aACC,IAAI,CAAC,mBAAmB,CAAC;aACzB,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,EACnC,OAAO,EACP,CAAC,KAAK,CAAC,CACR,CAAC,MAAM,EAAE,CAAA;IACZ,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAmB,EAAE,IAAY,EAAE,KAAe;QAC9D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACrC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAClC,IAAI,CAAC,YAAY,CACf,EAAE;aACC,IAAI,CAAC,wBAAwB,CAAC;aAC9B,IAAI,CAAC,kBAAkB,EAAE,QAAQ,EAAE,aAAa,CAAC;aACjD,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC;aACrB,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC;aACpC,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,EACvC,SAAS,EACT,KAAK,CACN,EACD,cAAc,CACf,CAAC,KAAK,EAAE,CAAA;QACT,OAAO,OAAO,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAmB,EAAE,UAAkB,EAAE,KAAe;QACjE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAA;QAClD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,SAAS,CAAC,YAAY,UAAU,4BAA4B,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;QAC1F,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CACtC,EAAE;aACC,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,EACtC,OAAO,EACP,CAAC,KAAK,CAAC,CACR,CAAC,KAAK,EAAE,CAAA;QACT,IAAI,QAAQ;YAAE,OAAM;QAEpB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC;gBACpC,IAAI,EAAE,MAAM,EAAE;gBACd,WAAW,EAAE,OAAO,CAAC,IAAI;gBACzB,WAAW,EAAE,OAAO,CAAC,IAAI;gBACzB,eAAe,EAAE,IAAI,CAAC,IAAI;gBAC1B,UAAU,EAAE,KAAK,CAAC,IAAI;gBACtB,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC;gBAChC,UAAU,EAAE,IAAI,IAAI,EAAE;aACvB,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,uEAAuE;YACvE,oCAAoC;YACpC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CACnC,EAAE;iBACC,IAAI,CAAC,cAAc,CAAC;iBACpB,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;iBAClC,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;iBAClC,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,EACtC,OAAO,EACP,CAAC,KAAK,CAAC,CACR,CAAC,KAAK,EAAE,CAAA;YACT,IAAI,CAAC,KAAK;gBAAE,MAAM,KAAK,CAAA;QACzB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAmB,EAAE,UAAkB,EAAE,KAAe;QACvE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAA;QAClD,IAAI,CAAC,IAAI;YAAE,OAAM;QAEjB,MAAM,IAAI,CAAC,YAAY,CACrB,EAAE;aACC,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,EACtC,OAAO,EACP,CAAC,KAAK,CAAC,CACR,CAAC,MAAM,EAAE,CAAA;IACZ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAAY,EAAE,KAAe;QAC9C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CACjC,IAAI,CAAC,YAAY,CACf,EAAE;aACC,IAAI,CAAC,wBAAwB,CAAC;aAC9B,IAAI,CAAC,kBAAkB,EAAE,QAAQ,EAAE,aAAa,CAAC;aACjD,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC;aACrB,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,EACpC,SAAS,EACT,CAAC,KAAK,CAAC,CACR,EACD,cAAc,CACf,CAAC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC,CAAA;QAE5C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;IACnF,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAmB,EAAE,KAAe;QAClD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CACjC,IAAI,CAAC,YAAY,CACf,EAAE;aACC,IAAI,CAAC,wBAAwB,CAAC;aAC9B,IAAI,CAAC,kBAAkB,EAAE,QAAQ,EAAE,aAAa,CAAC;aACjD,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC;aACpC,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,EACvC,SAAS,EACT,CAAC,KAAK,CAAC,CACR,EACD,cAAc,CACf,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACpB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACzC,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAAmB,EAAE,SAAoB;QAC5D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CACjC,EAAE;aACC,IAAI,CAAC,wBAAwB,CAAC;aAC9B,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC;aACpC,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC;aACpC,KAAK,CAAC,cAAc,EAAE,SAAS,CAAC,EACnC,cAAc,CACf,CAAC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC,CAAA;QAC1C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;IAClG,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAmB,EAAE,UAAkB;QACtD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAA;QAClD,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAA;QAEpB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CACjC,EAAE;aACC,IAAI,CAAC,wBAAwB,CAAC;aAC9B,IAAI,CAAC,8BAA8B,EAAE,cAAc,EAAE,aAAa,CAAC;aACnE,KAAK,CAAC,oBAAoB,EAAE,IAAI,CAAC,IAAI,CAAC;aACtC,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC;aACpC,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,EACvC,cAAc,CACf,CAAC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC,CAAA;QAE1C,MAAM,MAAM,GAAG,MAAM,EAAE;aACpB,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;aAClC,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC;aACnC,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;QAErC,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,IAAI,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CACjF,CAAA;QAED,MAAM,MAAM,GAAe,EAAE,CAAA;QAC7B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,SAAS,GAAa,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAA;YAC3F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;YACzC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;YAC9E,IAAI,CAAC,OAAO;gBAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACtC,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { AuthorizationDriver, GrantOptions, ScopeAncestorsResolver, ScopeRef, ScopeType, SubjectRef } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Driver `openfga` — los HECHOS (asignaciones y denies) viven en un servidor
|
|
4
|
+
* OpenFGA; el CATÁLOGO (roles/permisos/vínculos) y la JERARQUÍA (orgs/units)
|
|
5
|
+
* siguen siendo metadata local en las tablas del chasis (split de propiedad
|
|
6
|
+
* de datos del análisis: cambiar de driver = migrar una tabla de hechos).
|
|
7
|
+
*
|
|
8
|
+
* Modelo FGA genérico (ver `openFgaAuthorizationModel()`):
|
|
9
|
+
* - `role_binding:<scopeKey>|<rol>` #assignee → asignación de rol
|
|
10
|
+
* - `deny_binding:<scopeKey>|<perm>` #denied → deny explícito
|
|
11
|
+
* - Expiración vía condition `not_expired` (valid_until en la tupla,
|
|
12
|
+
* current_time en cada check) — ni scheduler necesita.
|
|
13
|
+
*
|
|
14
|
+
* La herencia se resuelve igual que en el driver database: la cadena de
|
|
15
|
+
* scopes se calcula localmente (el árbol lo declara el consumidor vía
|
|
16
|
+
* `resolveAncestors`) y se consulta FGA por batchCheck sobre la cadena.
|
|
17
|
+
*
|
|
18
|
+
* NADA del dominio está cableado: los holders llegan como `holderTypes`
|
|
19
|
+
* (morph name → tipo FGA) y los niveles de scope se derivan del propio
|
|
20
|
+
* `ScopeRef`, así que un consumidor con otros guards u otra jerarquía solo
|
|
21
|
+
* cambia config.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Mapa morph name → tipo del modelo FGA (`users` → `user`). Debe ser el
|
|
25
|
+
* MISMO con el que se generó el authorization model del store.
|
|
26
|
+
*/
|
|
27
|
+
export type HolderTypeMap = Record<string, string>;
|
|
28
|
+
/**
|
|
29
|
+
* El authorization model en formato JSON del API de FGA, generado a partir
|
|
30
|
+
* de los holders del consumidor. El mismo mapa debe usarse al construir el
|
|
31
|
+
* driver: si difieren, los checks no encuentran las tuplas.
|
|
32
|
+
*/
|
|
33
|
+
export declare function openFgaAuthorizationModel(holderTypeMap: HolderTypeMap): any;
|
|
34
|
+
/**
|
|
35
|
+
* Crea un store nuevo + escribe el authorization model derivado de los
|
|
36
|
+
* holders del consumidor. Para bootstrap de un appliance o del harness de
|
|
37
|
+
* tests. El `name` lo decide el caller (el comando openfga:provision
|
|
38
|
+
* resuelve APP_NAME del entorno — el motor no lee env).
|
|
39
|
+
*/
|
|
40
|
+
export declare function provisionOpenFgaStore(apiUrl: string, name: string, holderTypeMap: HolderTypeMap): Promise<{
|
|
41
|
+
storeId: string;
|
|
42
|
+
modelId: string;
|
|
43
|
+
}>;
|
|
44
|
+
export interface OpenFgaDriverOptions {
|
|
45
|
+
apiUrl: string;
|
|
46
|
+
storeId: string;
|
|
47
|
+
/** Pin del model; si se omite, FGA usa el último. */
|
|
48
|
+
modelId?: string;
|
|
49
|
+
/** Jerarquía del consumidor (ver ScopeAncestorsResolver). */
|
|
50
|
+
resolveAncestors?: ScopeAncestorsResolver;
|
|
51
|
+
/**
|
|
52
|
+
* Holders del consumidor: morph name → tipo FGA. Debe coincidir con el
|
|
53
|
+
* mapa usado al escribir el authorization model del store.
|
|
54
|
+
*/
|
|
55
|
+
holderTypes: HolderTypeMap;
|
|
56
|
+
}
|
|
57
|
+
export interface ImportFactsResult {
|
|
58
|
+
assignments: number;
|
|
59
|
+
denies: number;
|
|
60
|
+
skippedExpired: number;
|
|
61
|
+
dryRun: boolean;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Migración de hechos database → openfga: copia las asignaciones vigentes y
|
|
65
|
+
* los denies de las tablas `authz_*` como tuples del store FGA.
|
|
66
|
+
*
|
|
67
|
+
* - COPIA, no mueve: las tablas locales quedan intactas → el rollback es
|
|
68
|
+
* volver a AUTHZ_DRIVER=database (solo se pierde lo escrito mientras se
|
|
69
|
+
* operó con openfga). El catálogo y la jerarquía nunca migran: son
|
|
70
|
+
* metadata local para ambos drivers.
|
|
71
|
+
* - Idempotente: re-ejecutar no duplica (onDuplicateWrites: Ignore).
|
|
72
|
+
* - Las asignaciones ya expiradas se saltan (no tiene sentido copiarlas);
|
|
73
|
+
* las de expiración futura viajan con la condition `not_expired`.
|
|
74
|
+
*/
|
|
75
|
+
export declare function importAuthzFactsToOpenFga(options: OpenFgaDriverOptions & {
|
|
76
|
+
dryRun?: boolean;
|
|
77
|
+
}): Promise<ImportFactsResult>;
|
|
78
|
+
export declare class OpenFgaAuthorizationDriver implements AuthorizationDriver {
|
|
79
|
+
private client;
|
|
80
|
+
private resolveAncestors;
|
|
81
|
+
private holderTypes;
|
|
82
|
+
constructor(options: OpenFgaDriverOptions);
|
|
83
|
+
private chain;
|
|
84
|
+
private fgaSubject;
|
|
85
|
+
/**
|
|
86
|
+
* batchCheck troceado al límite del servidor FGA (50 checks/request) y con
|
|
87
|
+
* verificación de completitud: TODOS los checks deben volver respondidos.
|
|
88
|
+
*/
|
|
89
|
+
private batchCheckAll;
|
|
90
|
+
private findPermission;
|
|
91
|
+
private findRoleOrFail;
|
|
92
|
+
/** Roles del catálogo que conceden el permiso, agrupados por scope_type. */
|
|
93
|
+
private rolesGranting;
|
|
94
|
+
authorize(subject: SubjectRef, permission: string, scope: ScopeRef): Promise<boolean>;
|
|
95
|
+
grant(subject: SubjectRef, role: string, scope: ScopeRef, options?: GrantOptions): Promise<void>;
|
|
96
|
+
revoke(subject: SubjectRef, role: string, scope: ScopeRef): Promise<void>;
|
|
97
|
+
hasRole(subject: SubjectRef, role: string, scope: ScopeRef): Promise<boolean>;
|
|
98
|
+
deny(subject: SubjectRef, permission: string, scope: ScopeRef): Promise<void>;
|
|
99
|
+
removeDeny(subject: SubjectRef, permission: string, scope: ScopeRef): Promise<void>;
|
|
100
|
+
listSubjects(role: string, scope: ScopeRef): Promise<SubjectRef[]>;
|
|
101
|
+
/** role_binding ids del subject (asignaciones directas vigentes). */
|
|
102
|
+
private listBindings;
|
|
103
|
+
listRoles(subject: SubjectRef, scope: ScopeRef): Promise<string[]>;
|
|
104
|
+
listRoleScopes(subject: SubjectRef, scopeType: ScopeType): Promise<ScopeRef[]>;
|
|
105
|
+
listScopes(subject: SubjectRef, permission: string): Promise<ScopeRef[]>;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=openfga_driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openfga_driver.d.ts","sourceRoot":"","sources":["../../../src/drivers/openfga_driver.ts"],"names":[],"mappings":"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"}
|