@toa.io/extensions.exposition 1.0.0-alpha.102 → 1.0.0-alpha.104
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/components/identity.bans/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.basic/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/manifest.toa.yaml +4 -1
- package/components/identity.federation/operations/authenticate.js +1 -2
- package/components/identity.federation/operations/authenticate.js.map +1 -1
- package/components/identity.federation/operations/decode.d.ts +2 -0
- package/components/identity.federation/operations/decode.js +33 -0
- package/components/identity.federation/operations/decode.js.map +1 -0
- package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/operations/types/context.d.ts +1 -0
- package/components/identity.federation/source/authenticate.ts +1 -2
- package/components/identity.federation/source/decode.ts +9 -0
- package/components/identity.federation/source/types/context.ts +1 -0
- package/components/identity.keys/manifest.toa.yaml +19 -6
- package/components/identity.keys/operations/create.d.ts +5 -2
- package/components/identity.keys/operations/create.js +4 -2
- package/components/identity.keys/operations/create.js.map +1 -1
- package/components/identity.keys/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.keys/source/create.ts +10 -4
- package/components/identity.roles/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/manifest.toa.yaml +65 -17
- package/components/identity.tokens/operations/decrypt.js +1 -1
- package/components/identity.tokens/operations/decrypt.js.map +1 -1
- package/components/identity.tokens/operations/encrypt.js +1 -1
- package/components/identity.tokens/operations/encrypt.js.map +1 -1
- package/components/identity.tokens/operations/issue.d.ts +9 -3
- package/components/identity.tokens/operations/issue.js +16 -2
- package/components/identity.tokens/operations/issue.js.map +1 -1
- package/components/identity.tokens/operations/lib/types.d.ts +5 -1
- package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/source/authenticate.test.ts +4 -1
- package/components/identity.tokens/source/decrypt.test.ts +4 -1
- package/components/identity.tokens/source/decrypt.ts +1 -1
- package/components/identity.tokens/source/encrypt.test.ts +4 -1
- package/components/identity.tokens/source/encrypt.ts +2 -2
- package/components/identity.tokens/source/issue.ts +28 -5
- package/components/identity.tokens/source/lib/types.ts +5 -1
- package/features/identtiy.tokens.custom.feature +30 -19
- package/features/map.feature +67 -3
- package/features/steps/IdP.ts +32 -0
- package/features/steps/components/greeter/manifest.toa.yaml +0 -1
- package/features/steps/components/octets.tester/manifest.toa.yaml +0 -1
- package/features/steps/components/pots/manifest.toa.yaml +0 -3
- package/features/steps/components/sequences/manifest.toa.yaml +0 -1
- package/features/steps/components/users.properties/manifest.toa.yaml +0 -1
- package/package.json +2 -2
- package/source/directives/io/Input.ts +4 -1
- package/source/directives/map/Claims.ts +32 -11
- package/source/directives/map/Map.ts +10 -5
- package/source/directives/map/Mapping.ts +8 -2
- package/transpiled/directives/io/Input.js +2 -0
- package/transpiled/directives/io/Input.js.map +1 -1
- package/transpiled/directives/map/Claims.d.ts +6 -2
- package/transpiled/directives/map/Claims.js +21 -6
- package/transpiled/directives/map/Claims.js.map +1 -1
- package/transpiled/directives/map/Map.d.ts +4 -2
- package/transpiled/directives/map/Map.js +6 -4
- package/transpiled/directives/map/Map.js.map +1 -1
- package/transpiled/directives/map/Mapping.d.ts +7 -2
- package/transpiled/directives/map/Mapping.js +3 -1
- package/transpiled/directives/map/Mapping.js.map +1 -1
- package/transpiled/tsconfig.tsbuildinfo +1 -1
package/features/map.feature
CHANGED
|
@@ -175,8 +175,8 @@ Feature: HTTP context mapping
|
|
|
175
175
|
"""yaml
|
|
176
176
|
exposition:
|
|
177
177
|
/:
|
|
178
|
-
io:output: true
|
|
179
178
|
GET:
|
|
179
|
+
io:output: true
|
|
180
180
|
map:authority: name
|
|
181
181
|
endpoint: compute
|
|
182
182
|
"""
|
|
@@ -217,9 +217,9 @@ Feature: HTTP context mapping
|
|
|
217
217
|
"""yaml
|
|
218
218
|
exposition:
|
|
219
219
|
/:
|
|
220
|
-
anyone: true
|
|
221
|
-
io:output: true
|
|
222
220
|
GET:
|
|
221
|
+
anyone: true
|
|
222
|
+
io:output: true
|
|
223
223
|
map:claims:
|
|
224
224
|
name: email
|
|
225
225
|
endpoint: compute
|
|
@@ -239,3 +239,67 @@ Feature: HTTP context mapping
|
|
|
239
239
|
|
|
240
240
|
Hello Alice@test.local
|
|
241
241
|
"""
|
|
242
|
+
|
|
243
|
+
Scenario: Mapping Bearer token claims during inception
|
|
244
|
+
Given local IDP is running
|
|
245
|
+
And the `identity.federation` configuration:
|
|
246
|
+
"""yaml
|
|
247
|
+
trust:
|
|
248
|
+
- iss: http://localhost:44444
|
|
249
|
+
"""
|
|
250
|
+
And the `pots` is running with the following manifest:
|
|
251
|
+
"""yaml
|
|
252
|
+
exposition:
|
|
253
|
+
/:
|
|
254
|
+
POST:
|
|
255
|
+
auth:incept: id
|
|
256
|
+
io:input: [title, volume]
|
|
257
|
+
io:output: [id, title, volume]
|
|
258
|
+
map:claims:
|
|
259
|
+
title: email
|
|
260
|
+
endpoint: create
|
|
261
|
+
"""
|
|
262
|
+
And the IDP random token is issued
|
|
263
|
+
|
|
264
|
+
When the following request is received:
|
|
265
|
+
"""
|
|
266
|
+
POST /pots/ HTTP/1.1
|
|
267
|
+
host: the.two.com
|
|
268
|
+
authorization: Bearer ${{ random.id_token }}
|
|
269
|
+
accept: application/yaml
|
|
270
|
+
content-type: application/yaml
|
|
271
|
+
|
|
272
|
+
volume: 1.5
|
|
273
|
+
"""
|
|
274
|
+
Then the following reply is sent:
|
|
275
|
+
"""
|
|
276
|
+
201 Created
|
|
277
|
+
|
|
278
|
+
id: ${{ id }}
|
|
279
|
+
title: ${{ random.email }}
|
|
280
|
+
volume: 1.5
|
|
281
|
+
"""
|
|
282
|
+
|
|
283
|
+
Scenario: Mapping non-exposed properties
|
|
284
|
+
Given the `echo` is running with the following manifest:
|
|
285
|
+
"""yaml
|
|
286
|
+
exposition:
|
|
287
|
+
/:
|
|
288
|
+
GET:
|
|
289
|
+
io:output: true
|
|
290
|
+
io:input: [] # disallow input
|
|
291
|
+
map:authority: name
|
|
292
|
+
endpoint: compute
|
|
293
|
+
"""
|
|
294
|
+
When the following request is received:
|
|
295
|
+
"""
|
|
296
|
+
GET /echo/ HTTP/1.1
|
|
297
|
+
host: the.one.com
|
|
298
|
+
accept: text/plain
|
|
299
|
+
"""
|
|
300
|
+
Then the following reply is sent:
|
|
301
|
+
"""
|
|
302
|
+
200 OK
|
|
303
|
+
|
|
304
|
+
Hello the.one.com
|
|
305
|
+
"""
|
package/features/steps/IdP.ts
CHANGED
|
@@ -126,6 +126,38 @@ export class IdP {
|
|
|
126
126
|
this.captures.set(`${user}.id_token`, idToken)
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
@given('the IDP random token is issued')
|
|
130
|
+
public async issueNewToken (): Promise<void> {
|
|
131
|
+
assert.ok(IdP.privateKey, 'IdP private key is not available')
|
|
132
|
+
|
|
133
|
+
const sub = Math.random().toString(36).substring(7)
|
|
134
|
+
|
|
135
|
+
const jwt = [
|
|
136
|
+
{
|
|
137
|
+
typ: 'JWT',
|
|
138
|
+
alg: 'RS256'
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
iss: IdP.issuer,
|
|
142
|
+
sub,
|
|
143
|
+
aud: 'test',
|
|
144
|
+
email: sub + '@test.local',
|
|
145
|
+
iat: Math.floor(Date.now() / 1000),
|
|
146
|
+
exp: Math.floor((Date.now() + 1000 * 60 * 5) / 1000)
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
.map((v) => Buffer.from(JSON.stringify(v)).toString('base64url'))
|
|
150
|
+
.join('.')
|
|
151
|
+
|
|
152
|
+
const signature = crypto.createSign('RSA-SHA256').end(jwt).sign(IdP.privateKey, 'base64url')
|
|
153
|
+
|
|
154
|
+
const idToken = `${jwt}.${signature}`
|
|
155
|
+
|
|
156
|
+
this.captures.set('random.sub', sub)
|
|
157
|
+
this.captures.set('random.email', sub + '@test.local')
|
|
158
|
+
this.captures.set('random.id_token', idToken)
|
|
159
|
+
}
|
|
160
|
+
|
|
129
161
|
@given('the IDP {word} token for {word} is issued with following secret:')
|
|
130
162
|
public async issueSymmetricToken (alg: string, user: string, secret: string): Promise<void> {
|
|
131
163
|
const jwt = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/extensions.exposition",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.104",
|
|
4
4
|
"description": "Toa Exposition",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"@types/negotiator": "0.6.1",
|
|
62
62
|
"jest-esbuild": "0.3.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "60e54c62ce9007c6a1b24b76bb91eecac3ff0c0b"
|
|
65
65
|
}
|
|
@@ -19,7 +19,10 @@ export class Input implements Directive {
|
|
|
19
19
|
context.pipelines.body.push((body) => this.check(body))
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
private check (body: unknown):
|
|
22
|
+
private check (body: unknown): Message | Message[] | undefined {
|
|
23
|
+
if (body === undefined)
|
|
24
|
+
return body
|
|
25
|
+
|
|
23
26
|
try {
|
|
24
27
|
schemas.message.validate<Message | Message[]>(body)
|
|
25
28
|
} catch {
|
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
import assert from 'node:assert'
|
|
2
2
|
import { Mapping } from './Mapping'
|
|
3
|
+
import type { Component } from '@toa.io/core'
|
|
4
|
+
import type { Remotes } from '../../Remotes'
|
|
3
5
|
import type { Input } from '../../io'
|
|
4
6
|
|
|
5
7
|
export class Claims extends Mapping<Record<string, string>> {
|
|
6
|
-
|
|
8
|
+
private readonly discovery!: Promise<Component>
|
|
9
|
+
private federation: Component | null = null
|
|
10
|
+
|
|
11
|
+
public constructor (map: Record<string, string>, remotes: Remotes) {
|
|
7
12
|
assert.ok(map.constructor === Object, '`map:claims` must be an object')
|
|
8
13
|
|
|
9
14
|
assert.ok(Object.values(map).every((value) => typeof value === 'string'),
|
|
10
15
|
'`map:claims ` must be an object with string values')
|
|
11
16
|
|
|
12
|
-
super(map)
|
|
17
|
+
super(map, remotes)
|
|
18
|
+
|
|
19
|
+
this.discovery = remotes.discover('identity', 'federation')
|
|
13
20
|
}
|
|
14
21
|
|
|
15
|
-
public override properties (context: Input): Record<string, string> | null {
|
|
16
|
-
const
|
|
17
|
-
const claims = authenticated.identity?.claims
|
|
22
|
+
public override async properties (context: Input): Promise<Record<string, string> | null> {
|
|
23
|
+
const authentication = context.request.headers.authorization
|
|
18
24
|
|
|
19
|
-
if (
|
|
25
|
+
if (authentication === undefined)
|
|
26
|
+
return null
|
|
27
|
+
|
|
28
|
+
const claims = await this.claims(authentication)
|
|
29
|
+
|
|
30
|
+
if (claims === null)
|
|
20
31
|
return null
|
|
21
32
|
|
|
22
33
|
return Object.entries(this.value).reduce((properties: Record<string, string>, [property, claim]) => {
|
|
@@ -28,10 +39,20 @@ export class Claims extends Mapping<Record<string, string>> {
|
|
|
28
39
|
return properties
|
|
29
40
|
}, {})
|
|
30
41
|
}
|
|
31
|
-
}
|
|
32
42
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
private async claims (authentication: string): Promise<Record<string, string> | null> {
|
|
44
|
+
const [scheme, credentials] = authentication.split(' ')
|
|
45
|
+
|
|
46
|
+
if (scheme !== 'Bearer' || credentials === undefined)
|
|
47
|
+
return null
|
|
48
|
+
|
|
49
|
+
this.federation ??= await this.discovery
|
|
50
|
+
|
|
51
|
+
const claims = await this.federation.invoke<Record<string, string> | Error>('decode', { input: credentials })
|
|
52
|
+
|
|
53
|
+
if (claims instanceof Error)
|
|
54
|
+
return null
|
|
55
|
+
|
|
56
|
+
return claims
|
|
57
|
+
}
|
|
37
58
|
}
|
|
@@ -11,26 +11,31 @@ import type { Directive } from './Directive'
|
|
|
11
11
|
import type { Properties } from './Properties'
|
|
12
12
|
import type { DirectiveFamily, Parameter } from '../../RTD'
|
|
13
13
|
import type { Input, Output } from '../../io'
|
|
14
|
+
import type { Remotes } from '../../Remotes'
|
|
14
15
|
|
|
15
16
|
export class Map implements DirectiveFamily {
|
|
16
17
|
public readonly name = 'map'
|
|
17
18
|
public readonly mandatory = false
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
private remotes!: Remotes
|
|
21
|
+
|
|
22
|
+
public create (name: string, value: unknown, remotes: Remotes): Property | Mapping {
|
|
23
|
+
this.remotes = remotes
|
|
24
|
+
|
|
20
25
|
return match(name,
|
|
21
26
|
() => properties.has(name), (name: PN) => new Property(name, value as PV),
|
|
22
|
-
() => name in mappings, (name: keyof typeof mappings) => new mappings[name](value),
|
|
27
|
+
() => name in mappings, (name: keyof typeof mappings) => new mappings[name](value, remotes),
|
|
23
28
|
() => {
|
|
24
29
|
throw new Error(`Directive 'map:${name}' is not implemented`)
|
|
25
30
|
})
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
public preflight (directives: Directive[], context: Input, parameters: Parameter[]): Output {
|
|
33
|
+
public async preflight (directives: Directive[], context: Input, parameters: Parameter[]): Promise<Output> {
|
|
29
34
|
const properties = {}
|
|
30
35
|
|
|
31
36
|
for (const directive of directives)
|
|
32
37
|
if (directive instanceof Mapping)
|
|
33
|
-
Object.assign(properties, directive.properties(context, parameters, directives))
|
|
38
|
+
Object.assign(properties, await directive.properties(context, parameters, directives))
|
|
34
39
|
|
|
35
40
|
context.pipelines.body.push((body: unknown) => {
|
|
36
41
|
if (body === undefined || body === null || typeof body !== 'object')
|
|
@@ -46,7 +51,7 @@ export class Map implements DirectiveFamily {
|
|
|
46
51
|
type PN = keyof Properties
|
|
47
52
|
type PV = Properties[PN]
|
|
48
53
|
|
|
49
|
-
const mappings: Record<string, new (value: any) => Directive> = {
|
|
54
|
+
const mappings: Record<string, new (value: any, remotes: Remotes) => Directive> = {
|
|
50
55
|
authority: Authority,
|
|
51
56
|
headers: Headers,
|
|
52
57
|
languages: Languages,
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
+
import type { Remotes } from '../../Remotes'
|
|
1
2
|
import type { Directive } from './Directive'
|
|
2
3
|
import type { Input } from '../../io'
|
|
3
4
|
import type { Parameter } from '../../RTD'
|
|
4
5
|
|
|
5
6
|
export abstract class Mapping<T = unknown> {
|
|
6
7
|
protected value: T
|
|
8
|
+
protected remotes?: Remotes
|
|
7
9
|
|
|
8
|
-
protected constructor (value: T) {
|
|
10
|
+
protected constructor (value: T, remotes?: Remotes) {
|
|
9
11
|
this.value = value
|
|
12
|
+
this.remotes = remotes
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
public abstract properties (context: Input, parameters: Parameter[], directives: Directive[]):
|
|
15
|
+
public abstract properties (context: Input, parameters: Parameter[], directives: Directive[]): Output
|
|
13
16
|
}
|
|
17
|
+
|
|
18
|
+
type Properties = Record<string, unknown> | null
|
|
19
|
+
type Output = Properties | Promise<Properties>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../../source/directives/io/Input.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAuC;AACvC,mDAAoC;AAKpC,MAAa,KAAK;IACC,WAAW,CAAa;IAEzC,YAAoB,WAAwB;QAC1C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;IAChC,CAAC;IAEM,MAAM,CAAC,QAAQ,CAAE,WAAoB;QAC1C,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAc,WAAW,EAAE,+BAA+B,CAAC,CAAA;IACnF,CAAC;IAEM,MAAM,CAAE,OAAgB;QAC7B,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IACzD,CAAC;IAEO,KAAK,CAAE,IAAa;QAC1B,IAAI,CAAC;YACH,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAsB,IAAI,CAAC,CAAA;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,iBAAU,CAAC,sBAAsB,CAAC,CAAA;QAC9C,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QAErC,IAAI,QAAQ,KAAK,SAAS;YACxB,MAAM,IAAI,iBAAU,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAA;QAEvD,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,SAAS,CAAE,KAA0B;QAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACvB,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QAE1E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YAErC,IAAI,QAAQ,KAAK,SAAS;gBACxB,OAAO,QAAQ,CAAA;QACnB,CAAC;IACH,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../../source/directives/io/Input.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAuC;AACvC,mDAAoC;AAKpC,MAAa,KAAK;IACC,WAAW,CAAa;IAEzC,YAAoB,WAAwB;QAC1C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;IAChC,CAAC;IAEM,MAAM,CAAC,QAAQ,CAAE,WAAoB;QAC1C,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAc,WAAW,EAAE,+BAA+B,CAAC,CAAA;IACnF,CAAC;IAEM,MAAM,CAAE,OAAgB;QAC7B,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IACzD,CAAC;IAEO,KAAK,CAAE,IAAa;QAC1B,IAAI,IAAI,KAAK,SAAS;YACpB,OAAO,IAAI,CAAA;QAEb,IAAI,CAAC;YACH,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAsB,IAAI,CAAC,CAAA;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,iBAAU,CAAC,sBAAsB,CAAC,CAAA;QAC9C,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QAErC,IAAI,QAAQ,KAAK,SAAS;YACxB,MAAM,IAAI,iBAAU,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAA;QAEvD,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,SAAS,CAAE,KAA0B;QAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACvB,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QAE1E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YAErC,IAAI,QAAQ,KAAK,SAAS;gBACxB,OAAO,QAAQ,CAAA;QACnB,CAAC;IACH,CAAC;CACF;AA5CD,sBA4CC"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { Mapping } from './Mapping';
|
|
2
|
+
import type { Remotes } from '../../Remotes';
|
|
2
3
|
import type { Input } from '../../io';
|
|
3
4
|
export declare class Claims extends Mapping<Record<string, string>> {
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
private readonly discovery;
|
|
6
|
+
private federation;
|
|
7
|
+
constructor(map: Record<string, string>, remotes: Remotes);
|
|
8
|
+
properties(context: Input): Promise<Record<string, string> | null>;
|
|
9
|
+
private claims;
|
|
6
10
|
}
|
|
@@ -7,15 +7,20 @@ exports.Claims = void 0;
|
|
|
7
7
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
8
8
|
const Mapping_1 = require("./Mapping");
|
|
9
9
|
class Claims extends Mapping_1.Mapping {
|
|
10
|
-
|
|
10
|
+
discovery;
|
|
11
|
+
federation = null;
|
|
12
|
+
constructor(map, remotes) {
|
|
11
13
|
node_assert_1.default.ok(map.constructor === Object, '`map:claims` must be an object');
|
|
12
14
|
node_assert_1.default.ok(Object.values(map).every((value) => typeof value === 'string'), '`map:claims ` must be an object with string values');
|
|
13
|
-
super(map);
|
|
15
|
+
super(map, remotes);
|
|
16
|
+
this.discovery = remotes.discover('identity', 'federation');
|
|
14
17
|
}
|
|
15
|
-
properties(context) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
async properties(context) {
|
|
19
|
+
const authentication = context.request.headers.authorization;
|
|
20
|
+
if (authentication === undefined)
|
|
21
|
+
return null;
|
|
22
|
+
const claims = await this.claims(authentication);
|
|
23
|
+
if (claims === null)
|
|
19
24
|
return null;
|
|
20
25
|
return Object.entries(this.value).reduce((properties, [property, claim]) => {
|
|
21
26
|
const value = claims[claim];
|
|
@@ -24,6 +29,16 @@ class Claims extends Mapping_1.Mapping {
|
|
|
24
29
|
return properties;
|
|
25
30
|
}, {});
|
|
26
31
|
}
|
|
32
|
+
async claims(authentication) {
|
|
33
|
+
const [scheme, credentials] = authentication.split(' ');
|
|
34
|
+
if (scheme !== 'Bearer' || credentials === undefined)
|
|
35
|
+
return null;
|
|
36
|
+
this.federation ??= await this.discovery;
|
|
37
|
+
const claims = await this.federation.invoke('decode', { input: credentials });
|
|
38
|
+
if (claims instanceof Error)
|
|
39
|
+
return null;
|
|
40
|
+
return claims;
|
|
41
|
+
}
|
|
27
42
|
}
|
|
28
43
|
exports.Claims = Claims;
|
|
29
44
|
//# sourceMappingURL=Claims.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Claims.js","sourceRoot":"","sources":["../../../source/directives/map/Claims.ts"],"names":[],"mappings":";;;;;;AAAA,8DAAgC;AAChC,uCAAmC;
|
|
1
|
+
{"version":3,"file":"Claims.js","sourceRoot":"","sources":["../../../source/directives/map/Claims.ts"],"names":[],"mappings":";;;;;;AAAA,8DAAgC;AAChC,uCAAmC;AAKnC,MAAa,MAAO,SAAQ,iBAA+B;IACxC,SAAS,CAAqB;IACvC,UAAU,GAAqB,IAAI,CAAA;IAE3C,YAAoB,GAA2B,EAAE,OAAgB;QAC/D,qBAAM,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,KAAK,MAAM,EAAE,gCAAgC,CAAC,CAAA;QAEvE,qBAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,EACtE,oDAAoD,CAAC,CAAA;QAEvD,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAEnB,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;IAC7D,CAAC;IAEe,KAAK,CAAC,UAAU,CAAE,OAAc;QAC9C,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAA;QAE5D,IAAI,cAAc,KAAK,SAAS;YAC9B,OAAO,IAAI,CAAA;QAEb,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;QAEhD,IAAI,MAAM,KAAK,IAAI;YACjB,OAAO,IAAI,CAAA;QAEb,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,UAAkC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE;YACjG,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;YAE3B,IAAI,KAAK,KAAK,SAAS;gBACrB,UAAU,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAA;YAE9B,OAAO,UAAU,CAAA;QACnB,CAAC,EAAE,EAAE,CAAC,CAAA;IACR,CAAC;IAEO,KAAK,CAAC,MAAM,CAAE,cAAsB;QAC1C,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAEvD,IAAI,MAAM,KAAK,QAAQ,IAAI,WAAW,KAAK,SAAS;YAClD,OAAO,IAAI,CAAA;QAEb,IAAI,CAAC,UAAU,KAAK,MAAM,IAAI,CAAC,SAAS,CAAA;QAExC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAiC,QAAQ,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAA;QAE7G,IAAI,MAAM,YAAY,KAAK;YACzB,OAAO,IAAI,CAAA;QAEb,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAnDD,wBAmDC"}
|
|
@@ -3,9 +3,11 @@ import { Mapping } from './Mapping';
|
|
|
3
3
|
import type { Directive } from './Directive';
|
|
4
4
|
import type { DirectiveFamily, Parameter } from '../../RTD';
|
|
5
5
|
import type { Input, Output } from '../../io';
|
|
6
|
+
import type { Remotes } from '../../Remotes';
|
|
6
7
|
export declare class Map implements DirectiveFamily {
|
|
7
8
|
readonly name = "map";
|
|
8
9
|
readonly mandatory = false;
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
private remotes;
|
|
11
|
+
create(name: string, value: unknown, remotes: Remotes): Property | Mapping;
|
|
12
|
+
preflight(directives: Directive[], context: Input, parameters: Parameter[]): Promise<Output>;
|
|
11
13
|
}
|
|
@@ -13,16 +13,18 @@ const Claims_1 = require("./Claims");
|
|
|
13
13
|
class Map {
|
|
14
14
|
name = 'map';
|
|
15
15
|
mandatory = false;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
remotes;
|
|
17
|
+
create(name, value, remotes) {
|
|
18
|
+
this.remotes = remotes;
|
|
19
|
+
return (0, matchacho_1.match)(name, () => Properties_1.properties.has(name), (name) => new Properties_1.Property(name, value), () => name in mappings, (name) => new mappings[name](value, remotes), () => {
|
|
18
20
|
throw new Error(`Directive 'map:${name}' is not implemented`);
|
|
19
21
|
});
|
|
20
22
|
}
|
|
21
|
-
preflight(directives, context, parameters) {
|
|
23
|
+
async preflight(directives, context, parameters) {
|
|
22
24
|
const properties = {};
|
|
23
25
|
for (const directive of directives)
|
|
24
26
|
if (directive instanceof Mapping_1.Mapping)
|
|
25
|
-
Object.assign(properties, directive.properties(context, parameters, directives));
|
|
27
|
+
Object.assign(properties, await directive.properties(context, parameters, directives));
|
|
26
28
|
context.pipelines.body.push((body) => {
|
|
27
29
|
if (body === undefined || body === null || typeof body !== 'object')
|
|
28
30
|
return properties;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Map.js","sourceRoot":"","sources":["../../../source/directives/map/Map.ts"],"names":[],"mappings":";;;AAAA,yCAAiC;AACjC,6CAAmD;AACnD,uCAAmC;AACnC,uCAAmC;AACnC,2CAAuC;AACvC,yCAAqC;AACrC,yCAAqC;AACrC,2CAAuC;AACvC,qCAAiC;
|
|
1
|
+
{"version":3,"file":"Map.js","sourceRoot":"","sources":["../../../source/directives/map/Map.ts"],"names":[],"mappings":";;;AAAA,yCAAiC;AACjC,6CAAmD;AACnD,uCAAmC;AACnC,uCAAmC;AACnC,2CAAuC;AACvC,yCAAqC;AACrC,yCAAqC;AACrC,2CAAuC;AACvC,qCAAiC;AAOjC,MAAa,GAAG;IACE,IAAI,GAAG,KAAK,CAAA;IACZ,SAAS,GAAG,KAAK,CAAA;IAEzB,OAAO,CAAU;IAElB,MAAM,CAAE,IAAY,EAAE,KAAc,EAAE,OAAgB;QAC3D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QAEtB,OAAO,IAAA,iBAAK,EAAC,IAAI,EACf,GAAG,EAAE,CAAC,uBAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAQ,EAAE,EAAE,CAAC,IAAI,qBAAQ,CAAC,IAAI,EAAE,KAAW,CAAC,EACzE,GAAG,EAAE,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC,IAA2B,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,EAC3F,GAAG,EAAE;YACH,MAAM,IAAI,KAAK,CAAC,kBAAkB,IAAI,sBAAsB,CAAC,CAAA;QAC/D,CAAC,CAAC,CAAA;IACN,CAAC;IAEM,KAAK,CAAC,SAAS,CAAE,UAAuB,EAAE,OAAc,EAAE,UAAuB;QACtF,MAAM,UAAU,GAAG,EAAE,CAAA;QAErB,KAAK,MAAM,SAAS,IAAI,UAAU;YAChC,IAAI,SAAS,YAAY,iBAAO;gBAC9B,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAA;QAE1F,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAa,EAAE,EAAE;YAC5C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;gBACjE,OAAO,UAAU,CAAA;;gBAEjB,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;QAEF,OAAO,IAAI,CAAA;IACb,CAAC;CACF;AAjCD,kBAiCC;AAKD,MAAM,QAAQ,GAAoE;IAChF,SAAS,EAAE,qBAAS;IACpB,OAAO,EAAE,iBAAO;IAChB,SAAS,EAAE,qBAAS;IACpB,QAAQ,EAAE,mBAAQ;IAClB,QAAQ,EAAE,mBAAQ;IAClB,MAAM,EAAE,eAAM;CACf,CAAA"}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import type { Remotes } from '../../Remotes';
|
|
1
2
|
import type { Directive } from './Directive';
|
|
2
3
|
import type { Input } from '../../io';
|
|
3
4
|
import type { Parameter } from '../../RTD';
|
|
4
5
|
export declare abstract class Mapping<T = unknown> {
|
|
5
6
|
protected value: T;
|
|
6
|
-
protected
|
|
7
|
-
|
|
7
|
+
protected remotes?: Remotes;
|
|
8
|
+
protected constructor(value: T, remotes?: Remotes);
|
|
9
|
+
abstract properties(context: Input, parameters: Parameter[], directives: Directive[]): Output;
|
|
8
10
|
}
|
|
11
|
+
type Properties = Record<string, unknown> | null;
|
|
12
|
+
type Output = Properties | Promise<Properties>;
|
|
13
|
+
export {};
|
|
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Mapping = void 0;
|
|
4
4
|
class Mapping {
|
|
5
5
|
value;
|
|
6
|
-
|
|
6
|
+
remotes;
|
|
7
|
+
constructor(value, remotes) {
|
|
7
8
|
this.value = value;
|
|
9
|
+
this.remotes = remotes;
|
|
8
10
|
}
|
|
9
11
|
}
|
|
10
12
|
exports.Mapping = Mapping;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Mapping.js","sourceRoot":"","sources":["../../../source/directives/map/Mapping.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"Mapping.js","sourceRoot":"","sources":["../../../source/directives/map/Mapping.ts"],"names":[],"mappings":";;;AAKA,MAAsB,OAAO;IACjB,KAAK,CAAG;IACR,OAAO,CAAU;IAE3B,YAAuB,KAAQ,EAAE,OAAiB;QAChD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;CAGF;AAVD,0BAUC"}
|