@authup/server-core 1.0.0-beta.50 → 1.0.0-beta.51
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/adapters/database/domains/client-permission/entity.d.ts +2 -1
- package/dist/adapters/database/domains/client-permission/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/client-permission/entity.mjs +6 -0
- package/dist/adapters/database/domains/client-permission/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/robot-permission/entity.d.ts +2 -1
- package/dist/adapters/database/domains/robot-permission/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/robot-permission/entity.mjs +6 -0
- package/dist/adapters/database/domains/robot-permission/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/robot-role/entity.mjs +1 -1
- package/dist/adapters/database/domains/robot-role/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/role-permission/entity.d.ts +2 -1
- package/dist/adapters/database/domains/role-permission/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/role-permission/entity.mjs +6 -0
- package/dist/adapters/database/domains/role-permission/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/user-permission/entity.d.ts +2 -1
- package/dist/adapters/database/domains/user-permission/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/user-permission/entity.mjs +6 -0
- package/dist/adapters/database/domains/user-permission/entity.mjs.map +1 -1
- package/dist/adapters/database/migrations/mysql/1779300000000-Default.d.ts +7 -0
- package/dist/adapters/database/migrations/mysql/1779300000000-Default.d.ts.map +1 -0
- package/dist/adapters/database/migrations/mysql/1779300000000-Default.mjs +85 -0
- package/dist/adapters/database/migrations/mysql/1779300000000-Default.mjs.map +1 -0
- package/dist/adapters/database/migrations/postgres/1779300000000-Default.d.ts +7 -0
- package/dist/adapters/database/migrations/postgres/1779300000000-Default.d.ts.map +1 -0
- package/dist/adapters/database/migrations/postgres/1779300000000-Default.mjs +87 -0
- package/dist/adapters/database/migrations/postgres/1779300000000-Default.mjs.map +1 -0
- package/dist/adapters/http/adapters/index.mjs +2 -2
- package/dist/adapters/http/adapters/oauth2/grant-types/index.mjs +2 -2
- package/dist/adapters/http/adapters/oauth2/grant-types/password.d.ts +2 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/password.d.ts.map +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/password.mjs +12 -4
- package/dist/adapters/http/adapters/oauth2/grant-types/password.mjs.map +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/types.d.ts +2 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/types.d.ts.map +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.d.ts +1 -0
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.d.ts.map +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.mjs +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.mjs.map +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/index.mjs +2 -2
- package/dist/adapters/http/adapters/oauth2/index.mjs +2 -2
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +24 -9
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/token/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/token/module.mjs +2 -1
- package/dist/adapters/http/controllers/workflows/token/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/token/types.d.ts +2 -1
- package/dist/adapters/http/controllers/workflows/token/types.d.ts.map +1 -1
- package/dist/adapters/http/index.mjs +3 -3
- package/dist/adapters/http/request/helpers/identity.d.ts +0 -1
- package/dist/adapters/http/request/helpers/identity.d.ts.map +1 -1
- package/dist/adapters/http/request/helpers/identity.mjs +2 -5
- package/dist/adapters/http/request/helpers/identity.mjs.map +1 -1
- package/dist/adapters/http/request/helpers/index.mjs +2 -2
- package/dist/adapters/http/request/index.mjs +2 -2
- package/dist/adapters/http/request/permission/module.mjs +2 -2
- package/dist/adapters/http/request/permission/module.mjs.map +1 -1
- package/dist/app/modules/database/repositories/bindings.d.ts +2 -0
- package/dist/app/modules/database/repositories/bindings.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/bindings.mjs +3 -1
- package/dist/app/modules/database/repositories/bindings.mjs.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider/repository.mjs +4 -2
- package/dist/app/modules/database/repositories/identity-provider/repository.mjs.map +1 -1
- package/dist/app/modules/database/repositories/permission-provider/module.d.ts +2 -2
- package/dist/app/modules/database/repositories/permission-provider/module.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/permission-provider/module.mjs +4 -3
- package/dist/app/modules/database/repositories/permission-provider/module.mjs.map +1 -1
- package/dist/app/modules/database/repositories/realm/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/realm/repository.mjs +6 -2
- package/dist/app/modules/database/repositories/realm/repository.mjs.map +1 -1
- package/dist/app/modules/http/modules/controller.d.ts +2 -0
- package/dist/app/modules/http/modules/controller.d.ts.map +1 -1
- package/dist/app/modules/http/modules/controller.mjs +18 -0
- package/dist/app/modules/http/modules/controller.mjs.map +1 -1
- package/dist/app/modules/identity/repositories/client.mjs +2 -2
- package/dist/app/modules/identity/repositories/client.mjs.map +1 -1
- package/dist/app/modules/identity/repositories/robot.mjs +2 -2
- package/dist/app/modules/identity/repositories/robot.mjs.map +1 -1
- package/dist/app/modules/identity/repositories/user.mjs +2 -2
- package/dist/app/modules/identity/repositories/user.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/client/repository.mjs +2 -2
- package/dist/app/modules/oauth2/repositories/client/repository.mjs.map +1 -1
- package/dist/app/modules/provisioning/module.d.ts.map +1 -1
- package/dist/app/modules/provisioning/module.mjs +0 -1
- package/dist/app/modules/provisioning/module.mjs.map +1 -1
- package/dist/app/modules/provisioning/sources/default/module.d.ts.map +1 -1
- package/dist/app/modules/provisioning/sources/default/module.mjs +14 -56
- package/dist/app/modules/provisioning/sources/default/module.mjs.map +1 -1
- package/dist/core/entities/client/service.mjs +25 -7
- package/dist/core/entities/client/service.mjs.map +1 -1
- package/dist/core/entities/client-permission/service.d.ts +7 -4
- package/dist/core/entities/client-permission/service.d.ts.map +1 -1
- package/dist/core/entities/client-permission/service.mjs +59 -19
- package/dist/core/entities/client-permission/service.mjs.map +1 -1
- package/dist/core/entities/client-role/service.d.ts +3 -2
- package/dist/core/entities/client-role/service.d.ts.map +1 -1
- package/dist/core/entities/client-role/service.mjs +12 -5
- package/dist/core/entities/client-role/service.mjs.map +1 -1
- package/dist/core/entities/client-scope/service.d.ts +3 -2
- package/dist/core/entities/client-scope/service.d.ts.map +1 -1
- package/dist/core/entities/client-scope/service.mjs +12 -5
- package/dist/core/entities/client-scope/service.mjs.map +1 -1
- package/dist/core/entities/identity-provider-role-mapping/service.d.ts +7 -4
- package/dist/core/entities/identity-provider-role-mapping/service.d.ts.map +1 -1
- package/dist/core/entities/identity-provider-role-mapping/service.mjs +29 -6
- package/dist/core/entities/identity-provider-role-mapping/service.mjs.map +1 -1
- package/dist/core/entities/permission/service.d.ts +3 -5
- package/dist/core/entities/permission/service.d.ts.map +1 -1
- package/dist/core/entities/permission/service.mjs +30 -24
- package/dist/core/entities/permission/service.mjs.map +1 -1
- package/dist/core/entities/permission-policy/service.d.ts +3 -2
- package/dist/core/entities/permission-policy/service.d.ts.map +1 -1
- package/dist/core/entities/permission-policy/service.mjs +12 -5
- package/dist/core/entities/permission-policy/service.mjs.map +1 -1
- package/dist/core/entities/policy/service.d.ts.map +1 -1
- package/dist/core/entities/policy/service.mjs +16 -7
- package/dist/core/entities/policy/service.mjs.map +1 -1
- package/dist/core/entities/realm/service.mjs +4 -4
- package/dist/core/entities/realm/service.mjs.map +1 -1
- package/dist/core/entities/realm/types.d.ts +4 -0
- package/dist/core/entities/realm/types.d.ts.map +1 -1
- package/dist/core/entities/robot/service.d.ts.map +1 -1
- package/dist/core/entities/robot/service.mjs +29 -11
- package/dist/core/entities/robot/service.mjs.map +1 -1
- package/dist/core/entities/robot-permission/service.d.ts +7 -4
- package/dist/core/entities/robot-permission/service.d.ts.map +1 -1
- package/dist/core/entities/robot-permission/service.mjs +59 -19
- package/dist/core/entities/robot-permission/service.mjs.map +1 -1
- package/dist/core/entities/robot-role/service.d.ts +3 -2
- package/dist/core/entities/robot-role/service.d.ts.map +1 -1
- package/dist/core/entities/robot-role/service.mjs +12 -5
- package/dist/core/entities/robot-role/service.mjs.map +1 -1
- package/dist/core/entities/role/service.d.ts.map +1 -1
- package/dist/core/entities/role/service.mjs +16 -7
- package/dist/core/entities/role/service.mjs.map +1 -1
- package/dist/core/entities/role-attribute/service.d.ts.map +1 -1
- package/dist/core/entities/role-attribute/service.mjs +24 -6
- package/dist/core/entities/role-attribute/service.mjs.map +1 -1
- package/dist/core/entities/role-permission/service.d.ts +7 -4
- package/dist/core/entities/role-permission/service.d.ts.map +1 -1
- package/dist/core/entities/role-permission/service.mjs +61 -21
- package/dist/core/entities/role-permission/service.mjs.map +1 -1
- package/dist/core/entities/scope/service.d.ts.map +1 -1
- package/dist/core/entities/scope/service.mjs +16 -7
- package/dist/core/entities/scope/service.mjs.map +1 -1
- package/dist/core/entities/user/service.d.ts.map +1 -1
- package/dist/core/entities/user/service.mjs +28 -10
- package/dist/core/entities/user/service.mjs.map +1 -1
- package/dist/core/entities/user-attribute/service.d.ts.map +1 -1
- package/dist/core/entities/user-attribute/service.mjs +18 -6
- package/dist/core/entities/user-attribute/service.mjs.map +1 -1
- package/dist/core/entities/user-permission/service.d.ts +7 -4
- package/dist/core/entities/user-permission/service.d.ts.map +1 -1
- package/dist/core/entities/user-permission/service.mjs +59 -19
- package/dist/core/entities/user-permission/service.mjs.map +1 -1
- package/dist/core/entities/user-role/service.d.ts +3 -2
- package/dist/core/entities/user-role/service.d.ts.map +1 -1
- package/dist/core/entities/user-role/service.mjs +12 -5
- package/dist/core/entities/user-role/service.mjs.map +1 -1
- package/dist/core/identity/index.mjs +2 -1
- package/dist/core/identity/permission/checker/service.d.ts.map +1 -1
- package/dist/core/identity/permission/checker/service.mjs +6 -4
- package/dist/core/identity/permission/checker/service.mjs.map +1 -1
- package/dist/core/identity/permission/index.d.ts +1 -0
- package/dist/core/identity/permission/index.d.ts.map +1 -1
- package/dist/core/identity/permission/index.mjs +2 -1
- package/dist/core/identity/permission/junction-grant.d.ts +49 -0
- package/dist/core/identity/permission/junction-grant.d.ts.map +1 -0
- package/dist/core/identity/permission/junction-grant.mjs +57 -0
- package/dist/core/identity/permission/junction-grant.mjs.map +1 -0
- package/dist/core/identity/permission/module.d.ts +2 -3
- package/dist/core/identity/permission/module.d.ts.map +1 -1
- package/dist/core/identity/permission/module.mjs +52 -14
- package/dist/core/identity/permission/module.mjs.map +1 -1
- package/dist/core/identity/permission/types.d.ts +22 -2
- package/dist/core/identity/permission/types.d.ts.map +1 -1
- package/dist/core/index.mjs +2 -1
- package/dist/core/provisioning/entities/role/types.d.ts +8 -5
- package/dist/core/provisioning/entities/role/types.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/base.d.ts +3 -0
- package/dist/core/provisioning/synchronizer/base.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/base.mjs +3 -0
- package/dist/core/provisioning/synchronizer/base.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/client/module.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/client/module.mjs +1 -0
- package/dist/core/provisioning/synchronizer/client/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/entity-resolver.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/entity-resolver.mjs +3 -0
- package/dist/core/provisioning/synchronizer/entity-resolver.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/index.mjs +1 -0
- package/dist/core/provisioning/synchronizer/permission/module.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/permission/module.mjs +2 -1
- package/dist/core/provisioning/synchronizer/permission/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/policy/module.d.ts +2 -0
- package/dist/core/provisioning/synchronizer/policy/module.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/policy/module.mjs +19 -1
- package/dist/core/provisioning/synchronizer/policy/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/realm/module.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/realm/module.mjs +1 -0
- package/dist/core/provisioning/synchronizer/realm/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/robot/module.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/robot/module.mjs +1 -0
- package/dist/core/provisioning/synchronizer/robot/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/role/module.d.ts +2 -3
- package/dist/core/provisioning/synchronizer/role/module.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/role/module.mjs +14 -20
- package/dist/core/provisioning/synchronizer/role/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/role/types.d.ts +1 -2
- package/dist/core/provisioning/synchronizer/role/types.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/scope/module.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/scope/module.mjs +1 -0
- package/dist/core/provisioning/synchronizer/scope/module.mjs.map +1 -1
- package/dist/core/provisioning/synchronizer/user/module.d.ts.map +1 -1
- package/dist/core/provisioning/synchronizer/user/module.mjs +1 -0
- package/dist/core/provisioning/synchronizer/user/module.mjs.map +1 -1
- package/dist/core/security/policy/evaluator.d.ts +4 -4
- package/dist/core/security/policy/evaluator.d.ts.map +1 -1
- package/dist/core/security/policy/evaluator.mjs +19 -18
- package/dist/core/security/policy/evaluator.mjs.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/swagger.json +54 -0
- package/dist/ui/client/.vite/ssr-manifest.json +1017 -639
- package/dist/ui/client/assets/index-Cd3uWit-.js +127 -0
- package/dist/ui/client/assets/index-DoCTwJ8M.css +2 -0
- package/dist/ui/client/index.html +2 -2
- package/dist/ui/server/server.js +11086 -2362
- package/package.json +37 -35
- package/dist/ui/client/assets/index-BFXs98mu.js +0 -102
- package/dist/ui/client/assets/index-C_-HM1P-.css +0 -2
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { RealmScope } from '@authup/access';
|
|
2
|
+
import type { ResolveJunctionGrantResult } from './types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* The privilege-escalation boundary for permission-binding junctions, shared verbatim by
|
|
5
|
+
* role/user/client/robot-permission. Kept in ONE place (rather than copied into each service)
|
|
6
|
+
* so the fail-closed cap/inherit rule is audited and changed once — see #3160 / #3158 / #3159,
|
|
7
|
+
* which each had to patch this rule across all four services.
|
|
8
|
+
*
|
|
9
|
+
* It depends on a server-core type (`ResolveJunctionGrantResult`) and so cannot live on the
|
|
10
|
+
* generic `JunctionEntityService` in `@authup/server-kit` (that would invert the layering).
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Cap a junction CREATE to the actor's request-relative selected grant and inherit its policy.
|
|
14
|
+
*
|
|
15
|
+
* - `realm_scope` is capped to the actor's selected reach (`min(requested, grant.realmScope)`).
|
|
16
|
+
* - The policy follows the grant: only a genuinely unrestricted actor (an UNCAPPED `any` reach
|
|
17
|
+
* AND no policy) may keep an explicitly-requested `policy_id`; any restricted/policy-bound
|
|
18
|
+
* actor inherits its own grant's policy (it can neither attach an unowned policy nor detach to
|
|
19
|
+
* widen). The check reads `grant.realmScope` UNCAPPED precisely to distinguish that case — the
|
|
20
|
+
* grant is returned uncapped by `resolveJunctionGrant` for exactly this reason.
|
|
21
|
+
*
|
|
22
|
+
* Mutates `validated` in place (mirrors the surrounding service style).
|
|
23
|
+
*/
|
|
24
|
+
export declare function applyJunctionCreateGrant(validated: Record<string, any>, grant: ResolveJunctionGrantResult): void;
|
|
25
|
+
export type BuildJunctionUpdateDataInput = {
|
|
26
|
+
/** The validated update payload (UPDATE group) — presence of a key signals caller intent. */
|
|
27
|
+
data: Record<string, any>;
|
|
28
|
+
/** The persisted junction's current reach (used to re-cap a policy-only edit). */
|
|
29
|
+
existingScope: `${RealmScope}`;
|
|
30
|
+
/** The actor's UNCAPPED selected reach for this permission (`any` for system context). */
|
|
31
|
+
actorScope: `${RealmScope}`;
|
|
32
|
+
/** Whether the actor's selected grant carries no policy. */
|
|
33
|
+
actorPolicyFree: boolean;
|
|
34
|
+
/** The id of the actor's selected grant policy (null when policy-free). */
|
|
35
|
+
actorPolicyId: string | null;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Build the `{ realm_scope?, policy_id? }` delta for a junction UPDATE, capped to the actor's
|
|
39
|
+
* request-relative grant.
|
|
40
|
+
*
|
|
41
|
+
* - An unrestricted (`any`, policy-free) actor may set/clear `policy_id` explicitly and is never
|
|
42
|
+
* narrowed.
|
|
43
|
+
* - A restricted/policy-bound actor that touches the binding inherits its own grant's policy AND
|
|
44
|
+
* has the reach re-capped — including the EXISTING `realm_scope` when the update omits it, so a
|
|
45
|
+
* policy-only edit cannot leave a wider pre-existing reach standing (fail-OPEN otherwise: the
|
|
46
|
+
* persisted binding must always be dominated by a grant the actor really holds — #3160).
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildJunctionUpdateData(input: BuildJunctionUpdateDataInput): Record<string, any>;
|
|
49
|
+
//# sourceMappingURL=junction-grant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"junction-grant.d.ts","sourceRoot":"","sources":["../../../../src/core/identity/permission/junction-grant.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,UAAU,EAAiB,MAAM,gBAAgB,CAAC;AAE3D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE7D;;;;;;;;GAQG;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACpC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9B,KAAK,EAAE,0BAA0B,GAClC,IAAI,CAMN;AAED,MAAM,MAAM,4BAA4B,GAAG;IACvC,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,kFAAkF;IAClF,aAAa,EAAE,GAAG,UAAU,EAAE,CAAC;IAC/B,0FAA0F;IAC1F,UAAU,EAAE,GAAG,UAAU,EAAE,CAAC;IAC5B,4DAA4D;IAC5D,eAAe,EAAE,OAAO,CAAC;IACzB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,4BAA4B,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAkChG"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { hasOwnProperty } from "@authup/kit";
|
|
5
|
+
import { RealmScope, minRealmScope } from "@authup/access";
|
|
6
|
+
//#region src/core/identity/permission/junction-grant.ts
|
|
7
|
+
/**
|
|
8
|
+
* The privilege-escalation boundary for permission-binding junctions, shared verbatim by
|
|
9
|
+
* role/user/client/robot-permission. Kept in ONE place (rather than copied into each service)
|
|
10
|
+
* so the fail-closed cap/inherit rule is audited and changed once — see #3160 / #3158 / #3159,
|
|
11
|
+
* which each had to patch this rule across all four services.
|
|
12
|
+
*
|
|
13
|
+
* It depends on a server-core type (`ResolveJunctionGrantResult`) and so cannot live on the
|
|
14
|
+
* generic `JunctionEntityService` in `@authup/server-kit` (that would invert the layering).
|
|
15
|
+
*/ /**
|
|
16
|
+
* Cap a junction CREATE to the actor's request-relative selected grant and inherit its policy.
|
|
17
|
+
*
|
|
18
|
+
* - `realm_scope` is capped to the actor's selected reach (`min(requested, grant.realmScope)`).
|
|
19
|
+
* - The policy follows the grant: only a genuinely unrestricted actor (an UNCAPPED `any` reach
|
|
20
|
+
* AND no policy) may keep an explicitly-requested `policy_id`; any restricted/policy-bound
|
|
21
|
+
* actor inherits its own grant's policy (it can neither attach an unowned policy nor detach to
|
|
22
|
+
* widen). The check reads `grant.realmScope` UNCAPPED precisely to distinguish that case — the
|
|
23
|
+
* grant is returned uncapped by `resolveJunctionGrant` for exactly this reason.
|
|
24
|
+
*
|
|
25
|
+
* Mutates `validated` in place (mirrors the surrounding service style).
|
|
26
|
+
*/ function applyJunctionCreateGrant(validated, grant) {
|
|
27
|
+
validated.realm_scope = minRealmScope([validated.realm_scope ?? RealmScope.OWN, grant.realmScope]);
|
|
28
|
+
if (grant.realmScope !== RealmScope.ANY || grant.policy) validated.policy_id = grant.policy ? grant.policy.id : null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build the `{ realm_scope?, policy_id? }` delta for a junction UPDATE, capped to the actor's
|
|
32
|
+
* request-relative grant.
|
|
33
|
+
*
|
|
34
|
+
* - An unrestricted (`any`, policy-free) actor may set/clear `policy_id` explicitly and is never
|
|
35
|
+
* narrowed.
|
|
36
|
+
* - A restricted/policy-bound actor that touches the binding inherits its own grant's policy AND
|
|
37
|
+
* has the reach re-capped — including the EXISTING `realm_scope` when the update omits it, so a
|
|
38
|
+
* policy-only edit cannot leave a wider pre-existing reach standing (fail-OPEN otherwise: the
|
|
39
|
+
* persisted binding must always be dominated by a grant the actor really holds — #3160).
|
|
40
|
+
*/ function buildJunctionUpdateData(input) {
|
|
41
|
+
const { data, existingScope, actorScope, actorPolicyFree, actorPolicyId } = input;
|
|
42
|
+
const updateData = {};
|
|
43
|
+
const touchesScope = hasOwnProperty(data, "realm_scope");
|
|
44
|
+
const touchesPolicy = hasOwnProperty(data, "policy_id");
|
|
45
|
+
if (touchesScope) updateData.realm_scope = minRealmScope([data.realm_scope, actorScope]);
|
|
46
|
+
if (actorScope === RealmScope.ANY && actorPolicyFree) {
|
|
47
|
+
if (touchesPolicy) updateData.policy_id = data.policy_id;
|
|
48
|
+
} else if (touchesScope || touchesPolicy) {
|
|
49
|
+
updateData.policy_id = actorPolicyId;
|
|
50
|
+
if (!touchesScope) updateData.realm_scope = minRealmScope([existingScope, actorScope]);
|
|
51
|
+
}
|
|
52
|
+
return updateData;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { applyJunctionCreateGrant, buildJunctionUpdateData };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=junction-grant.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"junction-grant.mjs","names":["RealmScope","minRealmScope","hasOwnProperty","applyJunctionCreateGrant","validated","grant","realm_scope","OWN","realmScope","ANY","policy","policy_id","id","buildJunctionUpdateData","input","data","existingScope","actorScope","actorPolicyFree","actorPolicyId","updateData","touchesScope","touchesPolicy"],"sources":["../../../../src/core/identity/permission/junction-grant.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { RealmScope, minRealmScope } from '@authup/access';\nimport { hasOwnProperty } from '@authup/kit';\nimport type { ResolveJunctionGrantResult } from './types.ts';\n\n/**\n * The privilege-escalation boundary for permission-binding junctions, shared verbatim by\n * role/user/client/robot-permission. Kept in ONE place (rather than copied into each service)\n * so the fail-closed cap/inherit rule is audited and changed once — see #3160 / #3158 / #3159,\n * which each had to patch this rule across all four services.\n *\n * It depends on a server-core type (`ResolveJunctionGrantResult`) and so cannot live on the\n * generic `JunctionEntityService` in `@authup/server-kit` (that would invert the layering).\n */\n\n/**\n * Cap a junction CREATE to the actor's request-relative selected grant and inherit its policy.\n *\n * - `realm_scope` is capped to the actor's selected reach (`min(requested, grant.realmScope)`).\n * - The policy follows the grant: only a genuinely unrestricted actor (an UNCAPPED `any` reach\n * AND no policy) may keep an explicitly-requested `policy_id`; any restricted/policy-bound\n * actor inherits its own grant's policy (it can neither attach an unowned policy nor detach to\n * widen). The check reads `grant.realmScope` UNCAPPED precisely to distinguish that case — the\n * grant is returned uncapped by `resolveJunctionGrant` for exactly this reason.\n *\n * Mutates `validated` in place (mirrors the surrounding service style).\n */\nexport function applyJunctionCreateGrant(\n validated: Record<string, any>,\n grant: ResolveJunctionGrantResult,\n): void {\n validated.realm_scope = minRealmScope([validated.realm_scope ?? RealmScope.OWN, grant.realmScope]);\n\n if (grant.realmScope !== RealmScope.ANY || grant.policy) {\n validated.policy_id = grant.policy ? grant.policy.id : null;\n }\n}\n\nexport type BuildJunctionUpdateDataInput = {\n /** The validated update payload (UPDATE group) — presence of a key signals caller intent. */\n data: Record<string, any>,\n /** The persisted junction's current reach (used to re-cap a policy-only edit). */\n existingScope: `${RealmScope}`,\n /** The actor's UNCAPPED selected reach for this permission (`any` for system context). */\n actorScope: `${RealmScope}`,\n /** Whether the actor's selected grant carries no policy. */\n actorPolicyFree: boolean,\n /** The id of the actor's selected grant policy (null when policy-free). */\n actorPolicyId: string | null,\n};\n\n/**\n * Build the `{ realm_scope?, policy_id? }` delta for a junction UPDATE, capped to the actor's\n * request-relative grant.\n *\n * - An unrestricted (`any`, policy-free) actor may set/clear `policy_id` explicitly and is never\n * narrowed.\n * - A restricted/policy-bound actor that touches the binding inherits its own grant's policy AND\n * has the reach re-capped — including the EXISTING `realm_scope` when the update omits it, so a\n * policy-only edit cannot leave a wider pre-existing reach standing (fail-OPEN otherwise: the\n * persisted binding must always be dominated by a grant the actor really holds — #3160).\n */\nexport function buildJunctionUpdateData(input: BuildJunctionUpdateDataInput): Record<string, any> {\n const {\n data, \n existingScope, \n actorScope, \n actorPolicyFree, \n actorPolicyId,\n } = input;\n\n const updateData: Record<string, any> = {};\n\n const touchesScope = hasOwnProperty(data, 'realm_scope');\n const touchesPolicy = hasOwnProperty(data, 'policy_id');\n\n // CAP to the actor's ceiling — a restricted actor may narrow but never widen.\n // (`data` is the validated UPDATE payload, so realm_scope is already a valid enum value;\n // minRealmScope additionally normalizes any out-of-band input fail-closed to `own`.)\n if (touchesScope) {\n updateData.realm_scope = minRealmScope([data.realm_scope as `${RealmScope}`, actorScope]);\n }\n\n if (actorScope === RealmScope.ANY && actorPolicyFree) {\n if (touchesPolicy) {\n updateData.policy_id = data.policy_id;\n }\n } else if (touchesScope || touchesPolicy) {\n updateData.policy_id = actorPolicyId;\n\n if (!touchesScope) {\n updateData.realm_scope = minRealmScope([existingScope, actorScope]);\n }\n }\n\n return updateData;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;GAiCA,SAAgBG,yBACZC,WACAC,OAAiC;CAEjCD,UAAUE,cAAcL,cAAc,CAACG,UAAUE,eAAeN,WAAWO,KAAKF,MAAMG,UAAAA,CAAW;CAEjG,IAAIH,MAAMG,eAAeR,WAAWS,OAAOJ,MAAMK,QAC7CN,UAAUO,YAAYN,MAAMK,SAASL,MAAMK,OAAOE,KAAK;AAE/D;;;;;;;;;;;GA0BA,SAAgBC,wBAAwBC,OAAmC;CACvE,MAAM,EACFC,MACAC,eACAC,YACAC,iBACAC,kBACAL;CAEJ,MAAMM,aAAkC,CAAC;CAEzC,MAAMC,eAAenB,eAAea,MAAM,aAAA;CAC1C,MAAMO,gBAAgBpB,eAAea,MAAM,WAAA;CAK3C,IAAIM,cACAD,WAAWd,cAAcL,cAAc,CAACc,KAAKT,aAAgCW,UAAAA,CAAW;CAG5F,IAAIA,eAAejB,WAAWS,OAAOS;MAC7BI,eACAF,WAAWT,YAAYI,KAAKJ;CAAAA,OAE7B,IAAIU,gBAAgBC,eAAe;EACtCF,WAAWT,YAAYQ;EAEvB,IAAI,CAACE,cACDD,WAAWd,cAAcL,cAAc,CAACe,eAAeC,UAAAA,CAAW;CAE1E;CAEA,OAAOG;AACX"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { IdentityPolicyData, PermissionPolicyBinding } from '@authup/access';
|
|
2
|
-
import type { Policy } from '@authup/core-kit';
|
|
3
2
|
import type { IClientRepository } from '../../entities/client/types.ts';
|
|
4
3
|
import type { IRobotRepository } from '../../entities/robot/types.ts';
|
|
5
4
|
import type { IRoleRepository } from '../../entities/role/types.ts';
|
|
6
5
|
import type { IUserRepository } from '../../entities/user/types.ts';
|
|
7
6
|
import type { IIdentityRoleProvider } from '../role/types.ts';
|
|
8
|
-
import type { IIdentityPermissionProvider, IdentityPermissionProviderContext, ResolveJunctionPolicyOptions } from './types.ts';
|
|
7
|
+
import type { IIdentityPermissionProvider, IdentityPermissionProviderContext, ResolveJunctionGrantResult, ResolveJunctionPolicyOptions } from './types.ts';
|
|
9
8
|
export declare class IdentityPermissionProvider implements IIdentityPermissionProvider {
|
|
10
9
|
protected clientRepository: IClientRepository;
|
|
11
10
|
protected userRepository: IUserRepository;
|
|
@@ -14,7 +13,7 @@ export declare class IdentityPermissionProvider implements IIdentityPermissionPr
|
|
|
14
13
|
protected roleProvider: IIdentityRoleProvider;
|
|
15
14
|
constructor(ctx: IdentityPermissionProviderContext);
|
|
16
15
|
isSuperset(parent: IdentityPolicyData, child: IdentityPolicyData): Promise<boolean>;
|
|
17
|
-
|
|
16
|
+
resolveJunctionGrant(identity: IdentityPolicyData, options: ResolveJunctionPolicyOptions): Promise<ResolveJunctionGrantResult>;
|
|
18
17
|
getFor(identity: IdentityPolicyData): Promise<PermissionPolicyBinding[]>;
|
|
19
18
|
getForClient(identity: IdentityPolicyData): Promise<PermissionPolicyBinding[]>;
|
|
20
19
|
getForUser(identity: IdentityPolicyData): Promise<PermissionPolicyBinding[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../src/core/identity/permission/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACR,kBAAkB,
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../src/core/identity/permission/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACR,kBAAkB,EAElB,uBAAuB,EAC1B,MAAM,gBAAgB,CAAC;AAWxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,KAAK,EACR,2BAA2B,EAC3B,iCAAiC,EACjC,0BAA0B,EAC1B,4BAA4B,EAC/B,MAAM,YAAY,CAAC;AAEpB,qBAAa,0BAA2B,YAAW,2BAA2B;IAC1E,SAAS,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAE9C,SAAS,CAAC,cAAc,EAAE,eAAe,CAAC;IAE1C,SAAS,CAAC,cAAc,EAAE,eAAe,CAAC;IAE1C,SAAS,CAAC,eAAe,EAAE,gBAAgB,CAAC;IAE5C,SAAS,CAAC,YAAY,EAAE,qBAAqB,CAAC;gBAElC,GAAG,EAAE,iCAAiC;IAQ5C,UAAU,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,kBAAkB,GAAI,OAAO,CAAC,OAAO,CAAC;IAgCpF,oBAAoB,CACtB,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,4BAA4B,GACtC,OAAO,CAAC,0BAA0B,CAAC;IA6DhC,MAAM,CAAC,QAAQ,EAAE,kBAAkB,GAAI,OAAO,CAAC,uBAAuB,EAAE,CAAC;IAmBzE,YAAY,CAAC,QAAQ,EAAE,kBAAkB,GAAI,OAAO,CAAC,uBAAuB,EAAE,CAAC;IAO/E,UAAU,CAAC,QAAQ,EAAE,kBAAkB,GAAI,OAAO,CAAC,uBAAuB,EAAE,CAAC;IAQ7E,WAAW,CAAC,QAAQ,EAAE,kBAAkB,GAAI,OAAO,CAAC,uBAAuB,EAAE,CAAC;IAQ9E,UAAU,CAAC,QAAQ,EAAE,kBAAkB,GAAI,OAAO,CAAC,uBAAuB,EAAE,CAAC;YAKrE,uBAAuB;IAmBrC,OAAO,CAAC,8BAA8B;CAUzC"}
|
|
@@ -2,7 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { isPolicy } from "@authup/core-kit";
|
|
5
|
-
import { isPermissionPolicyBindingEqual,
|
|
5
|
+
import { RealmScope, aggregatePermissionPolicyBindings, compareRealmScope, grantDominates, isPermissionPolicyBindingEqual, minRealmScope } from "@authup/access";
|
|
6
6
|
//#region src/core/identity/permission/module.ts
|
|
7
7
|
var IdentityPermissionProvider = class {
|
|
8
8
|
clientRepository;
|
|
@@ -18,18 +18,16 @@ var IdentityPermissionProvider = class {
|
|
|
18
18
|
this.roleProvider = ctx.roleProvider;
|
|
19
19
|
}
|
|
20
20
|
async isSuperset(parent, child) {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
for (const childItem of childMerged) {
|
|
26
|
-
const parentItem = parentMerged.find((p) => isPermissionPolicyBindingEqual(p, childItem));
|
|
21
|
+
const parentAggregated = aggregatePermissionPolicyBindings(await this.getFor(parent));
|
|
22
|
+
const childAggregated = aggregatePermissionPolicyBindings(await this.getFor(child));
|
|
23
|
+
for (const childItem of childAggregated) {
|
|
24
|
+
const parentItem = parentAggregated.find((p) => isPermissionPolicyBindingEqual(p, childItem));
|
|
27
25
|
if (!parentItem) return false;
|
|
28
|
-
|
|
26
|
+
for (const childGrant of childItem.grants) if (!parentItem.grants.some((parentGrant) => grantDominates(parentGrant, childGrant))) return false;
|
|
29
27
|
}
|
|
30
28
|
return true;
|
|
31
29
|
}
|
|
32
|
-
async
|
|
30
|
+
async resolveJunctionGrant(identity, options) {
|
|
33
31
|
const matching = (await this.getFor(identity)).filter((b) => {
|
|
34
32
|
if (b.permission.name !== options.name) return false;
|
|
35
33
|
if (typeof options.realmId !== "undefined") {
|
|
@@ -40,12 +38,19 @@ var IdentityPermissionProvider = class {
|
|
|
40
38
|
}
|
|
41
39
|
return true;
|
|
42
40
|
});
|
|
43
|
-
if (matching.length === 0) return;
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
if (matching.length === 0) return { realmScope: RealmScope.OWN };
|
|
42
|
+
const grants = aggregatePermissionPolicyBindings(matching).flatMap((item) => item.grants);
|
|
43
|
+
if (grants.length === 0) return { realmScope: RealmScope.OWN };
|
|
44
|
+
const selected = selectGrantForRequest(grants, options.realmScope ?? RealmScope.OWN);
|
|
45
|
+
let policy;
|
|
46
|
+
if (selected.policy) {
|
|
47
|
+
if (!isPolicy(selected.policy)) return { realmScope: RealmScope.NONE };
|
|
48
|
+
policy = selected.policy;
|
|
48
49
|
}
|
|
50
|
+
return {
|
|
51
|
+
policy,
|
|
52
|
+
realmScope: selected.realm_scope
|
|
53
|
+
};
|
|
49
54
|
}
|
|
50
55
|
async getFor(identity) {
|
|
51
56
|
switch (identity.type) {
|
|
@@ -79,6 +84,39 @@ var IdentityPermissionProvider = class {
|
|
|
79
84
|
return bindings.filter((binding) => binding.permission.client_id === identity.clientId);
|
|
80
85
|
}
|
|
81
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Select the held grant that confers the least-restrictive junction for `requested` reach.
|
|
89
|
+
*
|
|
90
|
+
* Each grant is ranked by the reach it can actually confer for THIS request — its own
|
|
91
|
+
* `realm_scope` capped to `requested` — so a lower-scoped policy-free grant beats a
|
|
92
|
+
* higher-scoped policy-bound grant when both cap to the same requested reach (the mixed-grant
|
|
93
|
+
* fix, #3160). On equal capped reach, a policy-free grant wins (least restrictive). The
|
|
94
|
+
* ORIGINAL (uncapped) grant is returned: the consumer applies the `min` cap itself, and its
|
|
95
|
+
* uncapped `realm_scope`/`policy` drive the "actor is unrestricted-any?" check that decides
|
|
96
|
+
* whether an explicitly-requested `policy_id` may stand.
|
|
97
|
+
*
|
|
98
|
+
* The ordering is TOTAL and deterministic (independent of grant/repository order): ties between
|
|
99
|
+
* two policy-bound grants on equal capped reach are broken by higher uncapped reach, then a
|
|
100
|
+
* propagatable policy (one with an id) over an id-less composite that would fail closed, then
|
|
101
|
+
* lexicographic policy id.
|
|
102
|
+
*/ function selectGrantForRequest(grants, requested) {
|
|
103
|
+
return grants.reduce((best, grant) => isGrantPreferred(grant, best, requested) ? grant : best);
|
|
104
|
+
}
|
|
105
|
+
/** True when `candidate` is a strictly better propagation source than `incumbent` for `requested`. */ function isGrantPreferred(candidate, incumbent, requested) {
|
|
106
|
+
const byCapped = compareRealmScope(minRealmScope([candidate.realm_scope, requested]), minRealmScope([incumbent.realm_scope, requested]));
|
|
107
|
+
if (byCapped !== 0) return byCapped > 0;
|
|
108
|
+
if (!candidate.policy !== !incumbent.policy) return !candidate.policy;
|
|
109
|
+
const byUncapped = compareRealmScope(candidate.realm_scope, incumbent.realm_scope);
|
|
110
|
+
if (byUncapped !== 0) return byUncapped > 0;
|
|
111
|
+
const candidateId = candidate.policy && isPolicy(candidate.policy) ? candidate.policy.id : void 0;
|
|
112
|
+
const incumbentId = incumbent.policy && isPolicy(incumbent.policy) ? incumbent.policy.id : void 0;
|
|
113
|
+
if (candidateId !== incumbentId) {
|
|
114
|
+
if (typeof candidateId === "undefined") return false;
|
|
115
|
+
if (typeof incumbentId === "undefined") return true;
|
|
116
|
+
return candidateId < incumbentId;
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
82
120
|
//#endregion
|
|
83
121
|
export { IdentityPermissionProvider };
|
|
84
122
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["isPermissionPolicyBindingEqual","mergePermissionPolicyBindings","isPolicy","IdentityPermissionProvider","clientRepository","userRepository","roleRepository","robotRepository","roleProvider","ctx","isSuperset","parent","child","parentBindings","getFor","childBindings","parentMerged","childMerged","childItem","parentItem","find","p","policies","length","resolveJunctionPolicy","identity","options","bindings","matching","filter","b","permission","name","realmId","realm_id","clientId","client_id","undefined","merged","policy","type","getForClient","getForUser","getForRobot","getForRole","combineWithRoleBindings","getBoundPermissions","id","then","data","reduceBindingsByIdentityClient","bindingsPromise","roles","Promise","all","getRolesFor","roleBindings","getBoundPermissionsForMany","binding"],"sources":["../../../../src/core/identity/permission/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2024.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type {\n IdentityPolicyData,\n PermissionPolicyBinding,\n} from '@authup/access';\nimport { isPermissionPolicyBindingEqual, mergePermissionPolicyBindings } from '@authup/access';\nimport type { Policy } from '@authup/core-kit';\nimport { isPolicy } from '@authup/core-kit';\nimport type { IClientRepository } from '../../entities/client/types.ts';\nimport type { IRobotRepository } from '../../entities/robot/types.ts';\nimport type { IRoleRepository } from '../../entities/role/types.ts';\nimport type { IUserRepository } from '../../entities/user/types.ts';\nimport type { IIdentityRoleProvider } from '../role/types.ts';\nimport type {\n IIdentityPermissionProvider,\n IdentityPermissionProviderContext,\n ResolveJunctionPolicyOptions,\n} from './types.ts';\n\nexport class IdentityPermissionProvider implements IIdentityPermissionProvider {\n protected clientRepository: IClientRepository;\n\n protected userRepository: IUserRepository;\n\n protected roleRepository: IRoleRepository;\n\n protected robotRepository: IRobotRepository;\n\n protected roleProvider: IIdentityRoleProvider;\n\n constructor(ctx: IdentityPermissionProviderContext) {\n this.clientRepository = ctx.clientRepository;\n this.userRepository = ctx.userRepository;\n this.roleRepository = ctx.roleRepository;\n this.robotRepository = ctx.robotRepository;\n this.roleProvider = ctx.roleProvider;\n }\n\n async isSuperset(parent: IdentityPolicyData, child: IdentityPolicyData) : Promise<boolean> {\n const parentBindings = await this.getFor(parent);\n const childBindings = await this.getFor(child);\n\n const parentMerged = mergePermissionPolicyBindings(parentBindings);\n const childMerged = mergePermissionPolicyBindings(childBindings);\n\n for (const childItem of childMerged) {\n const parentItem = parentMerged.find(\n (p) => isPermissionPolicyBindingEqual(p, childItem),\n );\n\n if (!parentItem) {\n return false;\n }\n\n if (\n parentItem.policies && parentItem.policies.length > 0 &&\n (!childItem.policies || childItem.policies.length === 0)\n ) {\n return false;\n }\n }\n\n return true;\n }\n\n async resolveJunctionPolicy(\n identity: IdentityPolicyData,\n options: ResolveJunctionPolicyOptions,\n ): Promise<Policy | undefined> {\n const bindings = await this.getFor(identity);\n const matching = bindings.filter((b) => {\n if (b.permission.name !== options.name) {\n return false;\n }\n\n if (typeof options.realmId !== 'undefined') {\n if ((b.permission.realm_id ?? null) !== (options.realmId ?? null)) {\n return false;\n }\n }\n\n if (typeof options.clientId !== 'undefined') {\n if ((b.permission.client_id ?? null) !== (options.clientId ?? null)) {\n return false;\n }\n }\n\n return true;\n });\n\n if (matching.length === 0) {\n return undefined;\n }\n\n const merged = mergePermissionPolicyBindings(matching);\n\n if (merged.length > 0 && merged[0].policies && merged[0].policies.length > 0) {\n const policy = merged[0].policies[0];\n if (isPolicy(policy)) {\n return policy;\n }\n }\n\n return undefined;\n }\n\n async getFor(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n switch (identity.type) {\n case 'client': {\n return this.getForClient(identity);\n }\n case 'user': {\n return this.getForUser(identity);\n }\n case 'robot': {\n return this.getForRobot(identity);\n }\n case 'role': {\n return this.getForRole(identity);\n }\n }\n\n return [];\n }\n\n async getForClient(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n return this.combineWithRoleBindings(\n this.clientRepository.getBoundPermissions(identity.id),\n identity,\n );\n }\n\n async getForUser(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n return this.combineWithRoleBindings(\n this.userRepository.getBoundPermissions(identity.id)\n .then((data) => this.reduceBindingsByIdentityClient(data, identity)),\n identity,\n );\n }\n\n async getForRobot(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n return this.combineWithRoleBindings(\n this.robotRepository.getBoundPermissions(identity.id)\n .then((data) => this.reduceBindingsByIdentityClient(data, identity)),\n identity,\n );\n }\n\n async getForRole(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n return this.roleRepository.getBoundPermissions(identity.id)\n .then((data) => this.reduceBindingsByIdentityClient(data, identity));\n }\n\n private async combineWithRoleBindings(\n bindingsPromise: Promise<PermissionPolicyBinding[]>,\n identity: IdentityPolicyData,\n ): Promise<PermissionPolicyBinding[]> {\n const [bindings, roles] = await Promise.all([\n bindingsPromise,\n this.roleProvider.getRolesFor(identity),\n ]);\n const roleBindings = await this.roleRepository.getBoundPermissionsForMany(roles);\n if (roleBindings.length === 0) {\n return bindings;\n }\n\n return [\n ...bindings,\n ...roleBindings,\n ];\n }\n\n private reduceBindingsByIdentityClient(\n bindings: PermissionPolicyBinding[],\n identity: IdentityPolicyData,\n ): PermissionPolicyBinding[] {\n if (!identity.clientId) {\n return bindings;\n }\n\n return bindings.filter((binding) => binding.permission.client_id === identity.clientId);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["RealmScope","aggregatePermissionPolicyBindings","compareRealmScope","grantDominates","isPermissionPolicyBindingEqual","minRealmScope","isPolicy","IdentityPermissionProvider","clientRepository","userRepository","roleRepository","robotRepository","roleProvider","ctx","isSuperset","parent","child","parentAggregated","getFor","childAggregated","childItem","parentItem","find","p","childGrant","grants","dominated","some","parentGrant","resolveJunctionGrant","identity","options","bindings","matching","filter","b","permission","name","realmId","realm_id","clientId","client_id","length","realmScope","OWN","flatMap","item","requested","selected","selectGrantForRequest","policy","NONE","realm_scope","type","getForClient","getForUser","getForRobot","getForRole","combineWithRoleBindings","getBoundPermissions","id","then","data","reduceBindingsByIdentityClient","bindingsPromise","roles","Promise","all","getRolesFor","roleBindings","getBoundPermissionsForMany","binding","reduce","best","grant","isGrantPreferred","candidate","incumbent","byCapped","byUncapped","candidateId","undefined","incumbentId"],"sources":["../../../../src/core/identity/permission/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2024.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type {\n IdentityPolicyData,\n PermissionGrant,\n PermissionPolicyBinding,\n} from '@authup/access';\nimport {\n RealmScope,\n aggregatePermissionPolicyBindings,\n compareRealmScope,\n grantDominates,\n isPermissionPolicyBindingEqual,\n minRealmScope,\n} from '@authup/access';\nimport type { Policy } from '@authup/core-kit';\nimport { isPolicy } from '@authup/core-kit';\nimport type { IClientRepository } from '../../entities/client/types.ts';\nimport type { IRobotRepository } from '../../entities/robot/types.ts';\nimport type { IRoleRepository } from '../../entities/role/types.ts';\nimport type { IUserRepository } from '../../entities/user/types.ts';\nimport type { IIdentityRoleProvider } from '../role/types.ts';\nimport type {\n IIdentityPermissionProvider,\n IdentityPermissionProviderContext,\n ResolveJunctionGrantResult,\n ResolveJunctionPolicyOptions,\n} from './types.ts';\n\nexport class IdentityPermissionProvider implements IIdentityPermissionProvider {\n protected clientRepository: IClientRepository;\n\n protected userRepository: IUserRepository;\n\n protected roleRepository: IRoleRepository;\n\n protected robotRepository: IRobotRepository;\n\n protected roleProvider: IIdentityRoleProvider;\n\n constructor(ctx: IdentityPermissionProviderContext) {\n this.clientRepository = ctx.clientRepository;\n this.userRepository = ctx.userRepository;\n this.roleRepository = ctx.roleRepository;\n this.robotRepository = ctx.robotRepository;\n this.roleProvider = ctx.roleProvider;\n }\n\n async isSuperset(parent: IdentityPolicyData, child: IdentityPolicyData) : Promise<boolean> {\n const parentAggregated = aggregatePermissionPolicyBindings(await this.getFor(parent));\n const childAggregated = aggregatePermissionPolicyBindings(await this.getFor(child));\n\n for (const childItem of childAggregated) {\n const parentItem = parentAggregated.find(\n (p) => isPermissionPolicyBindingEqual(p, childItem),\n );\n\n if (!parentItem) {\n return false;\n }\n\n // Disjunction-aware superset: EVERY child grant must be dominated by SOME parent\n // grant (reach >= AND the parent's policy provably covers the child's — see\n // grantDominates). A child grant the parent cannot match — an unconditional `any`\n // the parent only holds policy-gated, or a policy the parent does not itself hold\n // (#3159) — fails the check; the actor cannot assign more than it holds.\n for (const childGrant of childItem.grants) {\n const dominated = parentItem.grants.some(\n (parentGrant) => grantDominates(parentGrant, childGrant),\n );\n\n if (!dominated) {\n return false;\n }\n }\n }\n\n return true;\n }\n\n async resolveJunctionGrant(\n identity: IdentityPolicyData,\n options: ResolveJunctionPolicyOptions,\n ): Promise<ResolveJunctionGrantResult> {\n const bindings = await this.getFor(identity);\n const matching = bindings.filter((b) => {\n if (b.permission.name !== options.name) {\n return false;\n }\n\n if (typeof options.realmId !== 'undefined') {\n if ((b.permission.realm_id ?? null) !== (options.realmId ?? null)) {\n return false;\n }\n }\n\n if (typeof options.clientId !== 'undefined') {\n if ((b.permission.client_id ?? null) !== (options.clientId ?? null)) {\n return false;\n }\n }\n\n return true;\n });\n\n if (matching.length === 0) {\n return { realmScope: RealmScope.OWN };\n }\n\n // Consider EVERY matching grant (a caller omitting realmId/clientId may leave more\n // than one permission-key group); combined with the total ordering in\n // selectGrantForRequest, the selection never depends on grant/repository order.\n const grants = aggregatePermissionPolicyBindings(matching)\n .flatMap((item) => item.grants);\n if (grants.length === 0) {\n return { realmScope: RealmScope.OWN };\n }\n\n // Select the actor's grant RELATIVE to the requested reach (#3160): the grant that\n // confers the least-restrictive junction once capped to `realmScope` (highest capped\n // reach, policy-free preferred on a tie) — NOT a global \"ceiling\". A mixed-grant actor\n // (e.g. own+no-policy and any+policy) thus propagates its policy-free own grant for an\n // own request instead of inheriting the wider grant's policy. The selected grant is\n // returned UNCAPPED so the consumer's own cap (`min(requested, realmScope)`) and its\n // \"actor is unrestricted-any?\" check (which honours an explicit policy_id) still hold.\n const requested = options.realmScope ?? RealmScope.OWN;\n const selected = selectGrantForRequest(grants, requested);\n\n let policy: Policy | undefined;\n if (selected.policy) {\n // The selected grant is policy-restricted but its policy is not a propagatable\n // Policy (e.g. a composite with no id). Fail CLOSED: a `none` reach blocks\n // propagation rather than silently dropping the restriction and widening to an\n // unrestricted grant.\n if (!isPolicy(selected.policy)) {\n return { realmScope: RealmScope.NONE };\n }\n\n policy = selected.policy;\n }\n\n return { policy, realmScope: selected.realm_scope };\n }\n\n async getFor(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n switch (identity.type) {\n case 'client': {\n return this.getForClient(identity);\n }\n case 'user': {\n return this.getForUser(identity);\n }\n case 'robot': {\n return this.getForRobot(identity);\n }\n case 'role': {\n return this.getForRole(identity);\n }\n }\n\n return [];\n }\n\n async getForClient(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n return this.combineWithRoleBindings(\n this.clientRepository.getBoundPermissions(identity.id),\n identity,\n );\n }\n\n async getForUser(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n return this.combineWithRoleBindings(\n this.userRepository.getBoundPermissions(identity.id)\n .then((data) => this.reduceBindingsByIdentityClient(data, identity)),\n identity,\n );\n }\n\n async getForRobot(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n return this.combineWithRoleBindings(\n this.robotRepository.getBoundPermissions(identity.id)\n .then((data) => this.reduceBindingsByIdentityClient(data, identity)),\n identity,\n );\n }\n\n async getForRole(identity: IdentityPolicyData) : Promise<PermissionPolicyBinding[]> {\n return this.roleRepository.getBoundPermissions(identity.id)\n .then((data) => this.reduceBindingsByIdentityClient(data, identity));\n }\n\n private async combineWithRoleBindings(\n bindingsPromise: Promise<PermissionPolicyBinding[]>,\n identity: IdentityPolicyData,\n ): Promise<PermissionPolicyBinding[]> {\n const [bindings, roles] = await Promise.all([\n bindingsPromise,\n this.roleProvider.getRolesFor(identity),\n ]);\n const roleBindings = await this.roleRepository.getBoundPermissionsForMany(roles);\n if (roleBindings.length === 0) {\n return bindings;\n }\n\n return [\n ...bindings,\n ...roleBindings,\n ];\n }\n\n private reduceBindingsByIdentityClient(\n bindings: PermissionPolicyBinding[],\n identity: IdentityPolicyData,\n ): PermissionPolicyBinding[] {\n if (!identity.clientId) {\n return bindings;\n }\n\n return bindings.filter((binding) => binding.permission.client_id === identity.clientId);\n }\n}\n\n/**\n * Select the held grant that confers the least-restrictive junction for `requested` reach.\n *\n * Each grant is ranked by the reach it can actually confer for THIS request — its own\n * `realm_scope` capped to `requested` — so a lower-scoped policy-free grant beats a\n * higher-scoped policy-bound grant when both cap to the same requested reach (the mixed-grant\n * fix, #3160). On equal capped reach, a policy-free grant wins (least restrictive). The\n * ORIGINAL (uncapped) grant is returned: the consumer applies the `min` cap itself, and its\n * uncapped `realm_scope`/`policy` drive the \"actor is unrestricted-any?\" check that decides\n * whether an explicitly-requested `policy_id` may stand.\n *\n * The ordering is TOTAL and deterministic (independent of grant/repository order): ties between\n * two policy-bound grants on equal capped reach are broken by higher uncapped reach, then a\n * propagatable policy (one with an id) over an id-less composite that would fail closed, then\n * lexicographic policy id.\n */\nfunction selectGrantForRequest(\n grants: PermissionGrant[],\n requested: `${RealmScope}`,\n): PermissionGrant {\n return grants.reduce((best, grant) => (isGrantPreferred(grant, best, requested) ? grant : best));\n}\n\n/** True when `candidate` is a strictly better propagation source than `incumbent` for `requested`. */\nfunction isGrantPreferred(\n candidate: PermissionGrant,\n incumbent: PermissionGrant,\n requested: `${RealmScope}`,\n): boolean {\n const byCapped = compareRealmScope(\n minRealmScope([candidate.realm_scope, requested]),\n minRealmScope([incumbent.realm_scope, requested]),\n );\n if (byCapped !== 0) {\n return byCapped > 0;\n }\n\n // Least restrictive: a policy-free grant beats a policy-bound one on equal capped reach.\n if (!candidate.policy !== !incumbent.policy) {\n return !candidate.policy;\n }\n\n // Deterministic tie-break for two policy-bound grants on equal capped reach.\n const byUncapped = compareRealmScope(candidate.realm_scope, incumbent.realm_scope);\n if (byUncapped !== 0) {\n return byUncapped > 0;\n }\n\n // Prefer a propagatable policy (has an id) over an id-less composite that would fail closed.\n const candidateId = candidate.policy && isPolicy(candidate.policy) ? candidate.policy.id : undefined;\n const incumbentId = incumbent.policy && isPolicy(incumbent.policy) ? incumbent.policy.id : undefined;\n if (candidateId !== incumbentId) {\n if (typeof candidateId === 'undefined') {\n return false;\n }\n if (typeof incumbentId === 'undefined') {\n return true;\n }\n return candidateId < incumbentId;\n }\n\n return false;\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Policy } from '@authup/core-kit';
|
|
2
|
-
import type { IdentityPolicyData, PermissionPolicyBinding } from '@authup/access';
|
|
2
|
+
import type { IdentityPolicyData, PermissionPolicyBinding, RealmScope } from '@authup/access';
|
|
3
3
|
import type { IClientRepository } from '../../entities/client/types.ts';
|
|
4
4
|
import type { IRobotRepository } from '../../entities/robot/types.ts';
|
|
5
5
|
import type { IRoleRepository } from '../../entities/role/types.ts';
|
|
@@ -9,11 +9,31 @@ export type ResolveJunctionPolicyOptions = {
|
|
|
9
9
|
name: string;
|
|
10
10
|
realmId?: string | null;
|
|
11
11
|
clientId?: string | null;
|
|
12
|
+
/**
|
|
13
|
+
* The realm reach the junction is requested to confer (default `own`). The actor's
|
|
14
|
+
* grant disjunction is selected RELATIVE to this request: the grant chosen is the one
|
|
15
|
+
* that confers the least-restrictive junction once capped to `realmScope`, not the
|
|
16
|
+
* actor's absolute most-permissive grant. Lets a mixed-grant actor propagate a
|
|
17
|
+
* policy-free `own` grant for an `own` request even while holding a wider policy-bound
|
|
18
|
+
* grant (#3160).
|
|
19
|
+
*/
|
|
20
|
+
realmScope?: `${RealmScope}`;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The actor's grant SELECTED for the requested reach (`ResolveJunctionPolicyOptions.realmScope`):
|
|
24
|
+
* the policy to inherit (if any) and the grant's UNCAPPED `realmScope`. Returned uncapped on
|
|
25
|
+
* purpose — the consumer applies the `min(requested, realmScope)` cap itself, and the uncapped
|
|
26
|
+
* reach distinguishes a genuinely unrestricted actor (see `applyJunctionCreateGrant` /
|
|
27
|
+
* `buildJunctionUpdateData`). This is not a global ceiling; it is request-relative (#3160).
|
|
28
|
+
*/
|
|
29
|
+
export type ResolveJunctionGrantResult = {
|
|
30
|
+
policy?: Policy;
|
|
31
|
+
realmScope: `${RealmScope}`;
|
|
12
32
|
};
|
|
13
33
|
export interface IIdentityPermissionProvider {
|
|
14
34
|
getFor(identity: IdentityPolicyData): Promise<PermissionPolicyBinding[]>;
|
|
15
35
|
isSuperset(parent: IdentityPolicyData, child: IdentityPolicyData): Promise<boolean>;
|
|
16
|
-
|
|
36
|
+
resolveJunctionGrant(identity: IdentityPolicyData, options: ResolveJunctionPolicyOptions): Promise<ResolveJunctionGrantResult>;
|
|
17
37
|
}
|
|
18
38
|
export type IdentityPermissionProviderContext = {
|
|
19
39
|
clientRepository: IClientRepository;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/identity/permission/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EACR,kBAAkB,EAClB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/identity/permission/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EACR,kBAAkB,EAClB,uBAAuB,EACvB,UAAU,EACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAE9D,MAAM,MAAM,4BAA4B,GAAG;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,GAAG,UAAU,EAAE,CAAC;CAChC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,GAAG,UAAU,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,WAAW,2BAA2B;IACxC,MAAM,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAAC;IACzE,UAAU,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAClI;AAED,MAAM,MAAM,iCAAiC,GAAG;IAC5C,gBAAgB,EAAE,iBAAiB,CAAC;IACpC,cAAc,EAAE,eAAe,CAAC;IAChC,eAAe,EAAE,gBAAgB,CAAC;IAClC,cAAc,EAAE,eAAe,CAAC;IAChC,YAAY,EAAE,qBAAqB,CAAC;CACvC,CAAC"}
|
package/dist/core/index.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import { SessionManager } from "./authentication/session/module.mjs";
|
|
|
13
13
|
import "./authentication/index.mjs";
|
|
14
14
|
import { ClientService } from "./entities/client/service.mjs";
|
|
15
15
|
import { WebClientProvisioner, buildWebClientAttributes } from "./entities/client/web-client.mjs";
|
|
16
|
+
import { applyJunctionCreateGrant, buildJunctionUpdateData } from "./identity/permission/junction-grant.mjs";
|
|
16
17
|
import { ClientPermissionService } from "./entities/client-permission/service.mjs";
|
|
17
18
|
import { ClientRoleService } from "./entities/client-role/service.mjs";
|
|
18
19
|
import { ClientScopeService } from "./entities/client-scope/service.mjs";
|
|
@@ -114,4 +115,4 @@ import { ScopeProvisioningSynchronizer } from "./provisioning/synchronizer/scope
|
|
|
114
115
|
import { UserProvisioningSynchronizer } from "./provisioning/synchronizer/user/module.mjs";
|
|
115
116
|
import "./provisioning/index.mjs";
|
|
116
117
|
import "./security/index.mjs";
|
|
117
|
-
export { BaseCredentialsAuthenticator, ClientAuthenticator, ClientCredentialsGrant, ClientCredentialsService, ClientPermissionService, ClientProvisioningSynchronizer, ClientProvisioningValidator, ClientRoleService, ClientScopeService, ClientService, CredentialsAuthenticator, GraphProvisioningSynchronizer, IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN, IdentityGrantType, IdentityPermissionProvider, IdentityProviderAccountBaseMapper, IdentityProviderAccountManager, IdentityProviderAttributeMapper, IdentityProviderFacebookAuthenticator, IdentityProviderGithubAuthenticator, IdentityProviderGoogleAuthenticator, IdentityProviderInstagramAuthenticator, IdentityProviderLdapAuthenticator, IdentityProviderLdapCollectionAuthenticator, IdentityProviderMapperOperation, IdentityProviderOAuth2Authenticator, IdentityProviderOpenIDAuthenticator, IdentityProviderPaypalAuthenticator, IdentityProviderPermissionMapper, IdentityProviderRoleMapper, IdentityProviderRoleMappingService, IdentityResolver, IdentityRoleProvider, MAIL_TEMPLATE_REGISTRY, MailTemplateName, MailTemplateRenderer, OAuth2AccessTokenIssuer, OAuth2Authorization, OAuth2AuthorizationCodeIssuer, OAuth2AuthorizationCodeRequestValidator, OAuth2AuthorizationCodeRequestVerifier, OAuth2AuthorizationCodeVerifier, OAuth2AuthorizationStateManager, OAuth2AuthorizeGrant, OAuth2ClientAuthenticator, OAuth2OpenIDClaimsBuilder, OAuth2OpenIDTokenIssuer, OAuth2RefreshTokenGrant, OAuth2RefreshTokenIssuer, OAuth2ScopeAttributesResolver, OAuth2TokenRevoker, OAuth2TokenSigner, OAuth2TokenVerifier, PASSWORD_RESET_EXPIRES_IN_MINUTES, PasswordGrantType, PasswordRecoveryService, PermissionBindingPolicyEvaluator, PermissionCheckerService, PermissionPolicyService, PermissionProvisioningSynchronizer, PermissionProvisioningValidator, PermissionService, PolicyCheckerService, PolicyEngine, PolicyProvisioningSynchronizer, PolicyService, ProvisioningEntityResolver, ProvisioningEntityStrategyType, ProvisioningJunctionSynchronizer, ProvisioningStrategyValidator, RealmProvisioningSynchronizer, RealmProvisioningValidator, RealmService, RegistrationService, RobotAuthenticator, RobotCredentialsGrant, RobotCredentialsService, RobotPermissionService, RobotProvisioningSynchronizer, RobotProvisioningValidator, RobotRoleService, RobotService, RoleAttributeService, RolePermissionService, RoleProvisioningSynchronizer, RoleProvisioningValidator, RoleService, RootProvisioningValidator, ScopeProvisioningSynchronizer, ScopeProvisioningValidator, ScopeService, SessionManager, UserAttributeService, UserAuthenticator, UserCredentialsService, UserPermissionService, UserProvisioningSynchronizer, UserProvisioningValidator, UserRoleService, UserService, WebClientProvisioner, base64URLEncode, buildOAuth2BearerTokenResponse, buildOAuth2CodeChallenge, buildOAuth2TokenHash, buildWebClientAttributes, createIdentityProviderOAuth2Authenticator, defineMailTemplate, generateOAuth2CodeVerifier, normalizeEntityProvisioningStrategy };
|
|
118
|
+
export { BaseCredentialsAuthenticator, ClientAuthenticator, ClientCredentialsGrant, ClientCredentialsService, ClientPermissionService, ClientProvisioningSynchronizer, ClientProvisioningValidator, ClientRoleService, ClientScopeService, ClientService, CredentialsAuthenticator, GraphProvisioningSynchronizer, IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN, IdentityGrantType, IdentityPermissionProvider, IdentityProviderAccountBaseMapper, IdentityProviderAccountManager, IdentityProviderAttributeMapper, IdentityProviderFacebookAuthenticator, IdentityProviderGithubAuthenticator, IdentityProviderGoogleAuthenticator, IdentityProviderInstagramAuthenticator, IdentityProviderLdapAuthenticator, IdentityProviderLdapCollectionAuthenticator, IdentityProviderMapperOperation, IdentityProviderOAuth2Authenticator, IdentityProviderOpenIDAuthenticator, IdentityProviderPaypalAuthenticator, IdentityProviderPermissionMapper, IdentityProviderRoleMapper, IdentityProviderRoleMappingService, IdentityResolver, IdentityRoleProvider, MAIL_TEMPLATE_REGISTRY, MailTemplateName, MailTemplateRenderer, OAuth2AccessTokenIssuer, OAuth2Authorization, OAuth2AuthorizationCodeIssuer, OAuth2AuthorizationCodeRequestValidator, OAuth2AuthorizationCodeRequestVerifier, OAuth2AuthorizationCodeVerifier, OAuth2AuthorizationStateManager, OAuth2AuthorizeGrant, OAuth2ClientAuthenticator, OAuth2OpenIDClaimsBuilder, OAuth2OpenIDTokenIssuer, OAuth2RefreshTokenGrant, OAuth2RefreshTokenIssuer, OAuth2ScopeAttributesResolver, OAuth2TokenRevoker, OAuth2TokenSigner, OAuth2TokenVerifier, PASSWORD_RESET_EXPIRES_IN_MINUTES, PasswordGrantType, PasswordRecoveryService, PermissionBindingPolicyEvaluator, PermissionCheckerService, PermissionPolicyService, PermissionProvisioningSynchronizer, PermissionProvisioningValidator, PermissionService, PolicyCheckerService, PolicyEngine, PolicyProvisioningSynchronizer, PolicyService, ProvisioningEntityResolver, ProvisioningEntityStrategyType, ProvisioningJunctionSynchronizer, ProvisioningStrategyValidator, RealmProvisioningSynchronizer, RealmProvisioningValidator, RealmService, RegistrationService, RobotAuthenticator, RobotCredentialsGrant, RobotCredentialsService, RobotPermissionService, RobotProvisioningSynchronizer, RobotProvisioningValidator, RobotRoleService, RobotService, RoleAttributeService, RolePermissionService, RoleProvisioningSynchronizer, RoleProvisioningValidator, RoleService, RootProvisioningValidator, ScopeProvisioningSynchronizer, ScopeProvisioningValidator, ScopeService, SessionManager, UserAttributeService, UserAuthenticator, UserCredentialsService, UserPermissionService, UserProvisioningSynchronizer, UserProvisioningValidator, UserRoleService, UserService, WebClientProvisioner, applyJunctionCreateGrant, base64URLEncode, buildJunctionUpdateData, buildOAuth2BearerTokenResponse, buildOAuth2CodeChallenge, buildOAuth2TokenHash, buildWebClientAttributes, createIdentityProviderOAuth2Authenticator, defineMailTemplate, generateOAuth2CodeVerifier, normalizeEntityProvisioningStrategy };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RealmScope } from '@authup/access';
|
|
1
2
|
import type { Role } from '@authup/core-kit';
|
|
2
3
|
import type { BaseProvisioningEntity } from '../types.ts';
|
|
3
4
|
export type RoleProvisioningRelations = {
|
|
@@ -10,14 +11,16 @@ export type RoleProvisioningRelations = {
|
|
|
10
11
|
*/
|
|
11
12
|
globalPermissionsExclude?: string[];
|
|
12
13
|
/**
|
|
13
|
-
* Default
|
|
14
|
+
* Default realm_scope (own | ownOrNull | any) to stamp on each
|
|
15
|
+
* role-permission junction entry. Realm reach is a coarse, actor-relative
|
|
16
|
+
* enum on the junction (not a policy).
|
|
14
17
|
*/
|
|
15
|
-
|
|
18
|
+
globalPermissionsRealmScope?: RealmScope;
|
|
16
19
|
/**
|
|
17
|
-
* Per-permission
|
|
18
|
-
* that should use that
|
|
20
|
+
* Per-permission realm_scope overrides. Maps a realm_scope value to the
|
|
21
|
+
* permission names that should use that scope instead of the default.
|
|
19
22
|
*/
|
|
20
|
-
|
|
23
|
+
globalPermissionsRealmScopeOverrides?: Partial<Record<RealmScope, string[]>>;
|
|
21
24
|
/**
|
|
22
25
|
* Assign role to realm permissions.
|
|
23
26
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/entities/role/types.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,yBAAyB,GAAG;IACpC;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B;;OAEG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpC
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/entities/role/types.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,yBAAyB,GAAG;IACpC;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B;;OAEG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpC;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,UAAU,CAAC;IAEzC;;;OAGG;IACH,oCAAoC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAE7E;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,sBAAsB,CAAC,IAAI,CAAC,GAAG;IAChE,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,SAAS,CAAC,EAAE,yBAAyB,CAAA;CACxC,CAAC"}
|
|
@@ -2,5 +2,8 @@ import type { IProvisioningSynchronizer } from '../types.ts';
|
|
|
2
2
|
export declare abstract class BaseProvisioningSynchronizer<T> implements IProvisioningSynchronizer<T> {
|
|
3
3
|
synchronizeMany(input: T[]): Promise<T[]>;
|
|
4
4
|
abstract synchronize(input: T): Promise<T>;
|
|
5
|
+
protected canonicalizeName(attributes: {
|
|
6
|
+
name?: string | null;
|
|
7
|
+
} | undefined): void;
|
|
5
8
|
}
|
|
6
9
|
//# sourceMappingURL=base.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/core/provisioning/synchronizer/base.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAE7D,8BAAsB,4BAA4B,CAAC,CAAC,CAAE,YAAW,yBAAyB,CAAC,CAAC,CAAC;IAGnF,eAAe,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAQ/C,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/core/provisioning/synchronizer/base.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAE7D,8BAAsB,4BAA4B,CAAC,CAAC,CAAE,YAAW,yBAAyB,CAAC,CAAC,CAAC;IAGnF,eAAe,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAQ/C,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAM1C,SAAS,CAAC,gBAAgB,CAAC,UAAU,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,SAAS,GAAG,IAAI;CAKrF"}
|
|
@@ -8,6 +8,9 @@ var BaseProvisioningSynchronizer = class {
|
|
|
8
8
|
for (const entity of input) output.push(await this.synchronize(entity));
|
|
9
9
|
return output;
|
|
10
10
|
}
|
|
11
|
+
canonicalizeName(attributes) {
|
|
12
|
+
if (attributes && typeof attributes.name === "string") attributes.name = attributes.name.trim().toLowerCase();
|
|
13
|
+
}
|
|
11
14
|
};
|
|
12
15
|
//#endregion
|
|
13
16
|
export { BaseProvisioningSynchronizer };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.mjs","names":["BaseProvisioningSynchronizer","synchronizeMany","input","output","entity","push","synchronize"],"sources":["../../../../src/core/provisioning/synchronizer/base.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { IProvisioningSynchronizer } from '../types.ts';\n\nexport abstract class BaseProvisioningSynchronizer<T> implements IProvisioningSynchronizer<T> {\n // Sequential to avoid race conditions on concurrent upserts.\n // Can be switched to Promise.all() if callers guarantee unique inputs.\n async synchronizeMany(input: T[]): Promise<T[]> {\n const output: T[] = [];\n for (const entity of input) {\n output.push(await this.synchronize(entity));\n }\n return output;\n }\n\n abstract synchronize(input: T): Promise<T>;\n}\n"],"mappings":";;;;AASA,IAAsBA,+BAAtB,MAAsBA;CAGlB,MAAMC,gBAAgBC,OAA0B;EAC5C,MAAMC,SAAc,CAAA;EACpB,KAAK,MAAMC,UAAUF,OACjBC,OAAOE,KAAK,MAAM,KAAKC,YAAYF,MAAAA,CAAAA;EAEvC,OAAOD;CACX;
|
|
1
|
+
{"version":3,"file":"base.mjs","names":["BaseProvisioningSynchronizer","synchronizeMany","input","output","entity","push","synchronize","canonicalizeName","attributes","name","trim","toLowerCase"],"sources":["../../../../src/core/provisioning/synchronizer/base.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { IProvisioningSynchronizer } from '../types.ts';\n\nexport abstract class BaseProvisioningSynchronizer<T> implements IProvisioningSynchronizer<T> {\n // Sequential to avoid race conditions on concurrent upserts.\n // Can be switched to Promise.all() if callers guarantee unique inputs.\n async synchronizeMany(input: T[]): Promise<T[]> {\n const output: T[] = [];\n for (const entity of input) {\n output.push(await this.synchronize(entity));\n }\n return output;\n }\n\n abstract synchronize(input: T): Promise<T>;\n\n // canonical identifier form: provisioning sources may carry raw names\n // (the file-source entity validators run group-less, so the validator\n // transforms don't apply); lookups against canonically stored rows\n // and canonical persistence both require it.\n protected canonicalizeName(attributes: { name?: string | null } | undefined): void {\n if (attributes && typeof attributes.name === 'string') {\n attributes.name = attributes.name.trim().toLowerCase();\n }\n }\n}\n"],"mappings":";;;;AASA,IAAsBA,+BAAtB,MAAsBA;CAGlB,MAAMC,gBAAgBC,OAA0B;EAC5C,MAAMC,SAAc,CAAA;EACpB,KAAK,MAAMC,UAAUF,OACjBC,OAAOE,KAAK,MAAM,KAAKC,YAAYF,MAAAA,CAAAA;EAEvC,OAAOD;CACX;CAQUI,iBAAiBC,YAAwD;EAC/E,IAAIA,cAAc,OAAOA,WAAWC,SAAS,UACzCD,WAAWC,OAAOD,WAAWC,KAAKC,KAAI,CAAA,CAAGC,YAAW;CAE5D;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/synchronizer/client/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACR,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,IAAI,EACP,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,YAAY,CAAC;AAExE,qBAAa,8BAA+B,SAAQ,4BAA4B,CAAC,wBAAwB,CAAC;IACtG,SAAS,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAE9C,SAAS,CAAC,kBAAkB,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAErE,SAAS,CAAC,YAAY,EAAE,0BAA0B,CAAC,IAAI,CAAC,CAAC;IAEzD,SAAS,CAAC,kBAAkB,EAAE,gCAAgC,CAAC,gBAAgB,CAAC,CAAC;IAEjF,SAAS,CAAC,YAAY,EAAE,gCAAgC,CAAC,UAAU,CAAC,CAAC;IAErE,SAAS,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,4BAA4B,CAAC,CAAC;IAE1F,SAAS,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,sBAAsB,CAAC,CAAC;gBAElE,GAAG,EAAE,qCAAqC;IAuBhD,WAAW,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../src/core/provisioning/synchronizer/client/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACR,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,IAAI,EACP,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,YAAY,CAAC;AAExE,qBAAa,8BAA+B,SAAQ,4BAA4B,CAAC,wBAAwB,CAAC;IACtG,SAAS,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAE9C,SAAS,CAAC,kBAAkB,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAErE,SAAS,CAAC,YAAY,EAAE,0BAA0B,CAAC,IAAI,CAAC,CAAC;IAEzD,SAAS,CAAC,kBAAkB,EAAE,gCAAgC,CAAC,gBAAgB,CAAC,CAAC;IAEjF,SAAS,CAAC,YAAY,EAAE,gCAAgC,CAAC,UAAU,CAAC,CAAC;IAErE,SAAS,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,4BAA4B,CAAC,CAAC;IAE1F,SAAS,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,sBAAsB,CAAC,CAAC;gBAElE,GAAG,EAAE,qCAAqC;IAuBhD,WAAW,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAC;CA+GxF"}
|
|
@@ -36,6 +36,7 @@ var ClientProvisioningSynchronizer = class extends BaseProvisioningSynchronizer
|
|
|
36
36
|
this.roleSynchronizer = ctx.roleSynchronizer;
|
|
37
37
|
}
|
|
38
38
|
async synchronize(input) {
|
|
39
|
+
this.canonicalizeName(input.attributes);
|
|
39
40
|
const strategy = normalizeEntityProvisioningStrategy(input.strategy);
|
|
40
41
|
let attributes = await this.clientRepository.findOneBy({
|
|
41
42
|
name: input.attributes.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["pickRecord","ProvisioningEntityStrategyType","normalizeEntityProvisioningStrategy","BaseProvisioningSynchronizer","ProvisioningEntityResolver","ProvisioningJunctionSynchronizer","ClientProvisioningSynchronizer","clientRepository","permissionResolver","roleResolver","permissionJunction","roleJunction","permissionSynchronizer","roleSynchronizer","ctx","permissionRepository","roleRepository","repository","clientPermissionRepository","ownerKey","ownerRealmKey","clientRoleRepository","synchronize","input","
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["pickRecord","ProvisioningEntityStrategyType","normalizeEntityProvisioningStrategy","BaseProvisioningSynchronizer","ProvisioningEntityResolver","ProvisioningJunctionSynchronizer","ClientProvisioningSynchronizer","clientRepository","permissionResolver","roleResolver","permissionJunction","roleJunction","permissionSynchronizer","roleSynchronizer","ctx","permissionRepository","roleRepository","repository","clientPermissionRepository","ownerKey","ownerRealmKey","clientRoleRepository","synchronize","input","canonicalizeName","attributes","strategy","findOneBy","name","realm_id","type","ABSENT","remove","MERGE","merge","save","REPLACE","id","create","permissions","resolveGlobal","relations","globalPermissions","resolveRealm","realmPermissions","length","roles","globalRoles","realmRoles","children","map","child","client_id","client","synchronizeMany"],"sources":["../../../../../src/core/provisioning/synchronizer/client/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2026-2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type {\n ClientPermission, \n ClientRole, \n Permission, \n Role,\n} from '@authup/core-kit';\nimport { pickRecord } from '@authup/kit';\nimport type { IClientRepository } from '../../../entities/index.ts';\nimport type { ClientProvisioningEntity } from '../../entities/client';\nimport type { PermissionProvisioningEntity } from '../../entities/permission';\nimport type { RoleProvisioningEntity } from '../../entities/role';\nimport { ProvisioningEntityStrategyType, normalizeEntityProvisioningStrategy } from '../../strategy/index.ts';\nimport type { IProvisioningSynchronizer } from '../../types.ts';\nimport { BaseProvisioningSynchronizer } from '../base.ts';\nimport { ProvisioningEntityResolver } from '../entity-resolver.ts';\nimport { ProvisioningJunctionSynchronizer } from '../junction-synchronizer.ts';\nimport type { ClientProvisioningSynchronizerContext } from './types.ts';\n\nexport class ClientProvisioningSynchronizer extends BaseProvisioningSynchronizer<ClientProvisioningEntity> {\n protected clientRepository: IClientRepository;\n\n protected permissionResolver: ProvisioningEntityResolver<Permission>;\n\n protected roleResolver: ProvisioningEntityResolver<Role>;\n\n protected permissionJunction: ProvisioningJunctionSynchronizer<ClientPermission>;\n\n protected roleJunction: ProvisioningJunctionSynchronizer<ClientRole>;\n\n protected permissionSynchronizer: IProvisioningSynchronizer<PermissionProvisioningEntity>;\n\n protected roleSynchronizer: IProvisioningSynchronizer<RoleProvisioningEntity>;\n\n constructor(ctx: ClientProvisioningSynchronizerContext) {\n super();\n\n this.clientRepository = ctx.clientRepository;\n\n this.permissionResolver = new ProvisioningEntityResolver(ctx.permissionRepository);\n this.roleResolver = new ProvisioningEntityResolver(ctx.roleRepository);\n\n this.permissionJunction = new ProvisioningJunctionSynchronizer({\n repository: ctx.clientPermissionRepository,\n ownerKey: 'client_id',\n ownerRealmKey: 'client_realm_id',\n });\n this.roleJunction = new ProvisioningJunctionSynchronizer({\n repository: ctx.clientRoleRepository,\n ownerKey: 'client_id',\n ownerRealmKey: 'client_realm_id',\n });\n\n this.permissionSynchronizer = ctx.permissionSynchronizer;\n this.roleSynchronizer = ctx.roleSynchronizer;\n }\n\n async synchronize(input: ClientProvisioningEntity): Promise<ClientProvisioningEntity> {\n this.canonicalizeName(input.attributes);\n\n const strategy = normalizeEntityProvisioningStrategy(input.strategy);\n\n let attributes = await this.clientRepository.findOneBy({\n name: input.attributes.name,\n realm_id: input.attributes.realm_id || null,\n });\n\n if (strategy.type === ProvisioningEntityStrategyType.ABSENT) {\n if (attributes) {\n await this.clientRepository.remove(attributes);\n }\n return {\n ...input,\n attributes: attributes || input.attributes, \n };\n }\n\n if (attributes) {\n switch (strategy.type) {\n case ProvisioningEntityStrategyType.MERGE:\n attributes = this.clientRepository.merge(\n attributes,\n strategy.attributes ?\n pickRecord(input.attributes, strategy.attributes) :\n input.attributes,\n );\n attributes = await this.clientRepository.save(attributes);\n break;\n case ProvisioningEntityStrategyType.REPLACE:\n input.attributes.id = attributes.id;\n attributes = await this.clientRepository.save(this.clientRepository.create(input.attributes));\n break;\n }\n } else {\n attributes = await this.clientRepository.save(this.clientRepository.create(input.attributes));\n }\n\n // Permissions (Global + Realm)\n const permissions = [\n ...await this.permissionResolver.resolveGlobal(\n input.relations && input.relations.globalPermissions,\n ),\n ...(attributes.realm_id ?\n await this.permissionResolver.resolveRealm(\n input.relations && input.relations.realmPermissions,\n attributes.realm_id,\n ) :\n []),\n ];\n\n if (permissions.length > 0) {\n await this.permissionJunction.synchronize(\n attributes,\n permissions,\n 'permission_id',\n 'permission_realm_id',\n );\n }\n\n // Roles (Global + Realm)\n const roles = [\n ...await this.roleResolver.resolveGlobal(\n input.relations && input.relations.globalRoles,\n ),\n ...(attributes.realm_id ?\n await this.roleResolver.resolveRealm(\n input.relations && input.relations.realmRoles,\n attributes.realm_id,\n ) :\n []),\n ];\n\n if (roles.length > 0) {\n await this.roleJunction.synchronize(\n attributes,\n roles,\n 'role_id',\n 'role_realm_id',\n );\n }\n\n // Containers\n\n if (input.relations && input.relations.permissions) {\n const children = input.relations.permissions.map((child) => {\n child.attributes.client_id = attributes.id;\n child.attributes.client = attributes;\n return child;\n });\n\n await this.permissionSynchronizer.synchronizeMany(children);\n }\n\n if (input.relations && input.relations.roles) {\n const children = input.relations.roles.map((child) => {\n child.attributes.client_id = attributes.id;\n child.attributes.client = attributes;\n return child;\n });\n\n await this.roleSynchronizer.synchronizeMany(children);\n }\n\n return {\n ...input,\n attributes,\n };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-resolver.d.ts","sourceRoot":"","sources":["../../../../src/core/provisioning/synchronizer/entity-resolver.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,qBAAa,0BAA0B,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa;IAC3E,SAAS,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;gBAE/B,UAAU,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAItC,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"entity-resolver.d.ts","sourceRoot":"","sources":["../../../../src/core/provisioning/synchronizer/entity-resolver.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,qBAAa,0BAA0B,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa;IAC3E,SAAS,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;gBAE/B,UAAU,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAItC,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAsB7C,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAsBxE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;CAqBpG"}
|
|
@@ -9,6 +9,7 @@ var ProvisioningEntityResolver = class {
|
|
|
9
9
|
}
|
|
10
10
|
async resolveGlobal(names) {
|
|
11
11
|
if (!names || names.length === 0) return [];
|
|
12
|
+
names = names.map((name) => name.trim().toLowerCase());
|
|
12
13
|
if (names.includes("*")) return this.repository.findManyBy({
|
|
13
14
|
realm_id: null,
|
|
14
15
|
client_id: null
|
|
@@ -21,6 +22,7 @@ var ProvisioningEntityResolver = class {
|
|
|
21
22
|
}
|
|
22
23
|
async resolveRealm(names, realmId) {
|
|
23
24
|
if (!names || names.length === 0) return [];
|
|
25
|
+
names = names.map((name) => name.trim().toLowerCase());
|
|
24
26
|
if (names.includes("*")) return this.repository.findManyBy({
|
|
25
27
|
realm_id: realmId,
|
|
26
28
|
client_id: null
|
|
@@ -33,6 +35,7 @@ var ProvisioningEntityResolver = class {
|
|
|
33
35
|
}
|
|
34
36
|
async resolveClient(names, realmId, clientId) {
|
|
35
37
|
if (!names || names.length === 0) return [];
|
|
38
|
+
names = names.map((name) => name.trim().toLowerCase());
|
|
36
39
|
if (names.includes("*")) return this.repository.findManyBy({
|
|
37
40
|
realm_id: realmId,
|
|
38
41
|
client_id: clientId
|