@seifer-webapp-factory/authorization 0.1.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/README.md +17 -0
- package/backend/templates/cache/ttl-cache.ts +41 -0
- package/backend/templates/config/config-fragment.ts +41 -0
- package/backend/templates/nestjs/authz.controller.ts +253 -0
- package/backend/templates/nestjs/authz.module.ts +158 -0
- package/backend/templates/nestjs/tokens.ts +41 -0
- package/backend/templates/persistence/migrations/0001_authz.sql +45 -0
- package/backend/templates/persistence/migrations/index.ts +84 -0
- package/backend/templates/persistence/pg-policy-store.ts +193 -0
- package/backend/templates/persistence/seed.ts +60 -0
- package/dist/backend/src/index.d.ts +10 -0
- package/dist/backend/src/index.d.ts.map +1 -0
- package/dist/backend/src/index.js +9 -0
- package/dist/backend/src/index.js.map +1 -0
- package/dist/backend/src/policy.d.ts +13 -0
- package/dist/backend/src/policy.d.ts.map +1 -0
- package/dist/backend/src/policy.js +49 -0
- package/dist/backend/src/policy.js.map +1 -0
- package/dist/backend/src/ports.d.ts +90 -0
- package/dist/backend/src/ports.d.ts.map +1 -0
- package/dist/backend/src/ports.js +2 -0
- package/dist/backend/src/ports.js.map +1 -0
- package/dist/backend/src/services.d.ts +81 -0
- package/dist/backend/src/services.d.ts.map +1 -0
- package/dist/backend/src/services.js +234 -0
- package/dist/backend/src/services.js.map +1 -0
- package/dist/contract/endpoints.d.ts +433 -0
- package/dist/contract/endpoints.d.ts.map +1 -0
- package/dist/contract/endpoints.js +57 -0
- package/dist/contract/endpoints.js.map +1 -0
- package/dist/contract/errors.d.ts +33 -0
- package/dist/contract/errors.d.ts.map +1 -0
- package/dist/contract/errors.js +51 -0
- package/dist/contract/errors.js.map +1 -0
- package/dist/contract/events.d.ts +50 -0
- package/dist/contract/events.d.ts.map +1 -0
- package/dist/contract/events.js +13 -0
- package/dist/contract/events.js.map +1 -0
- package/dist/contract/index.d.ts +10 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +10 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/contract/permissions.d.ts +35 -0
- package/dist/contract/permissions.d.ts.map +1 -0
- package/dist/contract/permissions.js +37 -0
- package/dist/contract/permissions.js.map +1 -0
- package/dist/contract/schemas.d.ts +288 -0
- package/dist/contract/schemas.d.ts.map +1 -0
- package/dist/contract/schemas.js +91 -0
- package/dist/contract/schemas.js.map +1 -0
- package/dist/frontend/src/client.d.ts +31 -0
- package/dist/frontend/src/client.d.ts.map +1 -0
- package/dist/frontend/src/client.js +83 -0
- package/dist/frontend/src/client.js.map +1 -0
- package/dist/frontend/src/composables.d.ts +62 -0
- package/dist/frontend/src/composables.d.ts.map +1 -0
- package/dist/frontend/src/composables.js +170 -0
- package/dist/frontend/src/composables.js.map +1 -0
- package/dist/frontend/src/guards.d.ts +12 -0
- package/dist/frontend/src/guards.d.ts.map +1 -0
- package/dist/frontend/src/guards.js +10 -0
- package/dist/frontend/src/guards.js.map +1 -0
- package/dist/frontend/src/index.d.ts +12 -0
- package/dist/frontend/src/index.d.ts.map +1 -0
- package/dist/frontend/src/index.js +9 -0
- package/dist/frontend/src/index.js.map +1 -0
- package/dist/manifest.d.ts +56 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +100 -0
- package/dist/manifest.js.map +1 -0
- package/dist/scaffolder/core/config.d.ts +86 -0
- package/dist/scaffolder/core/config.d.ts.map +1 -0
- package/dist/scaffolder/core/config.js +92 -0
- package/dist/scaffolder/core/config.js.map +1 -0
- package/dist/scaffolder/core/errors.d.ts +46 -0
- package/dist/scaffolder/core/errors.d.ts.map +1 -0
- package/dist/scaffolder/core/errors.js +60 -0
- package/dist/scaffolder/core/errors.js.map +1 -0
- package/dist/scaffolder/core/extend.d.ts +86 -0
- package/dist/scaffolder/core/extend.d.ts.map +1 -0
- package/dist/scaffolder/core/extend.js +94 -0
- package/dist/scaffolder/core/extend.js.map +1 -0
- package/dist/scaffolder/core/materialize.d.ts +71 -0
- package/dist/scaffolder/core/materialize.d.ts.map +1 -0
- package/dist/scaffolder/core/materialize.js +47 -0
- package/dist/scaffolder/core/materialize.js.map +1 -0
- package/dist/scaffolder/core/ports.d.ts +39 -0
- package/dist/scaffolder/core/ports.d.ts.map +1 -0
- package/dist/scaffolder/core/ports.js +33 -0
- package/dist/scaffolder/core/ports.js.map +1 -0
- package/dist/scaffolder/core/presence.d.ts +34 -0
- package/dist/scaffolder/core/presence.d.ts.map +1 -0
- package/dist/scaffolder/core/presence.js +29 -0
- package/dist/scaffolder/core/presence.js.map +1 -0
- package/dist/scaffolder/core/three-way-merge.d.ts +113 -0
- package/dist/scaffolder/core/three-way-merge.d.ts.map +1 -0
- package/dist/scaffolder/core/three-way-merge.js +184 -0
- package/dist/scaffolder/core/three-way-merge.js.map +1 -0
- package/dist/scaffolder/index.d.ts +25 -0
- package/dist/scaffolder/index.d.ts.map +1 -0
- package/dist/scaffolder/index.js +24 -0
- package/dist/scaffolder/index.js.map +1 -0
- package/frontend/templates/components/PermissionMatrix.vue +134 -0
- package/frontend/templates/i18n/en.json +61 -0
- package/frontend/templates/i18n/nl.json +61 -0
- package/frontend/templates/middleware/permission.ts +54 -0
- package/frontend/templates/pages/access-assignments.vue +151 -0
- package/frontend/templates/pages/role-editor.vue +169 -0
- package/frontend/templates/pages/roles-list.vue +84 -0
- package/frontend/templates/plugins/authz.client.ts +108 -0
- package/frontend/templates/runtime.ts +60 -0
- package/package.json +76 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* US-Z0601 — Postgres-backed {@link PolicyStore} bovenop de persistence-kit-{@link Pool}. De store
|
|
3
|
+
* bevat GEEN policy-logica (default-deny, escalatie, cyclusdetectie): dat zit in de kit + services. Hier
|
|
4
|
+
* enkel CRUD over de `authz_*`-tabellen. Rol-permissies staan genormaliseerd in `authz_role_permissions`
|
|
5
|
+
* en worden per rol via `array_agg` geaggregeerd tot `StoredRole.permissions`.
|
|
6
|
+
*/
|
|
7
|
+
import type { Pool, Row } from '@seifer-webapp-factory/kits/backend/persistence';
|
|
8
|
+
import type { RelationEdge } from '@seifer-webapp-factory/kits/backend/access-control';
|
|
9
|
+
import type {
|
|
10
|
+
CreateRoleInput,
|
|
11
|
+
PolicyStore,
|
|
12
|
+
StoredRelation,
|
|
13
|
+
StoredRole,
|
|
14
|
+
UpdateRolePatch,
|
|
15
|
+
} from '../../src/index.js';
|
|
16
|
+
|
|
17
|
+
/** Rij-vorm van een rol inclusief geaggregeerde permissie-sleutels. */
|
|
18
|
+
type RoleRow = Row & {
|
|
19
|
+
id: string;
|
|
20
|
+
key: string;
|
|
21
|
+
name: string;
|
|
22
|
+
parentRoleId: string | null;
|
|
23
|
+
permissions: string[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type RelationRow = Row & { from: string; relation: string; to: string };
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Selecteert rollen mét hun permissies (LEFT JOIN + array_agg). `array_remove(..., NULL)` zorgt dat
|
|
30
|
+
* een rol zonder permissies een lege array `{}` oplevert i.p.v. `{NULL}`.
|
|
31
|
+
*/
|
|
32
|
+
const ROLE_SELECT = `
|
|
33
|
+
SELECT r.id,
|
|
34
|
+
r.key,
|
|
35
|
+
r.name,
|
|
36
|
+
r.parent_role_id AS "parentRoleId",
|
|
37
|
+
COALESCE(array_remove(array_agg(rp.permission_key), NULL), '{}') AS permissions
|
|
38
|
+
FROM authz_roles r
|
|
39
|
+
LEFT JOIN authz_role_permissions rp ON rp.role_id = r.id
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
function toStoredRole(r: RoleRow): StoredRole {
|
|
43
|
+
return {
|
|
44
|
+
id: r.id,
|
|
45
|
+
key: r.key,
|
|
46
|
+
name: r.name,
|
|
47
|
+
permissions: r.permissions,
|
|
48
|
+
parentRoleId: r.parentRoleId,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function pgPolicyStore(pool: Pool): PolicyStore {
|
|
53
|
+
/** Vervangt de permissie-rijen van een rol door de opgegeven set (idempotent per sleutel). */
|
|
54
|
+
async function replacePermissions(roleId: string, permissions: string[]): Promise<void> {
|
|
55
|
+
await pool.execute('DELETE FROM authz_role_permissions WHERE role_id = $1', [roleId]);
|
|
56
|
+
for (const key of permissions) {
|
|
57
|
+
// Zorg dat de permissie-sleutel in de catalogus-tabel bestaat (US-Z0203 sync), dan koppel de rol.
|
|
58
|
+
await pool.execute(
|
|
59
|
+
'INSERT INTO authz_permissions (key, description) VALUES ($1, $1) ON CONFLICT (key) DO NOTHING',
|
|
60
|
+
[key],
|
|
61
|
+
);
|
|
62
|
+
await pool.execute(
|
|
63
|
+
`INSERT INTO authz_role_permissions (role_id, permission_key)
|
|
64
|
+
VALUES ($1, $2) ON CONFLICT (role_id, permission_key) DO NOTHING`,
|
|
65
|
+
[roleId, key],
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function getById(id: string): Promise<StoredRole | null> {
|
|
71
|
+
const { rows } = await pool.execute<RoleRow>(`${ROLE_SELECT} WHERE r.id = $1 GROUP BY r.id`, [id]);
|
|
72
|
+
return rows[0] ? toStoredRole(rows[0]) : null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
async listRoles(): Promise<StoredRole[]> {
|
|
77
|
+
const { rows } = await pool.execute<RoleRow>(`${ROLE_SELECT} GROUP BY r.id ORDER BY r.key`);
|
|
78
|
+
return rows.map(toStoredRole);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
getRole(id: string): Promise<StoredRole | null> {
|
|
82
|
+
return getById(id);
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
async getRoleByKey(key: string): Promise<StoredRole | null> {
|
|
86
|
+
const { rows } = await pool.execute<RoleRow>(`${ROLE_SELECT} WHERE r.key = $1 GROUP BY r.id`, [key]);
|
|
87
|
+
return rows[0] ? toStoredRole(rows[0]) : null;
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
async createRole(input: CreateRoleInput): Promise<StoredRole> {
|
|
91
|
+
// De store kent de id toe (gen_random_uuid, PG13+); de app levert geen id mee.
|
|
92
|
+
const { rows } = await pool.execute<Row & { id: string }>(
|
|
93
|
+
`INSERT INTO authz_roles (id, key, name, parent_role_id)
|
|
94
|
+
VALUES (gen_random_uuid()::text, $1, $2, $3)
|
|
95
|
+
RETURNING id`,
|
|
96
|
+
[input.key, input.name, input.parentRoleId],
|
|
97
|
+
);
|
|
98
|
+
const id = rows[0]!.id;
|
|
99
|
+
await replacePermissions(id, input.permissions);
|
|
100
|
+
const created = await getById(id);
|
|
101
|
+
return created!;
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
async updateRole(id: string, patch: UpdateRolePatch): Promise<StoredRole> {
|
|
105
|
+
// COALESCE laat afwezige velden ongemoeid; de CASE-vlag onderscheidt "niet gewijzigd" van "→ null".
|
|
106
|
+
if (patch.name !== undefined || patch.parentRoleId !== undefined) {
|
|
107
|
+
await pool.execute(
|
|
108
|
+
`UPDATE authz_roles SET
|
|
109
|
+
name = COALESCE($2, name),
|
|
110
|
+
parent_role_id = CASE WHEN $3 THEN $4 ELSE parent_role_id END
|
|
111
|
+
WHERE id = $1`,
|
|
112
|
+
[id, patch.name ?? null, patch.parentRoleId !== undefined, patch.parentRoleId ?? null],
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (patch.permissions !== undefined) {
|
|
116
|
+
await replacePermissions(id, patch.permissions);
|
|
117
|
+
}
|
|
118
|
+
const updated = await getById(id);
|
|
119
|
+
return updated!;
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
async deleteRole(id: string): Promise<void> {
|
|
123
|
+
// Verwijder afhankelijke rijen eerst zodat er geen wees-koppelingen achterblijven.
|
|
124
|
+
await pool.execute('DELETE FROM authz_role_assignments WHERE role_id = $1', [id]);
|
|
125
|
+
await pool.execute('DELETE FROM authz_role_permissions WHERE role_id = $1', [id]);
|
|
126
|
+
await pool.execute('UPDATE authz_roles SET parent_role_id = NULL WHERE parent_role_id = $1', [id]);
|
|
127
|
+
await pool.execute('DELETE FROM authz_roles WHERE id = $1', [id]);
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
async rolesForSubject(subjectId: string): Promise<StoredRole[]> {
|
|
131
|
+
const { rows } = await pool.execute<RoleRow>(
|
|
132
|
+
`SELECT r.id,
|
|
133
|
+
r.key,
|
|
134
|
+
r.name,
|
|
135
|
+
r.parent_role_id AS "parentRoleId",
|
|
136
|
+
COALESCE(array_remove(array_agg(rp.permission_key), NULL), '{}') AS permissions
|
|
137
|
+
FROM authz_roles r
|
|
138
|
+
JOIN authz_role_assignments a ON a.role_id = r.id AND a.subject_id = $1
|
|
139
|
+
LEFT JOIN authz_role_permissions rp ON rp.role_id = r.id
|
|
140
|
+
GROUP BY r.id
|
|
141
|
+
ORDER BY r.key`,
|
|
142
|
+
[subjectId],
|
|
143
|
+
);
|
|
144
|
+
return rows.map(toStoredRole);
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
async assignRole(subjectId: string, roleId: string): Promise<boolean> {
|
|
148
|
+
// Idempotent: bij een bestaande toewijzing verandert er niets → rowCount 0 → `false`.
|
|
149
|
+
const { rowCount } = await pool.execute(
|
|
150
|
+
`INSERT INTO authz_role_assignments (subject_id, role_id, scope, granted_at, granted_by)
|
|
151
|
+
VALUES ($1, $2, NULL, now(), $1)
|
|
152
|
+
ON CONFLICT (subject_id, role_id) DO NOTHING`,
|
|
153
|
+
[subjectId, roleId],
|
|
154
|
+
);
|
|
155
|
+
return rowCount > 0;
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
async revokeRole(subjectId: string, roleId: string): Promise<boolean> {
|
|
159
|
+
const { rowCount } = await pool.execute(
|
|
160
|
+
'DELETE FROM authz_role_assignments WHERE subject_id = $1 AND role_id = $2',
|
|
161
|
+
[subjectId, roleId],
|
|
162
|
+
);
|
|
163
|
+
return rowCount > 0;
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
async writeRelation(relation: StoredRelation): Promise<void> {
|
|
167
|
+
await pool.execute(
|
|
168
|
+
`INSERT INTO authz_relations (subject_id, relation, object_type, object_id)
|
|
169
|
+
VALUES ($1, $2, $3, $4)
|
|
170
|
+
ON CONFLICT (subject_id, relation, object_type, object_id) DO NOTHING`,
|
|
171
|
+
[relation.subjectId, relation.relation, relation.objectType, relation.objectId],
|
|
172
|
+
);
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
async removeRelation(relation: StoredRelation): Promise<void> {
|
|
176
|
+
await pool.execute(
|
|
177
|
+
`DELETE FROM authz_relations
|
|
178
|
+
WHERE subject_id = $1 AND relation = $2 AND object_type = $3 AND object_id = $4`,
|
|
179
|
+
[relation.subjectId, relation.relation, relation.objectType, relation.objectId],
|
|
180
|
+
);
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
async relationsFrom(node: string): Promise<RelationEdge[]> {
|
|
184
|
+
const { rows } = await pool.execute<RelationRow>(
|
|
185
|
+
`SELECT subject_id AS "from", relation, object_id AS "to"
|
|
186
|
+
FROM authz_relations
|
|
187
|
+
WHERE subject_id = $1`,
|
|
188
|
+
[node],
|
|
189
|
+
);
|
|
190
|
+
return rows.map((r) => ({ from: r.from, relation: r.relation, to: r.to }));
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* US-Z0702 — Bootstrap-seed. Legt de default-rollen aan en borgt dat er precies één beheer-rol met
|
|
3
|
+
* `authz.manage` bestaat die aan de first-admin wordt toegewezen. Zonder deze bootstrap zou geen enkele
|
|
4
|
+
* mutatie mogelijk zijn (de beheer-endpoints vereisen `authz.manage`) — management mag nooit
|
|
5
|
+
* onbereikbaar zijn. De seed is idempotent: bestaande rollen/toewijzingen worden niet gedupliceerd.
|
|
6
|
+
*/
|
|
7
|
+
import type { PolicyStore } from '../../src/index.js';
|
|
8
|
+
import { AUTHZ_MANAGE } from '../../../contract/index.js';
|
|
9
|
+
|
|
10
|
+
/** Een default-rol zoals de host die in de config declareert. */
|
|
11
|
+
export interface DefaultRoleSeed {
|
|
12
|
+
key: string;
|
|
13
|
+
name: string;
|
|
14
|
+
permissions: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface SeedDefaultsOptions {
|
|
18
|
+
/** De rollen die bij een verse installatie moeten bestaan (uit de config, US-Z0603). */
|
|
19
|
+
defaultRoles: DefaultRoleSeed[];
|
|
20
|
+
/** Het subject dat de eerste beheer-rol krijgt (bootstrap, US-Z0702). */
|
|
21
|
+
firstAdminSubjectId: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Zet de default-rollen klaar en wijst een beheer-rol toe aan de first-admin. */
|
|
25
|
+
export async function seedDefaults(store: PolicyStore, opts: SeedDefaultsOptions): Promise<void> {
|
|
26
|
+
// 1) Maak elke default-rol aan die nog niet bestaat (idempotent op `key`).
|
|
27
|
+
for (const def of opts.defaultRoles) {
|
|
28
|
+
const existing = await store.getRoleByKey(def.key);
|
|
29
|
+
if (existing === null) {
|
|
30
|
+
await store.createRole({
|
|
31
|
+
key: def.key,
|
|
32
|
+
name: def.name,
|
|
33
|
+
permissions: def.permissions,
|
|
34
|
+
parentRoleId: null,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 2) Borg een beheer-rol met `authz.manage`. Bestaat er al één (via de defaults), gebruik die;
|
|
40
|
+
// anders promoveer/creëer een `admin`-rol zodat de bootstrap nooit zonder beheer-rol eindigt.
|
|
41
|
+
const roles = await store.listRoles();
|
|
42
|
+
let adminRole = roles.find((r) => r.permissions.includes(AUTHZ_MANAGE)) ?? null;
|
|
43
|
+
if (adminRole === null) {
|
|
44
|
+
const byKey = await store.getRoleByKey('admin');
|
|
45
|
+
adminRole =
|
|
46
|
+
byKey !== null
|
|
47
|
+
? await store.updateRole(byKey.id, {
|
|
48
|
+
permissions: [...new Set([...byKey.permissions, AUTHZ_MANAGE])],
|
|
49
|
+
})
|
|
50
|
+
: await store.createRole({
|
|
51
|
+
key: 'admin',
|
|
52
|
+
name: 'Beheerder',
|
|
53
|
+
permissions: [AUTHZ_MANAGE],
|
|
54
|
+
parentRoleId: null,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 3) Wijs de beheer-rol toe aan de first-admin (idempotent: assignRole geeft `false` als het al bestond).
|
|
59
|
+
await store.assignRole(opts.firstAdminSubjectId, adminRole.id);
|
|
60
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* authorization — backend mechanisme (pinned dependency). Flow-services + poorten die de
|
|
3
|
+
* `access-control`-kit orkestreren. De HTTP-laag, pg-adapters, migraties en seed zijn materialiseerbare
|
|
4
|
+
* surface (backend/templates), geen onderdeel van dit mechanisme.
|
|
5
|
+
*/
|
|
6
|
+
export * from './ports.js';
|
|
7
|
+
export { RoleService, AssignmentService, PermissionResolver, AuthorizationPdp, RelationService } from './services.js';
|
|
8
|
+
export type { Actor } from './services.js';
|
|
9
|
+
export { buildRbac, effectivePermissions, toRbacDefinition } from './policy.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../backend/src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACtH,YAAY,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* authorization — backend mechanisme (pinned dependency). Flow-services + poorten die de
|
|
3
|
+
* `access-control`-kit orkestreren. De HTTP-laag, pg-adapters, migraties en seed zijn materialiseerbare
|
|
4
|
+
* surface (backend/templates), geen onderdeel van dit mechanisme.
|
|
5
|
+
*/
|
|
6
|
+
export * from './ports.js';
|
|
7
|
+
export { RoleService, AssignmentService, PermissionResolver, AuthorizationPdp, RelationService } from './services.js';
|
|
8
|
+
export { buildRbac, effectivePermissions, toRbacDefinition } from './policy.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../backend/src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEtH,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Rbac, RbacDefinition } from '@seifer-webapp-factory/kits/backend/access-control';
|
|
2
|
+
import type { StoredRole } from './ports.js';
|
|
3
|
+
/** Zet opgeslagen rollen om naar een kit-RBAC-definitie (key = rol-naam, parent → `includes`). */
|
|
4
|
+
export declare function toRbacDefinition(roles: StoredRole[]): RbacDefinition;
|
|
5
|
+
/**
|
|
6
|
+
* Bouwt een {@link Rbac} en vertaalt kit-fouten naar contract-fouten: een cyclische hiërarchie →
|
|
7
|
+
* `role_cycle`, een dangling parent → `permission_unknown`-achtige `role_not_found`. Fail-fast, zodat
|
|
8
|
+
* een ongeldige hiërarchie nooit als geldig model wordt geladen.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildRbac(roles: StoredRole[]): Rbac;
|
|
11
|
+
/** Effectieve permissies (incl. geërfde via hiërarchie) voor een set rol-sleutels. */
|
|
12
|
+
export declare function effectivePermissions(roles: StoredRole[], roleKeys: string[]): Set<string>;
|
|
13
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../backend/src/policy.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAkB,MAAM,oDAAoD,CAAC;AAE/G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,kGAAkG;AAClG,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,cAAc,CAapE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,CAQnD;AAED,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAOzF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interne policy-helper: bouwt het kit-RBAC-model uit opgeslagen rollen en lost effectieve permissies
|
|
3
|
+
* op. Voegt GEEN mechanisme toe — het composeert `createRbac` (US-0501) van de access-control-kit. De
|
|
4
|
+
* kit detecteert cycli en onbekende rollen fail-fast; hier vertalen we die naar contract-foutcodes.
|
|
5
|
+
*/
|
|
6
|
+
import { createRbac, RoleCycleError, UnknownRoleError } from '@seifer-webapp-factory/kits/backend/access-control';
|
|
7
|
+
import { AuthzError } from '../../contract/index.js';
|
|
8
|
+
/** Zet opgeslagen rollen om naar een kit-RBAC-definitie (key = rol-naam, parent → `includes`). */
|
|
9
|
+
export function toRbacDefinition(roles) {
|
|
10
|
+
const keyById = new Map();
|
|
11
|
+
for (const role of roles)
|
|
12
|
+
keyById.set(role.id, role.key);
|
|
13
|
+
const definitions = roles.map((role) => {
|
|
14
|
+
const parentKey = role.parentRoleId === null ? undefined : keyById.get(role.parentRoleId);
|
|
15
|
+
return {
|
|
16
|
+
name: role.key,
|
|
17
|
+
permissions: role.permissions,
|
|
18
|
+
includes: parentKey ? [parentKey] : [],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
return { roles: definitions };
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Bouwt een {@link Rbac} en vertaalt kit-fouten naar contract-fouten: een cyclische hiërarchie →
|
|
25
|
+
* `role_cycle`, een dangling parent → `permission_unknown`-achtige `role_not_found`. Fail-fast, zodat
|
|
26
|
+
* een ongeldige hiërarchie nooit als geldig model wordt geladen.
|
|
27
|
+
*/
|
|
28
|
+
export function buildRbac(roles) {
|
|
29
|
+
try {
|
|
30
|
+
return createRbac(toRbacDefinition(roles));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error instanceof RoleCycleError)
|
|
34
|
+
throw new AuthzError('role_cycle', 'cyclische rol-hiërarchie');
|
|
35
|
+
if (error instanceof UnknownRoleError)
|
|
36
|
+
throw new AuthzError('role_not_found', 'onbekende bovenliggende rol');
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Effectieve permissies (incl. geërfde via hiërarchie) voor een set rol-sleutels. */
|
|
41
|
+
export function effectivePermissions(roles, roleKeys) {
|
|
42
|
+
const rbac = buildRbac(roles);
|
|
43
|
+
const known = new Set(rbac.roleNames);
|
|
44
|
+
// Onbekende rol-sleutels stil overslaan i.p.v. crashen: een subject met een verwijderde rol houdt
|
|
45
|
+
// simpelweg minder permissies over (fail-closed, geen impliciete toegang).
|
|
46
|
+
const present = roleKeys.filter((key) => known.has(key));
|
|
47
|
+
return rbac.resolve(present);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../backend/src/policy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,oDAAoD,CAAC;AAElH,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAGrD,kGAAkG;AAClG,MAAM,UAAU,gBAAgB,CAAC,KAAmB;IAClD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAEzD,MAAM,WAAW,GAAqB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACvD,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC1F,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,GAAG;YACd,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE;SACvC,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAAmB;IAC3C,IAAI,CAAC;QACH,OAAO,UAAU,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,cAAc;YAAE,MAAM,IAAI,UAAU,CAAC,YAAY,EAAE,0BAA0B,CAAC,CAAC;QACpG,IAAI,KAAK,YAAY,gBAAgB;YAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,6BAA6B,CAAC,CAAC;QAC7G,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAAC,KAAmB,EAAE,QAAkB;IAC1E,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtC,kGAAkG;IAClG,2EAA2E;IAC3E,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Requires-ports die de host injecteert (US-Z0601/Z0602). De mechanisme-services zijn puur: geen HTTP,
|
|
3
|
+
* geen SQL van zichzelf — ze krijgen deze poorten via de constructor. De default-adapters (pg) leven
|
|
4
|
+
* als materialiseerbare surface (backend/templates), niet hier.
|
|
5
|
+
*/
|
|
6
|
+
import type { RelationEdge } from '@seifer-webapp-factory/kits/backend/access-control';
|
|
7
|
+
/** Een opgeslagen rol (US-Z0201). `parentRoleId` draagt de rol-hiërarchie (US-Z0202). */
|
|
8
|
+
export interface StoredRole {
|
|
9
|
+
id: string;
|
|
10
|
+
key: string;
|
|
11
|
+
name: string;
|
|
12
|
+
permissions: string[];
|
|
13
|
+
parentRoleId: string | null;
|
|
14
|
+
}
|
|
15
|
+
export interface CreateRoleInput {
|
|
16
|
+
key: string;
|
|
17
|
+
name: string;
|
|
18
|
+
permissions: string[];
|
|
19
|
+
parentRoleId: string | null;
|
|
20
|
+
}
|
|
21
|
+
export interface UpdateRolePatch {
|
|
22
|
+
name?: string;
|
|
23
|
+
permissions?: string[];
|
|
24
|
+
parentRoleId?: string | null;
|
|
25
|
+
}
|
|
26
|
+
/** ReBAC-tuple (US-Z0501) — subject staat via `relation` tot een object. */
|
|
27
|
+
export interface StoredRelation {
|
|
28
|
+
subjectId: string;
|
|
29
|
+
relation: string;
|
|
30
|
+
objectType: string;
|
|
31
|
+
objectId: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* US-Z0601 — De policy-store: rollen, rol↔permissie, rol-toewijzingen en (optioneel) ReBAC-relaties.
|
|
35
|
+
* De default-adapter draait over `persistence`; een host kan naar een bestaand schema wijzen. De store
|
|
36
|
+
* bevat GEEN policy-logica (default-deny, escalatie, cyclus) — die zit in de kit + services.
|
|
37
|
+
*/
|
|
38
|
+
export interface PolicyStore {
|
|
39
|
+
listRoles(): Promise<StoredRole[]>;
|
|
40
|
+
getRole(id: string): Promise<StoredRole | null>;
|
|
41
|
+
getRoleByKey(key: string): Promise<StoredRole | null>;
|
|
42
|
+
createRole(input: CreateRoleInput): Promise<StoredRole>;
|
|
43
|
+
updateRole(id: string, patch: UpdateRolePatch): Promise<StoredRole>;
|
|
44
|
+
deleteRole(id: string): Promise<void>;
|
|
45
|
+
/** Rollen die aan een subject zijn toegewezen (US-Z0301/Z0305). */
|
|
46
|
+
rolesForSubject(subjectId: string): Promise<StoredRole[]>;
|
|
47
|
+
/** Wijst een rol toe; geeft `false` als de toewijzing al bestond (idempotent, geen dubbel). */
|
|
48
|
+
assignRole(subjectId: string, roleId: string): Promise<boolean>;
|
|
49
|
+
/** Trekt een rol in; geeft `false` als er niets was om in te trekken (idempotent). */
|
|
50
|
+
revokeRole(subjectId: string, roleId: string): Promise<boolean>;
|
|
51
|
+
/** ReBAC (US-Z0501) — alleen gebruikt wanneer `model: 'rbac+rebac'`. */
|
|
52
|
+
writeRelation(relation: StoredRelation): Promise<void>;
|
|
53
|
+
removeRelation(relation: StoredRelation): Promise<void>;
|
|
54
|
+
/** Directe relatie-edges vanaf een node, voor de kit-`RebacChecker` (US-Z0502). */
|
|
55
|
+
relationsFrom(node: string): Promise<RelationEdge[]>;
|
|
56
|
+
}
|
|
57
|
+
/** Het geauthenticeerde subject (identiteit) — de module→module-seam met authentication (US-Z0602). */
|
|
58
|
+
export interface AuthzSubjectIdentity {
|
|
59
|
+
id: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* US-Z0602 — Leest het geauthenticeerde subject uit de sessie/context (het `Subject` dat de
|
|
63
|
+
* authentication-module plaatst). De host injecteert dit; `null` = geen geauthenticeerd subject
|
|
64
|
+
* (leidt tot default-deny / `unauthenticated`). `subjectId` is bewust GEEN harde cross-module-FK.
|
|
65
|
+
*/
|
|
66
|
+
export interface SubjectProvider<Ctx = unknown> {
|
|
67
|
+
current(context: Ctx): Promise<AuthzSubjectIdentity | null>;
|
|
68
|
+
}
|
|
69
|
+
/** Opgeloste effectieve permissies + rollen van een subject (US-Z0401). */
|
|
70
|
+
export interface ResolvedAccess {
|
|
71
|
+
subjectId: string;
|
|
72
|
+
roleKeys: string[];
|
|
73
|
+
permissions: string[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* US-Z0402 — Short-TTL cache van opgeloste permissies. De resolver invalideert expliciet bij elke
|
|
77
|
+
* mutatie (grant/revoke/role-change) zodat een revoke prompt doorwerkt (geen stale grants).
|
|
78
|
+
*/
|
|
79
|
+
export interface PermissionCache {
|
|
80
|
+
get(subjectId: string): Promise<ResolvedAccess | null>;
|
|
81
|
+
set(subjectId: string, value: ResolvedAccess): Promise<void>;
|
|
82
|
+
invalidate(subjectId: string): Promise<void>;
|
|
83
|
+
/** Volledige leegmaak — gebruikt bij een role-change die iedereen kan raken. */
|
|
84
|
+
clear(): Promise<void>;
|
|
85
|
+
}
|
|
86
|
+
/** Klok-poort zodat services deterministisch te testen zijn (event-timestamps, US-Z0103). */
|
|
87
|
+
export interface Clock {
|
|
88
|
+
now(): Date;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../../backend/src/ports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ports.js","sourceRoot":"","sources":["../../../backend/src/ports.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type AuthzEventSink, type CheckRequest, type CheckResponse, type PermissionCatalog, type Role } from '../../contract/index.js';
|
|
2
|
+
import type { Clock, CreateRoleInput, PermissionCache, PolicyStore, ResolvedAccess, UpdateRolePatch } from './ports.js';
|
|
3
|
+
/** Actor-context: wie voert de mutatie uit en welke effectieve permissies heeft die (escalatie-guard). */
|
|
4
|
+
export interface Actor {
|
|
5
|
+
id: string;
|
|
6
|
+
permissions: ReadonlySet<string>;
|
|
7
|
+
}
|
|
8
|
+
interface RoleDeps {
|
|
9
|
+
store: PolicyStore;
|
|
10
|
+
catalog: PermissionCatalog;
|
|
11
|
+
events: AuthzEventSink;
|
|
12
|
+
clock: Clock;
|
|
13
|
+
}
|
|
14
|
+
/** US-Z0201/0202/0203 — rollenbeheer (CRUD + hiërarchie + catalogus-sync). */
|
|
15
|
+
export declare class RoleService {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(deps: RoleDeps);
|
|
18
|
+
list(): Promise<Role[]>;
|
|
19
|
+
create(actor: Actor, input: CreateRoleInput): Promise<Role>;
|
|
20
|
+
update(actor: Actor, id: string, patch: UpdateRolePatch): Promise<Role>;
|
|
21
|
+
remove(actor: Actor, id: string): Promise<void>;
|
|
22
|
+
/** US-Z0203 — de code-declared catalogus is de bron; management vereist `authz.manage` (surface-guard). */
|
|
23
|
+
permissions(): PermissionCatalog;
|
|
24
|
+
}
|
|
25
|
+
interface AssignDeps {
|
|
26
|
+
store: PolicyStore;
|
|
27
|
+
cache: PermissionCache;
|
|
28
|
+
events: AuthzEventSink;
|
|
29
|
+
clock: Clock;
|
|
30
|
+
}
|
|
31
|
+
/** US-Z0301/0302/0303 — rol-toewijzing met escalation- en self-lockout-guards. */
|
|
32
|
+
export declare class AssignmentService {
|
|
33
|
+
#private;
|
|
34
|
+
constructor(deps: AssignDeps);
|
|
35
|
+
subjectRoles(subjectId: string): Promise<Role[]>;
|
|
36
|
+
assign(actor: Actor, subjectId: string, roleId: string): Promise<void>;
|
|
37
|
+
revoke(actor: Actor, subjectId: string, roleId: string): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
/** US-Z0401/0402 — resolveert een subject naar effectieve permissies, met cache + invalidatie. */
|
|
40
|
+
export declare class PermissionResolver {
|
|
41
|
+
#private;
|
|
42
|
+
constructor(deps: {
|
|
43
|
+
store: PolicyStore;
|
|
44
|
+
cache: PermissionCache;
|
|
45
|
+
});
|
|
46
|
+
resolve(subjectId: string): Promise<ResolvedAccess>;
|
|
47
|
+
has(subjectId: string, permission: string): Promise<boolean>;
|
|
48
|
+
}
|
|
49
|
+
/** US-Z0403 — Policy Decision Point: default-deny beslissing + veilige reden voor /authz/check. */
|
|
50
|
+
export declare class AuthorizationPdp {
|
|
51
|
+
#private;
|
|
52
|
+
constructor(deps: {
|
|
53
|
+
resolver: PermissionResolver;
|
|
54
|
+
store: PolicyStore;
|
|
55
|
+
rebacEnabled: boolean;
|
|
56
|
+
});
|
|
57
|
+
check(subjectId: string, request: CheckRequest): Promise<CheckResponse>;
|
|
58
|
+
}
|
|
59
|
+
interface RelationDeps {
|
|
60
|
+
store: PolicyStore;
|
|
61
|
+
rebacEnabled: boolean;
|
|
62
|
+
}
|
|
63
|
+
/** US-Z0501 — ReBAC-relatietuples schrijven/verwijderen (achter config-toggle). */
|
|
64
|
+
export declare class RelationService {
|
|
65
|
+
#private;
|
|
66
|
+
constructor(deps: RelationDeps);
|
|
67
|
+
write(relation: {
|
|
68
|
+
subjectId: string;
|
|
69
|
+
relation: string;
|
|
70
|
+
objectType: string;
|
|
71
|
+
objectId: string;
|
|
72
|
+
}): Promise<void>;
|
|
73
|
+
remove(relation: {
|
|
74
|
+
subjectId: string;
|
|
75
|
+
relation: string;
|
|
76
|
+
objectType: string;
|
|
77
|
+
objectId: string;
|
|
78
|
+
}): Promise<void>;
|
|
79
|
+
}
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=services.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../../backend/src/services.ts"],"names":[],"mappings":"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"}
|