@owlmeans/server-iam 0.1.18-rc.54 → 0.1.18-rc.56
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 +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-iam/SKILL.md +1 -1
- package/build/append.d.ts +1 -5
- package/build/append.d.ts.map +1 -1
- package/build/append.js.map +1 -1
- package/build/consts.local.d.ts +3 -0
- package/build/consts.local.d.ts.map +1 -0
- package/build/consts.local.js +3 -0
- package/build/consts.local.js.map +1 -0
- package/build/gate.d.ts +1 -12
- package/build/gate.d.ts.map +1 -1
- package/build/gate.js +28 -13
- package/build/gate.js.map +1 -1
- package/build/index.d.ts +2 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/runtime.d.ts +2 -30
- package/build/runtime.d.ts.map +1 -1
- package/build/runtime.js +1 -2
- package/build/runtime.js.map +1 -1
- package/build/types.d.ts +42 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/types.local.d.ts +15 -0
- package/build/types.local.d.ts.map +1 -0
- package/build/types.local.js +2 -0
- package/build/types.local.js.map +1 -0
- package/package.json +11 -10
- package/src/append.ts +1 -4
- package/src/consts.local.ts +2 -0
- package/src/gate.ts +33 -35
- package/src/index.ts +2 -1
- package/src/runtime.ts +5 -53
- package/src/types.local.ts +18 -0
- package/src/types.ts +43 -0
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ One-call OIDC RP wiring and IAM gate for OwlMeans servers — `appendIam()` and
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
bun add @owlmeans/server-iam@^0.1.18-rc.
|
|
17
|
+
bun add @owlmeans/server-iam@^0.1.18-rc.56
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
@@ -47,7 +47,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
47
47
|
your project's skill store (`.agents/skills/`):
|
|
48
48
|
|
|
49
49
|
```sh
|
|
50
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
50
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.48
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/server-iam",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.56",
|
|
5
|
+
"generatedAt": "2026-10-05T08:32:19.100Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -8,7 +8,7 @@ metadata:
|
|
|
8
8
|
|
|
9
9
|
# Using `@owlmeans/server-iam`
|
|
10
10
|
|
|
11
|
-
**Install:** `"@owlmeans/server-iam": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/server-iam": "^0.1.18-rc.56"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
Boilerplate-less server-side consumer of the OwlMeans IAM. One call wires the OIDC RP stack and the
|
|
14
14
|
IAM gate; the consumer never knows which IAM backend (Keycloak or integrated) is active. For a
|
package/build/append.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { WithSharedConfig } from '@owlmeans/oidc';
|
|
3
|
-
type IamServerConfig = ServerConfig & WithSharedConfig;
|
|
4
|
-
type IamServerContext<C extends IamServerConfig = IamServerConfig> = ServerContext<C>;
|
|
1
|
+
import type { IamServerConfig, IamServerContext } from './types.local.js';
|
|
5
2
|
/**
|
|
6
3
|
* One-call OIDC RP setup for a server context.
|
|
7
4
|
*
|
|
@@ -15,5 +12,4 @@ type IamServerContext<C extends IamServerConfig = IamServerConfig> = ServerConte
|
|
|
15
12
|
* context.cfg.oidc.providers[] — populate it before calling appendIam().
|
|
16
13
|
*/
|
|
17
14
|
export declare const appendIam: <C extends IamServerConfig, T extends IamServerContext<C>>(context: T) => T;
|
|
18
|
-
export {};
|
|
19
15
|
//# sourceMappingURL=append.d.ts.map
|
package/build/append.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAGzE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,eAAe,EAAE,CAAC,SAAS,gBAAgB,CAAC,CAAC,CAAC,WACvE,CAAC,KACT,CAQF,CAAA"}
|
package/build/append.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"append.js","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"append.js","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAC1G,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAIvC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,OAAU,EACP,EAAE;IACL,OAAO,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAA;IAChD,OAAO,CAAC,eAAe,CAAC,uBAAuB,EAAE,CAAC,CAAA;IAClD,sEAAsE;IACtE,gEAAgE;IAChE,OAAO,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC,CAAA;IACtC,eAAe,CAAO,OAAO,CAAC,CAAA;IAC9B,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,eAAO,MAAM,kBAAkB,kBAAkB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAA"}
|
package/build/gate.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GateService } from '@owlmeans/entrypoint';
|
|
2
|
+
import type { IamGateOptions } from './types.js';
|
|
2
3
|
/**
|
|
3
4
|
* The gate-param grammar lives in `@owlmeans/iam` so the browser, the adapters and code-generation
|
|
4
5
|
* tooling can all read it. Re-exported here because this module was its home and is the documented
|
|
@@ -6,18 +7,6 @@ import type { GateService } from '@owlmeans/entrypoint';
|
|
|
6
7
|
*/
|
|
7
8
|
export { RESOURCE_PARAM_SEPARATOR, RESOURCE_SOURCE_SEPARATOR, RESOURCE_PATH_SEPARATOR, GateParamSource, GateParamErrorCode, GateResolutionFailure, parseGateParam, parseGateSelector, formatGateParam, resolveGateResource, validateGateParams } from '@owlmeans/iam';
|
|
8
9
|
export type { ParsedGateParam, GateResourceSelector, GateParamAudit } from '@owlmeans/iam';
|
|
9
|
-
export interface IamGateOptions {
|
|
10
|
-
/**
|
|
11
|
-
* Refuse a resource-scoped param on the UMA2 fallback path instead of widening it to a
|
|
12
|
-
* project-wide check.
|
|
13
|
-
*
|
|
14
|
-
* Off by default, and deliberately so. A Keycloak-backed deployment cannot hold a resource-scoped
|
|
15
|
-
* grant at all — the adapter throws `IamUnsupported('resource-scoped-grant')` — so denying would
|
|
16
|
-
* lock every user out of every scoped endpoint rather than tightening anything. Turn it on only
|
|
17
|
-
* where the resulting refusals are the intended outcome.
|
|
18
|
-
*/
|
|
19
|
-
strictResourceScope?: boolean;
|
|
20
|
-
}
|
|
21
10
|
/**
|
|
22
11
|
* IAM gate: claims-first with UMA2 fallback. Registered under the OIDC_GATE alias by
|
|
23
12
|
* appendIam() so target code never knows which IAM backend is active.
|
package/build/gate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAqC,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAqC,MAAM,sBAAsB,CAAA;AAM1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD;;;;GAIG;AACH,OAAO,EACL,wBAAwB,EAAE,yBAAyB,EAAE,uBAAuB,EAC5E,eAAe,EAAE,kBAAkB,EAAE,qBAAqB,EAC1D,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,kBAAkB,EAC5F,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAgF1F;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,WAAW,MAAM,SAAqB,cAAc,KAAG,WAiG9E,CAAA"}
|
package/build/gate.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createLazyService } from '@owlmeans/context';
|
|
2
|
-
import { entitySlugOf } from '@owlmeans/auth';
|
|
2
|
+
import { entitySlugOf, AuthForbidden } from '@owlmeans/auth';
|
|
3
3
|
import { OIDC_GATE } from '@owlmeans/oidc';
|
|
4
|
-
import { AuthForbidden } from '@owlmeans/auth';
|
|
5
4
|
import { createGateModel, extractPermissionSets } from '@owlmeans/server-oidc-rp';
|
|
6
5
|
import { hasPermission, parseGateParam, resolveGateResource, validateGateParams, GateResolutionFailure } from '@owlmeans/iam';
|
|
6
|
+
import { logger, logThrottle } from '@owlmeans/log';
|
|
7
7
|
/**
|
|
8
8
|
* The gate-param grammar lives in `@owlmeans/iam` so the browser, the adapters and code-generation
|
|
9
9
|
* tooling can all read it. Re-exported here because this module was its home and is the documented
|
|
@@ -17,12 +17,26 @@ export { RESOURCE_PARAM_SEPARATOR, RESOURCE_SOURCE_SEPARATOR, RESOURCE_PATH_SEPA
|
|
|
17
17
|
* so an un-deduplicated log turns one typo into the incident.
|
|
18
18
|
*/
|
|
19
19
|
const reported = new Set();
|
|
20
|
-
const
|
|
20
|
+
const log = logger('server-iam:gate');
|
|
21
|
+
const reportOnce = (key, message, data) => {
|
|
21
22
|
if (reported.has(key)) {
|
|
22
23
|
return;
|
|
23
24
|
}
|
|
24
25
|
reported.add(key);
|
|
25
|
-
|
|
26
|
+
log.error(message, data);
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* A refusal of the gate. Logged once a minute per route, reason and subject — a hot endpoint
|
|
30
|
+
* refuses on every request, and one line per window says the same thing.
|
|
31
|
+
*/
|
|
32
|
+
const forbidden = (req, reason, params) => {
|
|
33
|
+
const auth = req.auth;
|
|
34
|
+
if (logThrottle(`access.forbidden\0${req.alias ?? ''}\0${reason}\0${auth?.userId ?? ''}`, 60_000)) {
|
|
35
|
+
log.warn('Access forbidden', {
|
|
36
|
+
alias: req.alias, reason, params, userId: auth?.userId, entitySlug: req.entity?.slug ?? (auth != null ? entitySlugOf(auth) : undefined),
|
|
37
|
+
}, { event: 'access.forbidden' });
|
|
38
|
+
}
|
|
39
|
+
return new AuthForbidden(reason);
|
|
26
40
|
};
|
|
27
41
|
/** Aliases whose declarations have already been checked. */
|
|
28
42
|
const audited = new Set();
|
|
@@ -57,8 +71,9 @@ const auditEntrypoint = (ctx, req, params) => {
|
|
|
57
71
|
...(entrypoint.filter != null ? { filter: entrypoint.filter } : {})
|
|
58
72
|
};
|
|
59
73
|
for (const issue of validateGateParams(params, audit)) {
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
log.error('Gate param is misconfigured', {
|
|
75
|
+
param: issue.param, alias: req.alias, code: issue.code, detail: issue.detail,
|
|
76
|
+
});
|
|
62
77
|
}
|
|
63
78
|
}
|
|
64
79
|
catch {
|
|
@@ -86,7 +101,7 @@ export const makeIamGate = (alias = OIDC_GATE, opts) => {
|
|
|
86
101
|
await service.ready();
|
|
87
102
|
const ctx = service.assertCtx();
|
|
88
103
|
if (req.auth == null) {
|
|
89
|
-
throw
|
|
104
|
+
throw forbidden(req, 'auth', params);
|
|
90
105
|
}
|
|
91
106
|
const auth = req.auth;
|
|
92
107
|
const sets = extractPermissionSets(auth.permissions);
|
|
@@ -124,8 +139,8 @@ export const makeIamGate = (alias = OIDC_GATE, opts) => {
|
|
|
124
139
|
return hasPermission(auth, fixed, { entitySlug });
|
|
125
140
|
});
|
|
126
141
|
if (!granted) {
|
|
127
|
-
structural.forEach(detail => reportOnce(`${req.alias}\0${detail}`,
|
|
128
|
-
throw
|
|
142
|
+
structural.forEach(detail => reportOnce(`${req.alias}\0${detail}`, 'Gate refused a request it could not evaluate', { alias: req.alias, detail }));
|
|
143
|
+
throw forbidden(req, 'permission', params);
|
|
129
144
|
}
|
|
130
145
|
return;
|
|
131
146
|
}
|
|
@@ -133,19 +148,19 @@ export const makeIamGate = (alias = OIDC_GATE, opts) => {
|
|
|
133
148
|
// store a resource-scoped grant, so a scoped param widens to a project-wide check and the same
|
|
134
149
|
// declaration means two different things depending on which backend is active.
|
|
135
150
|
const scoped = params.filter(param => parseGateParam(param).resource != null);
|
|
136
|
-
scoped.forEach(param => reportOnce(`uma2\0${req.alias}\0${param}`,
|
|
137
|
-
+ '
|
|
151
|
+
scoped.forEach(param => reportOnce(`uma2\0${req.alias}\0${param}`, 'Gate param is resource-scoped, but resource scoping is not enforced in UMA2 mode — it is checked as a '
|
|
152
|
+
+ 'project-wide permission', { param, alias: req.alias }));
|
|
138
153
|
const usable = opts?.strictResourceScope === true
|
|
139
154
|
? params.filter(param => parseGateParam(param).resource == null)
|
|
140
155
|
: params;
|
|
141
156
|
if (usable.length < 1) {
|
|
142
|
-
throw
|
|
157
|
+
throw forbidden(req, 'permission', params);
|
|
143
158
|
}
|
|
144
159
|
const stripped = usable.map(param => parseGateParam(param).permission);
|
|
145
160
|
const model = createGateModel(ctx);
|
|
146
161
|
const permissions = await model.loadPermissions(auth, stripped);
|
|
147
162
|
if (permissions.length < 1) {
|
|
148
|
-
throw
|
|
163
|
+
throw forbidden(req, 'permission', params);
|
|
149
164
|
}
|
|
150
165
|
}
|
|
151
166
|
});
|
package/build/gate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ export { ORGANIZATION_REFUSAL, ORGANIZATION_OWNER_REFUSAL } from '@owlmeans/oidc
|
|
|
4
4
|
export * from './consts.js';
|
|
5
5
|
export * from './append.js';
|
|
6
6
|
export * from './gate.js';
|
|
7
|
+
export type * from './types.js';
|
|
7
8
|
export { organizationOf, organizationsOf } from './organization.js';
|
|
8
9
|
export { iamRuntime } from './runtime.js';
|
|
9
|
-
export type { IamRuntimeClient } from './
|
|
10
|
+
export type { IamRuntimeClient } from './types.js';
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,eAAe,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAA;AACjF,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,YAAY,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,eAAe,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAA;AACjF,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,mBAAmB,YAAY,CAAA;AAC/B,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA"}
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAA;AACjF,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAA;AACjF,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AAEzB,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA"}
|
package/build/runtime.d.ts
CHANGED
|
@@ -1,34 +1,6 @@
|
|
|
1
1
|
import type { AbstractRequest } from '@owlmeans/entrypoint';
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
4
|
-
/**
|
|
5
|
-
* The runtime IAM API as the signed-in subject of one request: its organizations, their members,
|
|
6
|
-
* the grantable definitions and the grants. Every call acts as that subject — the provider decides
|
|
7
|
-
* owner and member rights from the access token, never from anything sent here.
|
|
8
|
-
*/
|
|
9
|
-
export interface IamRuntimeClient {
|
|
10
|
-
organizations: {
|
|
11
|
-
list: () => Promise<IamRuntimeOrganization[]>;
|
|
12
|
-
/** The subject becomes the new organization's owner. */
|
|
13
|
-
create: (body?: IamRuntimeOrganizationCreate) => Promise<IamRuntimeOrganization>;
|
|
14
|
-
update: (entitySlug: string, body: IamRuntimeOrganizationUpdate) => Promise<IamRuntimeOrganization>;
|
|
15
|
-
};
|
|
16
|
-
members: {
|
|
17
|
-
list: (entitySlug: string) => Promise<IamRuntimeMember[]>;
|
|
18
|
-
/** Find-or-create by e-mail: adding an address twice answers the same member. */
|
|
19
|
-
add: (entitySlug: string, invite: IamRuntimeMemberInvite) => Promise<IamRuntimeMember>;
|
|
20
|
-
update: (entitySlug: string, profileId: string, update: IamRuntimeMemberUpdate) => Promise<IamRuntimeMember>;
|
|
21
|
-
remove: (entitySlug: string, profileId: string) => Promise<void>;
|
|
22
|
-
};
|
|
23
|
-
permissions: {
|
|
24
|
-
list: (entitySlug: string) => Promise<IamRuntimePermission[]>;
|
|
25
|
-
};
|
|
26
|
-
grants: {
|
|
27
|
-
list: (entitySlug: string, query?: IamRuntimeGrantQuery) => Promise<IamRuntimeGrant[]>;
|
|
28
|
-
assign: (entitySlug: string, grant: IamRuntimeGrantRequest) => Promise<IamRuntimeGrant>;
|
|
29
|
-
revoke: (entitySlug: string, grant: IamRuntimeGrantRequest) => Promise<void>;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
2
|
+
import { type Config, type Context } from '@owlmeans/server-oidc-rp';
|
|
3
|
+
import type { IamRuntimeClient } from './types.js';
|
|
32
4
|
/**
|
|
33
5
|
* A typed client of the provider's runtime IAM API, bound to one request.
|
|
34
6
|
*
|
package/build/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAI3D,OAAO,EAAwC,KAAK,MAAM,EAAE,KAAK,OAAO,EAA0B,MAAM,0BAA0B,CAAA;AAIlI,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAgFlD;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,WACtD,CAAC,WAAW,eAAe,KACnC,gBAsFF,CAAA"}
|
package/build/runtime.js
CHANGED
|
@@ -4,8 +4,7 @@ import { IAM_RUNTIME_ROUTES, IamClientError, IamError } from '@owlmeans/iam';
|
|
|
4
4
|
import { IAM_API_METADATA, ORGANIZATION_OWNER_REFUSAL, ORGANIZATION_REFUSAL } from '@owlmeans/oidc';
|
|
5
5
|
import { DEFAULT_ALIAS as OIDC_CLIENT_SERVICE } from '@owlmeans/server-oidc-rp';
|
|
6
6
|
import { sessionOf } from './organization.js';
|
|
7
|
-
|
|
8
|
-
const INCIDENT_ID_HEADER = 'x-incident-id';
|
|
7
|
+
import { INCIDENT_ID_HEADER } from './consts.local.js';
|
|
9
8
|
/**
|
|
10
9
|
* Discovered runtime bases, per context and per client. Discovery is a network round trip the OIDC
|
|
11
10
|
* client service does not memoise, and the base never changes while a provider runs. A failed
|
package/build/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { IamRuntimeGrant, IamRuntimeGrantQuery, IamRuntimeGrantRequest, IamRuntimeMember, IamRuntimeMemberInvite, IamRuntimeMemberUpdate, IamRuntimeOrganization, IamRuntimeOrganizationCreate, IamRuntimeOrganizationUpdate, IamRuntimePermission } from '@owlmeans/iam';
|
|
2
|
+
export interface IamGateOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Refuse a resource-scoped param on the UMA2 fallback path instead of widening it to a
|
|
5
|
+
* project-wide check.
|
|
6
|
+
*
|
|
7
|
+
* Off by default, and deliberately so. A Keycloak-backed deployment cannot hold a resource-scoped
|
|
8
|
+
* grant at all — the adapter throws `IamUnsupported('resource-scoped-grant')` — so denying would
|
|
9
|
+
* lock every user out of every scoped endpoint rather than tightening anything. Turn it on only
|
|
10
|
+
* where the resulting refusals are the intended outcome.
|
|
11
|
+
*/
|
|
12
|
+
strictResourceScope?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The runtime IAM API as the signed-in subject of one request: its organizations, their members,
|
|
16
|
+
* the grantable definitions and the grants. Every call acts as that subject — the provider decides
|
|
17
|
+
* owner and member rights from the access token, never from anything sent here.
|
|
18
|
+
*/
|
|
19
|
+
export interface IamRuntimeClient {
|
|
20
|
+
organizations: {
|
|
21
|
+
list: () => Promise<IamRuntimeOrganization[]>;
|
|
22
|
+
/** The subject becomes the new organization's owner. */
|
|
23
|
+
create: (body?: IamRuntimeOrganizationCreate) => Promise<IamRuntimeOrganization>;
|
|
24
|
+
update: (entitySlug: string, body: IamRuntimeOrganizationUpdate) => Promise<IamRuntimeOrganization>;
|
|
25
|
+
};
|
|
26
|
+
members: {
|
|
27
|
+
list: (entitySlug: string) => Promise<IamRuntimeMember[]>;
|
|
28
|
+
/** Find-or-create by e-mail: adding an address twice answers the same member. */
|
|
29
|
+
add: (entitySlug: string, invite: IamRuntimeMemberInvite) => Promise<IamRuntimeMember>;
|
|
30
|
+
update: (entitySlug: string, profileId: string, update: IamRuntimeMemberUpdate) => Promise<IamRuntimeMember>;
|
|
31
|
+
remove: (entitySlug: string, profileId: string) => Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
permissions: {
|
|
34
|
+
list: (entitySlug: string) => Promise<IamRuntimePermission[]>;
|
|
35
|
+
};
|
|
36
|
+
grants: {
|
|
37
|
+
list: (entitySlug: string, query?: IamRuntimeGrantQuery) => Promise<IamRuntimeGrant[]>;
|
|
38
|
+
assign: (entitySlug: string, grant: IamRuntimeGrantRequest) => Promise<IamRuntimeGrant>;
|
|
39
|
+
revoke: (entitySlug: string, grant: IamRuntimeGrantRequest) => Promise<void>;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAE9Q,MAAM,WAAW,cAAc;IAC7B;;;;;;;;OAQG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE;QACb,IAAI,EAAE,MAAM,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAA;QAC7C,wDAAwD;QACxD,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,4BAA4B,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAA;QAChF,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAA;KACpG,CAAA;IACD,OAAO,EAAE;QACP,IAAI,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAA;QACzD,iFAAiF;QACjF,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAA;QACtF,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAA;QAC5G,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KACjE,CAAA;IACD,WAAW,EAAE;QACX,IAAI,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAA;KAC9D,CAAA;IACD,MAAM,EAAE;QACN,IAAI,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;QACtF,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAA;QACvF,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAC7E,CAAA;CACF"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ServerConfig, ServerContext } from '@owlmeans/server-context';
|
|
2
|
+
import type { WithSharedConfig } from '@owlmeans/oidc';
|
|
3
|
+
export type IamServerConfig = ServerConfig & WithSharedConfig;
|
|
4
|
+
export type IamServerContext<C extends IamServerConfig = IamServerConfig> = ServerContext<C>;
|
|
5
|
+
/** Who a route admits — and therefore which refusal a bare 403 from it means. */
|
|
6
|
+
export type Access = 'subject' | 'member' | 'owner';
|
|
7
|
+
export interface Call {
|
|
8
|
+
method: 'GET' | 'POST';
|
|
9
|
+
path: string;
|
|
10
|
+
access: Access;
|
|
11
|
+
params?: Record<string, string>;
|
|
12
|
+
query?: object;
|
|
13
|
+
body?: object;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=types.local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,gBAAgB,CAAA;AAE7D,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,IAAI,aAAa,CAAC,CAAC,CAAC,CAAA;AAE5F,iFAAiF;AACjF,MAAM,MAAM,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAA;AAEnD,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,KAAK,GAAG,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.local.js","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/server-iam",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.56",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -22,18 +22,19 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@owlmeans/auth": "^0.1.18-rc.
|
|
26
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
27
|
-
"@owlmeans/entrypoint": "^0.1.18-rc.
|
|
28
|
-
"@owlmeans/error": "^0.1.18-rc.
|
|
29
|
-
"@owlmeans/iam": "^0.1.18-rc.
|
|
30
|
-
"@owlmeans/
|
|
31
|
-
"@owlmeans/
|
|
32
|
-
"@owlmeans/server-
|
|
25
|
+
"@owlmeans/auth": "^0.1.18-rc.39",
|
|
26
|
+
"@owlmeans/context": "^0.1.18-rc.33",
|
|
27
|
+
"@owlmeans/entrypoint": "^0.1.18-rc.40",
|
|
28
|
+
"@owlmeans/error": "^0.1.18-rc.37",
|
|
29
|
+
"@owlmeans/iam": "^0.1.18-rc.49",
|
|
30
|
+
"@owlmeans/log": "^0.1.18-rc.1",
|
|
31
|
+
"@owlmeans/oidc": "^0.1.18-rc.54",
|
|
32
|
+
"@owlmeans/server-context": "^0.1.18-rc.42",
|
|
33
|
+
"@owlmeans/server-oidc-rp": "^0.1.18-rc.54"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@owlmeans/dep-config": "workspace:*",
|
|
36
|
-
"@types/bun": "^1.4.
|
|
37
|
+
"@types/bun": "^1.4.2",
|
|
37
38
|
"nodemon": "^3.1.14",
|
|
38
39
|
"typescript": "^7.0.2"
|
|
39
40
|
},
|
package/src/append.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
|
|
2
|
-
import type { WithSharedConfig } from '@owlmeans/oidc'
|
|
3
1
|
import { appendOidcGuard, makeOidcClientService, makeOidcWrappingService } from '@owlmeans/server-oidc-rp'
|
|
4
2
|
import { makeIamGate } from './gate.js'
|
|
3
|
+
import type { IamServerConfig, IamServerContext } from './types.local.js'
|
|
5
4
|
|
|
6
|
-
type IamServerConfig = ServerConfig & WithSharedConfig
|
|
7
|
-
type IamServerContext<C extends IamServerConfig = IamServerConfig> = ServerContext<C>
|
|
8
5
|
|
|
9
6
|
/**
|
|
10
7
|
* One-call OIDC RP setup for a server context.
|
package/src/gate.ts
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { createLazyService } from '@owlmeans/context'
|
|
2
2
|
import type { GateService, AbstractRequest, CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
3
|
-
import { entitySlugOf } from '@owlmeans/auth'
|
|
3
|
+
import { entitySlugOf, AuthForbidden, type Auth } from '@owlmeans/auth'
|
|
4
4
|
import { OIDC_GATE } from '@owlmeans/oidc'
|
|
5
|
-
import {
|
|
6
|
-
import type
|
|
7
|
-
import {
|
|
8
|
-
import type {
|
|
9
|
-
import {
|
|
10
|
-
hasPermission, parseGateParam, resolveGateResource, validateGateParams, GateResolutionFailure
|
|
11
|
-
} from '@owlmeans/iam'
|
|
12
|
-
import type { GateParamAudit } from '@owlmeans/iam'
|
|
5
|
+
import { createGateModel, extractPermissionSets, type Config, type Context } from '@owlmeans/server-oidc-rp'
|
|
6
|
+
import { hasPermission, parseGateParam, resolveGateResource, validateGateParams, GateResolutionFailure, type GateParamAudit } from '@owlmeans/iam'
|
|
7
|
+
import { logger, logThrottle } from '@owlmeans/log'
|
|
8
|
+
import type { IamGateOptions } from './types.js'
|
|
13
9
|
|
|
14
10
|
/**
|
|
15
11
|
* The gate-param grammar lives in `@owlmeans/iam` so the browser, the adapters and code-generation
|
|
@@ -23,19 +19,6 @@ export {
|
|
|
23
19
|
} from '@owlmeans/iam'
|
|
24
20
|
export type { ParsedGateParam, GateResourceSelector, GateParamAudit } from '@owlmeans/iam'
|
|
25
21
|
|
|
26
|
-
export interface IamGateOptions {
|
|
27
|
-
/**
|
|
28
|
-
* Refuse a resource-scoped param on the UMA2 fallback path instead of widening it to a
|
|
29
|
-
* project-wide check.
|
|
30
|
-
*
|
|
31
|
-
* Off by default, and deliberately so. A Keycloak-backed deployment cannot hold a resource-scoped
|
|
32
|
-
* grant at all — the adapter throws `IamUnsupported('resource-scoped-grant')` — so denying would
|
|
33
|
-
* lock every user out of every scoped endpoint rather than tightening anything. Turn it on only
|
|
34
|
-
* where the resulting refusals are the intended outcome.
|
|
35
|
-
*/
|
|
36
|
-
strictResourceScope?: boolean
|
|
37
|
-
}
|
|
38
|
-
|
|
39
22
|
/**
|
|
40
23
|
* Structural faults are logged once per alias+param+reason.
|
|
41
24
|
*
|
|
@@ -44,12 +27,28 @@ export interface IamGateOptions {
|
|
|
44
27
|
*/
|
|
45
28
|
const reported = new Set<string>()
|
|
46
29
|
|
|
47
|
-
const
|
|
30
|
+
const log = logger('server-iam:gate')
|
|
31
|
+
|
|
32
|
+
const reportOnce = (key: string, message: string, data: Record<string, unknown>): void => {
|
|
48
33
|
if (reported.has(key)) {
|
|
49
34
|
return
|
|
50
35
|
}
|
|
51
36
|
reported.add(key)
|
|
52
|
-
|
|
37
|
+
log.error(message, data)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A refusal of the gate. Logged once a minute per route, reason and subject — a hot endpoint
|
|
42
|
+
* refuses on every request, and one line per window says the same thing.
|
|
43
|
+
*/
|
|
44
|
+
const forbidden = (req: AbstractRequest, reason: string, params: string[]): AuthForbidden => {
|
|
45
|
+
const auth = req.auth as Auth | undefined
|
|
46
|
+
if (logThrottle(`access.forbidden\0${req.alias ?? ''}\0${reason}\0${auth?.userId ?? ''}`, 60_000)) {
|
|
47
|
+
log.warn('Access forbidden', {
|
|
48
|
+
alias: req.alias, reason, params, userId: auth?.userId, entitySlug: req.entity?.slug ?? (auth != null ? entitySlugOf(auth) : undefined),
|
|
49
|
+
}, { event: 'access.forbidden' })
|
|
50
|
+
}
|
|
51
|
+
return new AuthForbidden(reason)
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
/** Aliases whose declarations have already been checked. */
|
|
@@ -89,10 +88,9 @@ const auditEntrypoint = (ctx: Context, req: AbstractRequest, params: string[]):
|
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
for (const issue of validateGateParams(params, audit)) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
)
|
|
91
|
+
log.error('Gate param is misconfigured', {
|
|
92
|
+
param: issue.param, alias: req.alias, code: issue.code, detail: issue.detail,
|
|
93
|
+
})
|
|
96
94
|
}
|
|
97
95
|
} catch {
|
|
98
96
|
// An entrypoint that cannot be looked up is not this gate's problem to report.
|
|
@@ -121,7 +119,7 @@ export const makeIamGate = (alias: string = OIDC_GATE, opts?: IamGateOptions): G
|
|
|
121
119
|
const ctx = service.assertCtx<Config, Context>()
|
|
122
120
|
|
|
123
121
|
if (req.auth == null) {
|
|
124
|
-
throw
|
|
122
|
+
throw forbidden(req, 'auth', params)
|
|
125
123
|
}
|
|
126
124
|
|
|
127
125
|
const auth = req.auth as Auth
|
|
@@ -173,10 +171,10 @@ export const makeIamGate = (alias: string = OIDC_GATE, opts?: IamGateOptions): G
|
|
|
173
171
|
if (!granted) {
|
|
174
172
|
structural.forEach(detail => reportOnce(
|
|
175
173
|
`${req.alias}\0${detail}`,
|
|
176
|
-
|
|
174
|
+
'Gate refused a request it could not evaluate', { alias: req.alias, detail }
|
|
177
175
|
))
|
|
178
176
|
|
|
179
|
-
throw
|
|
177
|
+
throw forbidden(req, 'permission', params)
|
|
180
178
|
}
|
|
181
179
|
|
|
182
180
|
return
|
|
@@ -188,8 +186,8 @@ export const makeIamGate = (alias: string = OIDC_GATE, opts?: IamGateOptions): G
|
|
|
188
186
|
const scoped = params.filter(param => parseGateParam(param).resource != null)
|
|
189
187
|
scoped.forEach(param => reportOnce(
|
|
190
188
|
`uma2\0${req.alias}\0${param}`,
|
|
191
|
-
|
|
192
|
-
+ '
|
|
189
|
+
'Gate param is resource-scoped, but resource scoping is not enforced in UMA2 mode — it is checked as a '
|
|
190
|
+
+ 'project-wide permission', { param, alias: req.alias }
|
|
193
191
|
))
|
|
194
192
|
|
|
195
193
|
const usable = opts?.strictResourceScope === true
|
|
@@ -197,7 +195,7 @@ export const makeIamGate = (alias: string = OIDC_GATE, opts?: IamGateOptions): G
|
|
|
197
195
|
: params
|
|
198
196
|
|
|
199
197
|
if (usable.length < 1) {
|
|
200
|
-
throw
|
|
198
|
+
throw forbidden(req, 'permission', params)
|
|
201
199
|
}
|
|
202
200
|
|
|
203
201
|
const stripped = usable.map(param => parseGateParam(param).permission)
|
|
@@ -205,7 +203,7 @@ export const makeIamGate = (alias: string = OIDC_GATE, opts?: IamGateOptions): G
|
|
|
205
203
|
const permissions = await model.loadPermissions(auth, stripped)
|
|
206
204
|
|
|
207
205
|
if (permissions.length < 1) {
|
|
208
|
-
throw
|
|
206
|
+
throw forbidden(req, 'permission', params)
|
|
209
207
|
}
|
|
210
208
|
}
|
|
211
209
|
})
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { ORGANIZATION_REFUSAL, ORGANIZATION_OWNER_REFUSAL } from '@owlmeans/oidc
|
|
|
4
4
|
export * from './consts.js'
|
|
5
5
|
export * from './append.js'
|
|
6
6
|
export * from './gate.js'
|
|
7
|
+
export type * from './types.js'
|
|
7
8
|
export { organizationOf, organizationsOf } from './organization.js'
|
|
8
9
|
export { iamRuntime } from './runtime.js'
|
|
9
|
-
export type { IamRuntimeClient } from './
|
|
10
|
+
export type { IamRuntimeClient } from './types.js'
|
package/src/runtime.ts
CHANGED
|
@@ -1,61 +1,13 @@
|
|
|
1
1
|
import { AuthForbidden, AuthorizationError, AuthUnavailable } from '@owlmeans/auth'
|
|
2
2
|
import type { AbstractRequest } from '@owlmeans/entrypoint'
|
|
3
3
|
import { ResilientError } from '@owlmeans/error'
|
|
4
|
-
import { IAM_RUNTIME_ROUTES, IamClientError, IamError } from '@owlmeans/iam'
|
|
5
|
-
import type {
|
|
6
|
-
IamRuntimeAck, IamRuntimeGrant, IamRuntimeGrantList, IamRuntimeGrantQuery, IamRuntimeGrantRequest,
|
|
7
|
-
IamRuntimeMember, IamRuntimeMemberInvite, IamRuntimeMemberList, IamRuntimeMemberUpdate, IamRuntimeOrganization,
|
|
8
|
-
IamRuntimeOrganizationCreate, IamRuntimeOrganizationList, IamRuntimeOrganizationUpdate, IamRuntimePermission,
|
|
9
|
-
IamRuntimePermissionList,
|
|
10
|
-
} from '@owlmeans/iam'
|
|
4
|
+
import { IAM_RUNTIME_ROUTES, IamClientError, IamError, type IamRuntimeAck, type IamRuntimeGrant, type IamRuntimeGrantList, type IamRuntimeMember, type IamRuntimeMemberList, type IamRuntimeOrganization, type IamRuntimeOrganizationList, type IamRuntimePermissionList } from '@owlmeans/iam'
|
|
11
5
|
import { IAM_API_METADATA, ORGANIZATION_OWNER_REFUSAL, ORGANIZATION_REFUSAL } from '@owlmeans/oidc'
|
|
12
|
-
import { DEFAULT_ALIAS as OIDC_CLIENT_SERVICE } from '@owlmeans/server-oidc-rp'
|
|
13
|
-
import type { Config, Context, OidcClientService } from '@owlmeans/server-oidc-rp'
|
|
6
|
+
import { DEFAULT_ALIAS as OIDC_CLIENT_SERVICE, type Config, type Context, type OidcClientService } from '@owlmeans/server-oidc-rp'
|
|
14
7
|
import { sessionOf } from './organization.js'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* the grantable definitions and the grants. Every call acts as that subject — the provider decides
|
|
19
|
-
* owner and member rights from the access token, never from anything sent here.
|
|
20
|
-
*/
|
|
21
|
-
export interface IamRuntimeClient {
|
|
22
|
-
organizations: {
|
|
23
|
-
list: () => Promise<IamRuntimeOrganization[]>
|
|
24
|
-
/** The subject becomes the new organization's owner. */
|
|
25
|
-
create: (body?: IamRuntimeOrganizationCreate) => Promise<IamRuntimeOrganization>
|
|
26
|
-
update: (entitySlug: string, body: IamRuntimeOrganizationUpdate) => Promise<IamRuntimeOrganization>
|
|
27
|
-
}
|
|
28
|
-
members: {
|
|
29
|
-
list: (entitySlug: string) => Promise<IamRuntimeMember[]>
|
|
30
|
-
/** Find-or-create by e-mail: adding an address twice answers the same member. */
|
|
31
|
-
add: (entitySlug: string, invite: IamRuntimeMemberInvite) => Promise<IamRuntimeMember>
|
|
32
|
-
update: (entitySlug: string, profileId: string, update: IamRuntimeMemberUpdate) => Promise<IamRuntimeMember>
|
|
33
|
-
remove: (entitySlug: string, profileId: string) => Promise<void>
|
|
34
|
-
}
|
|
35
|
-
permissions: {
|
|
36
|
-
list: (entitySlug: string) => Promise<IamRuntimePermission[]>
|
|
37
|
-
}
|
|
38
|
-
grants: {
|
|
39
|
-
list: (entitySlug: string, query?: IamRuntimeGrantQuery) => Promise<IamRuntimeGrant[]>
|
|
40
|
-
assign: (entitySlug: string, grant: IamRuntimeGrantRequest) => Promise<IamRuntimeGrant>
|
|
41
|
-
revoke: (entitySlug: string, grant: IamRuntimeGrantRequest) => Promise<void>
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Who a route admits — and therefore which refusal a bare 403 from it means. */
|
|
46
|
-
type Access = 'subject' | 'member' | 'owner'
|
|
47
|
-
|
|
48
|
-
interface Call {
|
|
49
|
-
method: 'GET' | 'POST'
|
|
50
|
-
path: string
|
|
51
|
-
access: Access
|
|
52
|
-
params?: Record<string, string>
|
|
53
|
-
query?: object
|
|
54
|
-
body?: object
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** `@owlmeans/server-api`'s incident header; a production error body is nothing but this id. */
|
|
58
|
-
const INCIDENT_ID_HEADER = 'x-incident-id'
|
|
8
|
+
import { INCIDENT_ID_HEADER } from './consts.local.js'
|
|
9
|
+
import type { Access, Call } from './types.local.js'
|
|
10
|
+
import type { IamRuntimeClient } from './types.js'
|
|
59
11
|
|
|
60
12
|
/**
|
|
61
13
|
* Discovered runtime bases, per context and per client. Discovery is a network round trip the OIDC
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
|
|
2
|
+
import type { WithSharedConfig } from '@owlmeans/oidc'
|
|
3
|
+
|
|
4
|
+
export type IamServerConfig = ServerConfig & WithSharedConfig
|
|
5
|
+
|
|
6
|
+
export type IamServerContext<C extends IamServerConfig = IamServerConfig> = ServerContext<C>
|
|
7
|
+
|
|
8
|
+
/** Who a route admits — and therefore which refusal a bare 403 from it means. */
|
|
9
|
+
export type Access = 'subject' | 'member' | 'owner'
|
|
10
|
+
|
|
11
|
+
export interface Call {
|
|
12
|
+
method: 'GET' | 'POST'
|
|
13
|
+
path: string
|
|
14
|
+
access: Access
|
|
15
|
+
params?: Record<string, string>
|
|
16
|
+
query?: object
|
|
17
|
+
body?: object
|
|
18
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { IamRuntimeGrant, IamRuntimeGrantQuery, IamRuntimeGrantRequest, IamRuntimeMember, IamRuntimeMemberInvite, IamRuntimeMemberUpdate, IamRuntimeOrganization, IamRuntimeOrganizationCreate, IamRuntimeOrganizationUpdate, IamRuntimePermission } from '@owlmeans/iam'
|
|
2
|
+
|
|
3
|
+
export interface IamGateOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Refuse a resource-scoped param on the UMA2 fallback path instead of widening it to a
|
|
6
|
+
* project-wide check.
|
|
7
|
+
*
|
|
8
|
+
* Off by default, and deliberately so. A Keycloak-backed deployment cannot hold a resource-scoped
|
|
9
|
+
* grant at all — the adapter throws `IamUnsupported('resource-scoped-grant')` — so denying would
|
|
10
|
+
* lock every user out of every scoped endpoint rather than tightening anything. Turn it on only
|
|
11
|
+
* where the resulting refusals are the intended outcome.
|
|
12
|
+
*/
|
|
13
|
+
strictResourceScope?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The runtime IAM API as the signed-in subject of one request: its organizations, their members,
|
|
18
|
+
* the grantable definitions and the grants. Every call acts as that subject — the provider decides
|
|
19
|
+
* owner and member rights from the access token, never from anything sent here.
|
|
20
|
+
*/
|
|
21
|
+
export interface IamRuntimeClient {
|
|
22
|
+
organizations: {
|
|
23
|
+
list: () => Promise<IamRuntimeOrganization[]>
|
|
24
|
+
/** The subject becomes the new organization's owner. */
|
|
25
|
+
create: (body?: IamRuntimeOrganizationCreate) => Promise<IamRuntimeOrganization>
|
|
26
|
+
update: (entitySlug: string, body: IamRuntimeOrganizationUpdate) => Promise<IamRuntimeOrganization>
|
|
27
|
+
}
|
|
28
|
+
members: {
|
|
29
|
+
list: (entitySlug: string) => Promise<IamRuntimeMember[]>
|
|
30
|
+
/** Find-or-create by e-mail: adding an address twice answers the same member. */
|
|
31
|
+
add: (entitySlug: string, invite: IamRuntimeMemberInvite) => Promise<IamRuntimeMember>
|
|
32
|
+
update: (entitySlug: string, profileId: string, update: IamRuntimeMemberUpdate) => Promise<IamRuntimeMember>
|
|
33
|
+
remove: (entitySlug: string, profileId: string) => Promise<void>
|
|
34
|
+
}
|
|
35
|
+
permissions: {
|
|
36
|
+
list: (entitySlug: string) => Promise<IamRuntimePermission[]>
|
|
37
|
+
}
|
|
38
|
+
grants: {
|
|
39
|
+
list: (entitySlug: string, query?: IamRuntimeGrantQuery) => Promise<IamRuntimeGrant[]>
|
|
40
|
+
assign: (entitySlug: string, grant: IamRuntimeGrantRequest) => Promise<IamRuntimeGrant>
|
|
41
|
+
revoke: (entitySlug: string, grant: IamRuntimeGrantRequest) => Promise<void>
|
|
42
|
+
}
|
|
43
|
+
}
|