@toa.io/extensions.exposition 1.0.0-alpha.100 → 1.0.0-alpha.102
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.basic/manifest.toa.yaml +9 -0
- package/components/identity.basic/operations/authenticate.js +2 -2
- package/components/identity.basic/operations/authenticate.js.map +1 -1
- package/components/identity.basic/operations/incept.js +1 -1
- package/components/identity.basic/operations/incept.js.map +1 -1
- package/components/identity.basic/operations/transit.js +3 -3
- package/components/identity.basic/operations/transit.js.map +1 -1
- package/components/identity.basic/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.basic/source/authenticate.ts +2 -2
- package/components/identity.basic/source/incept.ts +1 -1
- package/components/identity.basic/source/transit.ts +3 -3
- package/components/identity.federation/manifest.toa.yaml +20 -6
- package/components/identity.federation/operations/authenticate.js +1 -1
- package/components/identity.federation/operations/authenticate.js.map +1 -1
- package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/source/authenticate.ts +1 -1
- package/components/identity.keys/manifest.toa.yaml +41 -0
- package/components/identity.keys/operations/create.d.ts +19 -0
- package/components/identity.keys/operations/create.js +14 -0
- package/components/identity.keys/operations/create.js.map +1 -0
- package/components/identity.keys/operations/tsconfig.tsbuildinfo +1 -0
- package/components/identity.keys/source/create.ts +29 -0
- package/components/identity.keys/tsconfig.json +9 -0
- package/components/identity.roles/manifest.toa.yaml +2 -0
- package/components/identity.roles/operations/grant.js +2 -2
- package/components/identity.roles/operations/grant.js.map +1 -1
- package/components/identity.roles/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.roles/source/grant.ts +2 -2
- package/components/identity.tokens/manifest.toa.yaml +41 -9
- package/components/identity.tokens/operations/authenticate.d.ts +2 -2
- package/components/identity.tokens/operations/authenticate.js +12 -12
- package/components/identity.tokens/operations/authenticate.js.map +1 -1
- package/components/identity.tokens/operations/decrypt.d.ts +12 -3
- package/components/identity.tokens/operations/decrypt.js +62 -18
- package/components/identity.tokens/operations/decrypt.js.map +1 -1
- package/components/identity.tokens/operations/encrypt.d.ts +3 -3
- package/components/identity.tokens/operations/encrypt.js +23 -7
- package/components/identity.tokens/operations/encrypt.js.map +1 -1
- package/components/identity.tokens/operations/issue.d.ts +18 -0
- package/components/identity.tokens/operations/issue.js +44 -0
- package/components/identity.tokens/operations/issue.js.map +1 -0
- package/components/identity.tokens/operations/lib/index.d.ts +2 -0
- package/components/identity.tokens/operations/lib/index.js +19 -0
- package/components/identity.tokens/operations/lib/index.js.map +1 -0
- package/components/identity.tokens/operations/lib/pad.d.ts +1 -0
- package/components/identity.tokens/operations/lib/pad.js +5 -0
- package/components/identity.tokens/operations/lib/pad.js.map +1 -0
- package/components/identity.tokens/operations/{types.d.ts → lib/types.d.ts} +31 -7
- package/components/identity.tokens/operations/lib/types.js.map +1 -0
- package/components/identity.tokens/operations/revoke.d.ts +2 -2
- package/components/identity.tokens/operations/revoke.js.map +1 -1
- package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/source/authenticate.test.ts +10 -7
- package/components/identity.tokens/source/authenticate.ts +14 -14
- package/components/identity.tokens/source/decrypt.test.ts +26 -16
- package/components/identity.tokens/source/decrypt.ts +90 -20
- package/components/identity.tokens/source/encrypt.test.ts +41 -13
- package/components/identity.tokens/source/encrypt.ts +35 -11
- package/components/identity.tokens/source/issue.ts +57 -0
- package/components/identity.tokens/source/lib/index.ts +2 -0
- package/components/identity.tokens/source/lib/pad.ts +1 -0
- package/components/identity.tokens/source/lib/paseto.test.ts +16 -0
- package/components/identity.tokens/source/{types.ts → lib/types.ts} +33 -7
- package/components/identity.tokens/source/revoke.ts +2 -2
- package/components/octets.storage/operations/put.js +4 -4
- package/documentation/components.md +77 -39
- package/features/auth.claims.feature +1 -0
- package/features/identity.basic.feature +2 -2
- package/features/identity.tokens.feature +0 -43
- package/features/identtiy.tokens.custom.feature +236 -0
- package/features/octets.cloudinary.feature +2 -2
- package/features/steps/Gateway.ts +3 -1
- package/package.json +7 -4
- package/source/directives/auth/Authorization.ts +30 -18
- package/source/directives/auth/Delegate.ts +1 -3
- package/source/directives/auth/Role.ts +4 -8
- package/source/directives/auth/types.ts +2 -1
- package/source/directives/octets/Put.ts +3 -19
- package/transpiled/directives/auth/Authorization.d.ts +2 -1
- package/transpiled/directives/auth/Authorization.js +25 -16
- package/transpiled/directives/auth/Authorization.js.map +1 -1
- package/transpiled/directives/auth/Delegate.js +1 -2
- package/transpiled/directives/auth/Delegate.js.map +1 -1
- package/transpiled/directives/auth/Role.d.ts +1 -1
- package/transpiled/directives/auth/Role.js +3 -5
- package/transpiled/directives/auth/Role.js.map +1 -1
- package/transpiled/directives/auth/types.d.ts +2 -1
- package/transpiled/directives/octets/Put.d.ts +0 -1
- package/transpiled/directives/octets/Put.js +0 -11
- package/transpiled/directives/octets/Put.js.map +1 -1
- package/transpiled/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/operations/types.js.map +0 -1
- /package/components/identity.tokens/operations/{types.js → lib/types.js} +0 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
@security
|
|
2
|
+
Feature: Custom tokens
|
|
3
|
+
|
|
4
|
+
Background:
|
|
5
|
+
Given the `identity.basic` database contains:
|
|
6
|
+
| _id | authority | username | password |
|
|
7
|
+
| efe3a65ebbee47ed95a73edd911ea328 | nex | developer | $2b$10$ZRSKkgZoGnrcTNA5w5eCcu3pxDzdTduhteVYXcp56AaNcilNkwJ.O |
|
|
8
|
+
And the `identity.roles` database contains:
|
|
9
|
+
| _id | identity | role |
|
|
10
|
+
| 9c4702490ff84f2a9e1b1da2ab64bdd4 | efe3a65ebbee47ed95a73edd911ea328 | app:notes |
|
|
11
|
+
And the `identity.keys` database is empty
|
|
12
|
+
And the annotation:
|
|
13
|
+
"""yaml
|
|
14
|
+
/:
|
|
15
|
+
/notes:
|
|
16
|
+
auth:role: app:notes
|
|
17
|
+
GET:
|
|
18
|
+
io:output: true
|
|
19
|
+
dev:stub:
|
|
20
|
+
access: granted!
|
|
21
|
+
POST:
|
|
22
|
+
io:output: true
|
|
23
|
+
dev:stub:
|
|
24
|
+
access: granted!
|
|
25
|
+
/public:
|
|
26
|
+
GET:
|
|
27
|
+
auth:role: app:notes:public
|
|
28
|
+
io:output: true
|
|
29
|
+
dev:stub:
|
|
30
|
+
access: granted!
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
Scenario: Issuing token
|
|
34
|
+
When the following request is received:
|
|
35
|
+
"""
|
|
36
|
+
POST /identity/tokens/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
37
|
+
host: nex.toa.io
|
|
38
|
+
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
39
|
+
content-type: application/yaml
|
|
40
|
+
accept: application/json
|
|
41
|
+
|
|
42
|
+
lifetime: 0
|
|
43
|
+
name: Dev token
|
|
44
|
+
"""
|
|
45
|
+
Then the following reply is sent:
|
|
46
|
+
"""
|
|
47
|
+
201 Created
|
|
48
|
+
|
|
49
|
+
"${{ token }}"
|
|
50
|
+
"""
|
|
51
|
+
When the following request is received:
|
|
52
|
+
"""
|
|
53
|
+
GET /identity/ HTTP/1.1
|
|
54
|
+
host: nex.toa.io
|
|
55
|
+
authorization: Token ${{ token }}
|
|
56
|
+
accept: application/yaml
|
|
57
|
+
"""
|
|
58
|
+
Then the following reply is sent:
|
|
59
|
+
"""
|
|
60
|
+
200 OK
|
|
61
|
+
|
|
62
|
+
id: efe3a65ebbee47ed95a73edd911ea328
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
# debug LRU cache
|
|
66
|
+
When the following request is received:
|
|
67
|
+
"""
|
|
68
|
+
GET /identity/ HTTP/1.1
|
|
69
|
+
host: nex.toa.io
|
|
70
|
+
authorization: Token ${{ token }}
|
|
71
|
+
"""
|
|
72
|
+
Then the following reply is sent:
|
|
73
|
+
"""
|
|
74
|
+
200 OK
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
Scenario: Token with restricted scopes
|
|
78
|
+
When the following request is received:
|
|
79
|
+
"""
|
|
80
|
+
POST /identity/tokens/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
81
|
+
host: nex.toa.io
|
|
82
|
+
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
83
|
+
accept: application/json
|
|
84
|
+
content-type: application/yaml
|
|
85
|
+
|
|
86
|
+
lifetime: 10
|
|
87
|
+
scopes: [app:notes:public]
|
|
88
|
+
"""
|
|
89
|
+
Then the following reply is sent:
|
|
90
|
+
"""
|
|
91
|
+
201 Created
|
|
92
|
+
|
|
93
|
+
"${{ token }}"
|
|
94
|
+
"""
|
|
95
|
+
When the following request is received:
|
|
96
|
+
"""
|
|
97
|
+
GET /notes/ HTTP/1.1
|
|
98
|
+
host: nex.toa.io
|
|
99
|
+
authorization: Token ${{ token }}
|
|
100
|
+
"""
|
|
101
|
+
Then the following reply is sent:
|
|
102
|
+
"""
|
|
103
|
+
403 Forbidden
|
|
104
|
+
"""
|
|
105
|
+
When the following request is received:
|
|
106
|
+
"""
|
|
107
|
+
GET /notes/public/ HTTP/1.1
|
|
108
|
+
host: nex.toa.io
|
|
109
|
+
authorization: Token ${{ token }}
|
|
110
|
+
"""
|
|
111
|
+
Then the following reply is sent:
|
|
112
|
+
"""
|
|
113
|
+
200 OK
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
Scenario: Token with restricted permissions
|
|
117
|
+
When the following request is received:
|
|
118
|
+
"""
|
|
119
|
+
POST /identity/tokens/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
120
|
+
host: nex.toa.io
|
|
121
|
+
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
122
|
+
accept: application/json
|
|
123
|
+
content-type: application/yaml
|
|
124
|
+
|
|
125
|
+
lifetime: 10
|
|
126
|
+
permissions: {
|
|
127
|
+
/notes/: [GET]
|
|
128
|
+
}
|
|
129
|
+
"""
|
|
130
|
+
Then the following reply is sent:
|
|
131
|
+
"""
|
|
132
|
+
201 Created
|
|
133
|
+
|
|
134
|
+
"${{ token }}"
|
|
135
|
+
"""
|
|
136
|
+
When the following request is received:
|
|
137
|
+
"""
|
|
138
|
+
GET /notes/ HTTP/1.1
|
|
139
|
+
host: nex.toa.io
|
|
140
|
+
authorization: Token ${{ token }}
|
|
141
|
+
"""
|
|
142
|
+
Then the following reply is sent:
|
|
143
|
+
"""
|
|
144
|
+
200 OK
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
# method is not permitted
|
|
148
|
+
When the following request is received:
|
|
149
|
+
"""
|
|
150
|
+
POST /notes/ HTTP/1.1
|
|
151
|
+
host: nex.toa.io
|
|
152
|
+
authorization: Token ${{ token }}
|
|
153
|
+
"""
|
|
154
|
+
Then the following reply is sent:
|
|
155
|
+
"""
|
|
156
|
+
403 Forbidden
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
# resource is not permitted
|
|
160
|
+
When the following request is received:
|
|
161
|
+
"""
|
|
162
|
+
GET /notes/public/ HTTP/1.1
|
|
163
|
+
host: nex.toa.io
|
|
164
|
+
authorization: Token ${{ token }}
|
|
165
|
+
"""
|
|
166
|
+
Then the following reply is sent:
|
|
167
|
+
"""
|
|
168
|
+
403 Forbidden
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
Scenario: Token revocation
|
|
172
|
+
Given the `identity.tokens` configuration:
|
|
173
|
+
"""yaml
|
|
174
|
+
cache: 1
|
|
175
|
+
"""
|
|
176
|
+
When the following request is received:
|
|
177
|
+
"""
|
|
178
|
+
POST /identity/tokens/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
179
|
+
host: nex.toa.io
|
|
180
|
+
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
181
|
+
content-type: application/yaml
|
|
182
|
+
accept: application/json
|
|
183
|
+
|
|
184
|
+
lifetime: 0
|
|
185
|
+
name: One-time token
|
|
186
|
+
"""
|
|
187
|
+
Then the following reply is sent:
|
|
188
|
+
"""
|
|
189
|
+
201 Created
|
|
190
|
+
|
|
191
|
+
"${{ token }}"
|
|
192
|
+
"""
|
|
193
|
+
When the following request is received:
|
|
194
|
+
"""
|
|
195
|
+
GET /identity/ HTTP/1.1
|
|
196
|
+
host: nex.toa.io
|
|
197
|
+
authorization: Token ${{ token }}
|
|
198
|
+
accept: application/yaml
|
|
199
|
+
"""
|
|
200
|
+
Then the following reply is sent:
|
|
201
|
+
"""
|
|
202
|
+
200 OK
|
|
203
|
+
|
|
204
|
+
id: efe3a65ebbee47ed95a73edd911ea328
|
|
205
|
+
"""
|
|
206
|
+
When the following request is received:
|
|
207
|
+
"""
|
|
208
|
+
GET /identity/keys/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
209
|
+
host: nex.toa.io
|
|
210
|
+
authorization: Token ${{ token }}
|
|
211
|
+
accept: application/yaml
|
|
212
|
+
"""
|
|
213
|
+
Then the following reply is sent:
|
|
214
|
+
"""
|
|
215
|
+
200 OK
|
|
216
|
+
|
|
217
|
+
- id: ${{ token.kid }}
|
|
218
|
+
name: One-time token
|
|
219
|
+
"""
|
|
220
|
+
When the following request is received:
|
|
221
|
+
"""
|
|
222
|
+
DELETE /identity/keys/efe3a65ebbee47ed95a73edd911ea328/${{ token.kid }}/ HTTP/1.1
|
|
223
|
+
host: nex.toa.io
|
|
224
|
+
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
225
|
+
"""
|
|
226
|
+
And after 1 second
|
|
227
|
+
When the following request is received:
|
|
228
|
+
"""
|
|
229
|
+
GET /identity/ HTTP/1.1
|
|
230
|
+
host: nex.toa.io
|
|
231
|
+
authorization: Token ${{ token }}
|
|
232
|
+
"""
|
|
233
|
+
Then the following reply is sent:
|
|
234
|
+
"""
|
|
235
|
+
401 Unauthorized
|
|
236
|
+
"""
|
|
@@ -29,13 +29,13 @@ Feature: Octets with Cloudinary storage
|
|
|
29
29
|
201 Created
|
|
30
30
|
content-type: application/yaml
|
|
31
31
|
|
|
32
|
-
id:
|
|
32
|
+
id: ${{ id }}
|
|
33
33
|
type: image/png
|
|
34
34
|
size: 473831
|
|
35
35
|
"""
|
|
36
36
|
When the following request is received:
|
|
37
37
|
"""
|
|
38
|
-
GET
|
|
38
|
+
GET /${{ id }} HTTP/1.1
|
|
39
39
|
host: nex.toa.io
|
|
40
40
|
"""
|
|
41
41
|
Then the stream equals to `lenna.png` is sent with the following headers:
|
|
@@ -127,6 +127,8 @@ const DEFAULT_PROPERTIES: Partial<http.Options> = {
|
|
|
127
127
|
|
|
128
128
|
const DEFAULT_CONFIGURATION: Record<string, object> = {
|
|
129
129
|
'identity.tokens': {
|
|
130
|
-
|
|
130
|
+
keys: {
|
|
131
|
+
0: 'k3.local.pIZT8-9Fa6U_QtfQHOSStfGtmyzPINyKQq2Xk-hd7vA'
|
|
132
|
+
}
|
|
131
133
|
}
|
|
132
134
|
}
|
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.102",
|
|
4
4
|
"description": "Toa Exposition",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -22,10 +22,12 @@
|
|
|
22
22
|
"@toa.io/generic": "1.0.0-alpha.93",
|
|
23
23
|
"@toa.io/schemas": "1.0.0-alpha.93",
|
|
24
24
|
"bcryptjs": "2.4.3",
|
|
25
|
-
"error-value": "0.
|
|
25
|
+
"error-value": "0.4.1",
|
|
26
26
|
"http-cache-semantics": "4.1.1",
|
|
27
27
|
"js-yaml": "4.1.0",
|
|
28
|
+
"lru-cache": "11.0.1",
|
|
28
29
|
"matchacho": "0.3.5",
|
|
30
|
+
"minimatch": "10.0.1",
|
|
29
31
|
"msgpackr": "1.10.1",
|
|
30
32
|
"negotiator": "0.6.3",
|
|
31
33
|
"openspan": "1.0.0-alpha.93",
|
|
@@ -39,12 +41,13 @@
|
|
|
39
41
|
},
|
|
40
42
|
"scripts": {
|
|
41
43
|
"test": "jest",
|
|
42
|
-
"transpile": "tsc && npm run transpile:bans && npm run transpile:basic && npm run transpile:tokens && npm run transpile:roles && npm run transpile:federation",
|
|
44
|
+
"transpile": "tsc && npm run transpile:bans && npm run transpile:basic && npm run transpile:tokens && npm run transpile:roles && npm run transpile:federation && npm run transpile:keys",
|
|
43
45
|
"transpile:bans": "tsc -p ./components/identity.bans",
|
|
44
46
|
"transpile:basic": "tsc -p ./components/identity.basic",
|
|
45
47
|
"transpile:tokens": "tsc -p ./components/identity.tokens",
|
|
46
48
|
"transpile:roles": "tsc -p ./components/identity.roles",
|
|
47
49
|
"transpile:federation": "tsc -p ./components/identity.federation",
|
|
50
|
+
"transpile:keys": "tsc -p ./components/identity.keys",
|
|
48
51
|
"features": "cucumber-js",
|
|
49
52
|
"features:security": "cucumber-js --tags @security",
|
|
50
53
|
"features:octets": "cucumber-js features/octets.*"
|
|
@@ -58,5 +61,5 @@
|
|
|
58
61
|
"@types/negotiator": "0.6.1",
|
|
59
62
|
"jest-esbuild": "0.3.0"
|
|
60
63
|
},
|
|
61
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "ce5b6e22c1adbec4cc5d4dc5dd8f6bafc41d93d0"
|
|
62
65
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import assert from 'node:assert'
|
|
2
2
|
import { match } from 'matchacho'
|
|
3
|
+
import { console } from 'openspan'
|
|
4
|
+
import { minimatch } from 'minimatch'
|
|
3
5
|
import * as http from '../../HTTP'
|
|
4
6
|
import { Anonymous } from './Anonymous'
|
|
5
7
|
import { Id } from './Id'
|
|
@@ -57,27 +59,21 @@ export class Authorization implements DirectiveFamily<Directive, Extension> {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
public async preflight (directives: Directive[],
|
|
60
|
-
|
|
62
|
+
context: Input,
|
|
61
63
|
parameters: Parameter[]): Promise<Output> {
|
|
62
|
-
|
|
63
|
-
* Some authentication scheme providers may create identity during authentication;
|
|
64
|
-
* therefore, we need to skip the authentication process if the Incept directive is present.
|
|
65
|
-
*
|
|
66
|
-
* If the provided credentials already exist,
|
|
67
|
-
* the inception will cause a unique constraint violation on the settle stage.
|
|
68
|
-
*/
|
|
69
|
-
// const inception = directives.reduce((yes, directive) => yes || directive instanceof Incept, false)
|
|
70
|
-
|
|
71
|
-
input.identity = await this.resolve(input.authority, input.request.headers.authorization)
|
|
64
|
+
context.identity = await this.resolve(context.authority, context.request.headers.authorization)
|
|
72
65
|
|
|
73
66
|
for (const directive of directives) {
|
|
74
|
-
const allow = await directive.authorize(
|
|
67
|
+
const allow = await directive.authorize(context.identity, context, parameters)
|
|
75
68
|
|
|
76
69
|
if (allow)
|
|
77
|
-
|
|
70
|
+
if (this.permitted(context))
|
|
71
|
+
return directive.reply?.(context.identity) ?? null
|
|
72
|
+
else
|
|
73
|
+
throw new http.Forbidden()
|
|
78
74
|
}
|
|
79
75
|
|
|
80
|
-
if (
|
|
76
|
+
if (context.identity === null)
|
|
81
77
|
throw new http.Unauthorized()
|
|
82
78
|
else
|
|
83
79
|
throw new http.Forbidden()
|
|
@@ -98,9 +94,7 @@ export class Authorization implements DirectiveFamily<Directive, Extension> {
|
|
|
98
94
|
return
|
|
99
95
|
|
|
100
96
|
// Role directive may have already set the value
|
|
101
|
-
|
|
102
|
-
await Role.set(identity, this.discovery.roles)
|
|
103
|
-
|
|
97
|
+
identity.roles ??= await Role.get(identity, this.discovery.roles)
|
|
104
98
|
this.tokens ??= await this.discovery.tokens
|
|
105
99
|
|
|
106
100
|
const token = await this.tokens.invoke<string>('encrypt', {
|
|
@@ -132,8 +126,14 @@ export class Authorization implements DirectiveFamily<Directive, Extension> {
|
|
|
132
126
|
}
|
|
133
127
|
})
|
|
134
128
|
|
|
135
|
-
if (result instanceof Error)
|
|
129
|
+
if (result instanceof Error) {
|
|
130
|
+
const code: string | unknown = (result as unknown as { code: string }).code
|
|
131
|
+
|
|
132
|
+
if (typeof code === 'string')
|
|
133
|
+
console.info('Authentication failed', { code })
|
|
134
|
+
|
|
136
135
|
return null
|
|
136
|
+
}
|
|
137
137
|
|
|
138
138
|
const identity = result.identity
|
|
139
139
|
|
|
@@ -145,6 +145,18 @@ export class Authorization implements DirectiveFamily<Directive, Extension> {
|
|
|
145
145
|
return identity
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
private permitted (context: Input): boolean {
|
|
149
|
+
const permissions = context.identity?.permissions
|
|
150
|
+
|
|
151
|
+
if (permissions === undefined)
|
|
152
|
+
return true
|
|
153
|
+
|
|
154
|
+
return Object.entries(permissions).some(([pattern, methods]) => {
|
|
155
|
+
return methods.some((method) => method === '*' || method === context.request.method) &&
|
|
156
|
+
minimatch(context.request.url, pattern)
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
148
160
|
private async banned (identity: Identity): Promise<boolean> {
|
|
149
161
|
this.bans ??= await this.discovery.bans
|
|
150
162
|
|
|
@@ -17,9 +17,7 @@ export class Delegate implements Directive {
|
|
|
17
17
|
if (identity === null)
|
|
18
18
|
return false
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
await Role.set(identity, this.discovery)
|
|
22
|
-
|
|
20
|
+
identity.roles ??= await Role.get(identity, this.discovery)
|
|
23
21
|
context.pipelines.body.push((body) => this.embed(body, identity))
|
|
24
22
|
|
|
25
23
|
return true
|
|
@@ -15,7 +15,7 @@ export class Role implements Directive {
|
|
|
15
15
|
this.dynamic = this.roles.some((role) => role.includes('{'))
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
public static async
|
|
18
|
+
public static async get (identity: Identity, discovery: Promise<Component>): Promise<string[]> {
|
|
19
19
|
this.remote ??= await discovery
|
|
20
20
|
|
|
21
21
|
const query: Query = {
|
|
@@ -23,7 +23,7 @@ export class Role implements Directive {
|
|
|
23
23
|
limit: 1024
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
return await this.remote.invoke('list', { query })
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
public async authorize
|
|
@@ -31,13 +31,9 @@ export class Role implements Directive {
|
|
|
31
31
|
if (identity === null)
|
|
32
32
|
return false
|
|
33
33
|
|
|
34
|
-
await Role.
|
|
34
|
+
identity.roles ??= await Role.get(identity, this.discovery)
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return false
|
|
39
|
-
|
|
40
|
-
return this.match(identity.roles!, parameters)
|
|
36
|
+
return this.match(identity.roles, parameters)
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
private match (roles: string[], parameters: Parameter[]): boolean {
|
|
@@ -18,8 +18,9 @@ export interface Directive {
|
|
|
18
18
|
|
|
19
19
|
export interface Identity {
|
|
20
20
|
readonly id: string
|
|
21
|
-
scheme: string | null // null for transient identities
|
|
22
21
|
roles?: string[]
|
|
22
|
+
permissions?: Record<string, string[]>
|
|
23
|
+
scheme: string | null // null for transient identities
|
|
23
24
|
refresh: boolean
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -11,7 +11,7 @@ import type { Parameter } from '../../RTD'
|
|
|
11
11
|
import type { Unit } from './workflows'
|
|
12
12
|
import type { Entry } from '@toa.io/extensions.storages'
|
|
13
13
|
import type { Remotes } from '../../Remotes'
|
|
14
|
-
import type {
|
|
14
|
+
import type { Err } from 'error-value'
|
|
15
15
|
import type { Component } from '@toa.io/core'
|
|
16
16
|
import type { Output } from '../../io'
|
|
17
17
|
import type { Input } from './types'
|
|
@@ -69,7 +69,7 @@ export class Put extends Directive {
|
|
|
69
69
|
const entry = await this.storage.invoke<Entry>('put', request)
|
|
70
70
|
|
|
71
71
|
return match<Output>(entry,
|
|
72
|
-
Error, (error:
|
|
72
|
+
Error, (error: Err) => this.throw(error),
|
|
73
73
|
() => this.reply(input, storage, entry, parameters))
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -94,7 +94,7 @@ export class Put extends Directive {
|
|
|
94
94
|
return stream
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
private throw (error:
|
|
97
|
+
private throw (error: Err): never {
|
|
98
98
|
throw match(error.code,
|
|
99
99
|
'NOT_ACCEPTABLE', () => new http.UnsupportedMediaType(),
|
|
100
100
|
'TYPE_MISMATCH', () => new http.BadRequest(),
|
|
@@ -105,22 +105,6 @@ export class Put extends Directive {
|
|
|
105
105
|
'INVALID_ID', () => new http.BadRequest(error.message),
|
|
106
106
|
error)
|
|
107
107
|
}
|
|
108
|
-
|
|
109
|
-
private attributes (value: string | string[]): Record<string, string> {
|
|
110
|
-
if (Array.isArray(value))
|
|
111
|
-
value = value.join(',')
|
|
112
|
-
|
|
113
|
-
const attributes: Record<string, string> = {}
|
|
114
|
-
|
|
115
|
-
for (const pair of value.split(',')) {
|
|
116
|
-
const eq = pair.indexOf('=')
|
|
117
|
-
const key = (eq === -1 ? pair : pair.slice(0, eq)).trim()
|
|
118
|
-
|
|
119
|
-
attributes[key] = eq === -1 ? 'true' : pair.slice(eq + 1).trim()
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return attributes
|
|
123
|
-
}
|
|
124
108
|
}
|
|
125
109
|
|
|
126
110
|
export interface Options {
|
|
@@ -12,8 +12,9 @@ export declare class Authorization implements DirectiveFamily<Directive, Extensi
|
|
|
12
12
|
private tokens;
|
|
13
13
|
private bans;
|
|
14
14
|
create(name: string, value: any, remotes: Remotes): Directive;
|
|
15
|
-
preflight(directives: Directive[],
|
|
15
|
+
preflight(directives: Directive[], context: Input, parameters: Parameter[]): Promise<Output>;
|
|
16
16
|
settle(directives: Directive[], input: Input, response: http.OutgoingMessage): Promise<void>;
|
|
17
17
|
private resolve;
|
|
18
|
+
private permitted;
|
|
18
19
|
private banned;
|
|
19
20
|
}
|
|
@@ -29,6 +29,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
29
|
exports.Authorization = void 0;
|
|
30
30
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
31
31
|
const matchacho_1 = require("matchacho");
|
|
32
|
+
const openspan_1 = require("openspan");
|
|
33
|
+
const minimatch_1 = require("minimatch");
|
|
32
34
|
const http = __importStar(require("../../HTTP"));
|
|
33
35
|
const Anonymous_1 = require("./Anonymous");
|
|
34
36
|
const Id_1 = require("./Id");
|
|
@@ -57,22 +59,17 @@ class Authorization {
|
|
|
57
59
|
this.discovery[name] ??= remotes.discover('identity', name);
|
|
58
60
|
return (0, matchacho_1.match)(Class, Role_1.Role, () => new Role_1.Role(value, this.discovery.roles), Rule_1.Rule, () => new Rule_1.Rule(value, this.create.bind(this)), Incept_1.Incept, () => new Incept_1.Incept(value, this.discovery), Delegate_1.Delegate, () => new Delegate_1.Delegate(value, this.discovery.roles), () => new Class(value));
|
|
59
61
|
}
|
|
60
|
-
async preflight(directives,
|
|
61
|
-
|
|
62
|
-
* Some authentication scheme providers may create identity during authentication;
|
|
63
|
-
* therefore, we need to skip the authentication process if the Incept directive is present.
|
|
64
|
-
*
|
|
65
|
-
* If the provided credentials already exist,
|
|
66
|
-
* the inception will cause a unique constraint violation on the settle stage.
|
|
67
|
-
*/
|
|
68
|
-
// const inception = directives.reduce((yes, directive) => yes || directive instanceof Incept, false)
|
|
69
|
-
input.identity = await this.resolve(input.authority, input.request.headers.authorization);
|
|
62
|
+
async preflight(directives, context, parameters) {
|
|
63
|
+
context.identity = await this.resolve(context.authority, context.request.headers.authorization);
|
|
70
64
|
for (const directive of directives) {
|
|
71
|
-
const allow = await directive.authorize(
|
|
65
|
+
const allow = await directive.authorize(context.identity, context, parameters);
|
|
72
66
|
if (allow)
|
|
73
|
-
|
|
67
|
+
if (this.permitted(context))
|
|
68
|
+
return directive.reply?.(context.identity) ?? null;
|
|
69
|
+
else
|
|
70
|
+
throw new http.Forbidden();
|
|
74
71
|
}
|
|
75
|
-
if (
|
|
72
|
+
if (context.identity === null)
|
|
76
73
|
throw new http.Unauthorized();
|
|
77
74
|
else
|
|
78
75
|
throw new http.Forbidden();
|
|
@@ -85,8 +82,7 @@ class Authorization {
|
|
|
85
82
|
if (identity.scheme === schemes_1.PRIMARY && !identity.refresh)
|
|
86
83
|
return;
|
|
87
84
|
// Role directive may have already set the value
|
|
88
|
-
|
|
89
|
-
await Role_1.Role.set(identity, this.discovery.roles);
|
|
85
|
+
identity.roles ??= await Role_1.Role.get(identity, this.discovery.roles);
|
|
90
86
|
this.tokens ??= await this.discovery.tokens;
|
|
91
87
|
const token = await this.tokens.invoke('encrypt', {
|
|
92
88
|
input: { authority: input.authority, identity }
|
|
@@ -109,8 +105,12 @@ class Authorization {
|
|
|
109
105
|
credentials
|
|
110
106
|
}
|
|
111
107
|
});
|
|
112
|
-
if (result instanceof Error)
|
|
108
|
+
if (result instanceof Error) {
|
|
109
|
+
const code = result.code;
|
|
110
|
+
if (typeof code === 'string')
|
|
111
|
+
openspan_1.console.info('Authentication failed', { code });
|
|
113
112
|
return null;
|
|
113
|
+
}
|
|
114
114
|
const identity = result.identity;
|
|
115
115
|
if (scheme !== schemes_1.PRIMARY && (await this.banned(identity)))
|
|
116
116
|
throw new http.Unauthorized();
|
|
@@ -118,6 +118,15 @@ class Authorization {
|
|
|
118
118
|
identity.refresh = result.refresh;
|
|
119
119
|
return identity;
|
|
120
120
|
}
|
|
121
|
+
permitted(context) {
|
|
122
|
+
const permissions = context.identity?.permissions;
|
|
123
|
+
if (permissions === undefined)
|
|
124
|
+
return true;
|
|
125
|
+
return Object.entries(permissions).some(([pattern, methods]) => {
|
|
126
|
+
return methods.some((method) => method === '*' || method === context.request.method) &&
|
|
127
|
+
(0, minimatch_1.minimatch)(context.request.url, pattern);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
121
130
|
async banned(identity) {
|
|
122
131
|
this.bans ??= await this.discovery.bans;
|
|
123
132
|
const ban = await this.bans.invoke('observe', { query: { id: identity.id } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Authorization.js","sourceRoot":"","sources":["../../../source/directives/auth/Authorization.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,8DAAgC;AAChC,yCAAiC;AACjC,iDAAkC;AAClC,2CAAuC;AACvC,6BAAyB;AACzB,iCAA6B;AAC7B,iCAA6B;AAC7B,qCAAiC;AACjC,iCAA6B;AAC7B,qCAAiC;AACjC,yCAAqC;AACrC,6CAAyC;AACzC,mCAA+B;AAC/B,uCAA8C;AAC9C,qCAAiC;AAiBjC,MAAa,aAAa;IACR,OAAO,GAAa,CAAC,MAAM,CAAC,CAAA;IAC5B,IAAI,GAAW,MAAM,CAAA;IACrB,SAAS,GAAY,IAAI,CAAA;IAExB,OAAO,GAAG,EAAwB,CAAA;IAClC,SAAS,GAAG,EAA0B,CAAA;IAC/C,MAAM,GAAqB,IAAI,CAAA;IAC/B,IAAI,GAAqB,IAAI,CAAA;IAE9B,MAAM,CAAE,IAAY,EAAE,KAAU,EAAE,OAAgB;QACvD,qBAAM,CAAC,EAAE,CAAC,IAAI,IAAI,YAAY,EAC5B,mBAAmB,IAAI,sBAAsB,CAAC,CAAA;QAEhD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;QAEhC,KAAK,MAAM,IAAI,IAAI,OAAO;YACxB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;QAE7D,OAAO,IAAA,iBAAK,EAAC,KAAK,EAChB,WAAI,EAAE,GAAG,EAAE,CAAC,IAAI,WAAI,CAAC,KAA0B,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EACtE,WAAI,EAAE,GAAG,EAAE,CAAC,IAAI,WAAI,CAAC,KAA+B,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAC7E,eAAM,EAAE,GAAG,EAAE,CAAC,IAAI,eAAM,CAAC,KAAe,EAAE,IAAI,CAAC,SAAS,CAAC,EACzD,mBAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAQ,CAAC,KAAe,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EACnE,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IAC3B,CAAC;IAEM,KAAK,CAAC,SAAS,CAAE,UAAuB,EAC7C,
|
|
1
|
+
{"version":3,"file":"Authorization.js","sourceRoot":"","sources":["../../../source/directives/auth/Authorization.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,8 +13,7 @@ class Delegate {
|
|
|
13
13
|
async authorize(identity, context) {
|
|
14
14
|
if (identity === null)
|
|
15
15
|
return false;
|
|
16
|
-
|
|
17
|
-
await Role_1.Role.set(identity, this.discovery);
|
|
16
|
+
identity.roles ??= await Role_1.Role.get(identity, this.discovery);
|
|
18
17
|
context.pipelines.body.push((body) => this.embed(body, identity));
|
|
19
18
|
return true;
|
|
20
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Delegate.js","sourceRoot":"","sources":["../../../source/directives/auth/Delegate.ts"],"names":[],"mappings":";;;AAAA,qCAAuC;AAEvC,iCAA6B;AAI7B,MAAa,QAAQ;IACF,QAAQ,CAAQ;IAChB,SAAS,CAAoB;IAE9C,YAAoB,QAAgB,EAAE,SAA6B;QACjE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;IAC5B,CAAC;IAEM,KAAK,CAAC,SAAS,CAAE,QAAyB,EAAE,OAAc;QAC/D,IAAI,QAAQ,KAAK,IAAI;YACnB,OAAO,KAAK,CAAA;QAEd,
|
|
1
|
+
{"version":3,"file":"Delegate.js","sourceRoot":"","sources":["../../../source/directives/auth/Delegate.ts"],"names":[],"mappings":";;;AAAA,qCAAuC;AAEvC,iCAA6B;AAI7B,MAAa,QAAQ;IACF,QAAQ,CAAQ;IAChB,SAAS,CAAoB;IAE9C,YAAoB,QAAgB,EAAE,SAA6B;QACjE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;IAC5B,CAAC;IAEM,KAAK,CAAC,SAAS,CAAE,QAAyB,EAAE,OAAc;QAC/D,IAAI,QAAQ,KAAK,IAAI;YACnB,OAAO,KAAK,CAAA;QAEd,QAAQ,CAAC,KAAK,KAAK,MAAM,WAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QAC3D,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;QAEjE,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,KAAK,CAAE,IAAa,EAAE,QAAkB;QAC9C,IAAI,IAAI,KAAK,SAAS;YACpB,IAAI,GAAG,EAAE,CAAA;QAEX,KAAK,CAAC,IAAI,CAAC,CAAA;QACX,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAA;QAE/C,OAAO,IAAI,CAAA;IACb,CAAC;CACF;AA5BD,4BA4BC;AAED,SAAS,KAAK,CAAE,IAAa;IAC3B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAC3C,MAAM,IAAI,iBAAU,CAAC,sBAAsB,CAAC,CAAA;AAChD,CAAC"}
|
|
@@ -7,7 +7,7 @@ export declare class Role implements Directive {
|
|
|
7
7
|
private readonly discovery;
|
|
8
8
|
private readonly dynamic;
|
|
9
9
|
constructor(roles: string | string[], discovery: Promise<Component>);
|
|
10
|
-
static
|
|
10
|
+
static get(identity: Identity, discovery: Promise<Component>): Promise<string[]>;
|
|
11
11
|
authorize(identity: Identity | null, _: unknown, parameters: Parameter[]): Promise<boolean>;
|
|
12
12
|
private match;
|
|
13
13
|
private substitute;
|