@toa.io/extensions.exposition 1.0.0-alpha.278 → 1.0.0-alpha.282
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/CHANGELOG.md +31 -0
- package/components/identity.basic/events/principal.js +5 -1
- package/components/identity.basic/manifest.toa.yaml +11 -1
- package/components/identity.basic/operations/authenticate.js +9 -5
- package/components/identity.basic/operations/authenticate.js.map +1 -1
- package/components/identity.basic/operations/check.js +2 -1
- package/components/identity.basic/operations/check.js.map +1 -1
- package/components/identity.basic/operations/incept.js +4 -5
- package/components/identity.basic/operations/incept.js.map +1 -1
- package/components/identity.basic/operations/lib/credentials.d.ts +5 -0
- package/components/identity.basic/operations/lib/credentials.js +12 -0
- package/components/identity.basic/operations/lib/credentials.js.map +1 -0
- package/components/identity.basic/operations/transit.d.ts +2 -0
- package/components/identity.basic/operations/transit.js +12 -2
- package/components/identity.basic/operations/transit.js.map +1 -1
- package/components/identity.basic/operations/types.d.ts +11 -1
- package/components/identity.basic/source/authenticate.ts +11 -5
- package/components/identity.basic/source/check.ts +2 -1
- package/components/identity.basic/source/incept.ts +5 -5
- package/components/identity.basic/source/lib/credentials.test.ts +18 -0
- package/components/identity.basic/source/lib/credentials.ts +13 -0
- package/components/identity.basic/source/transit.ts +16 -4
- package/components/identity.basic/source/types.ts +13 -1
- package/components/identity.basic/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/events/principal.js +1 -0
- package/components/identity.federation/manifest.toa.yaml +5 -1
- package/components/identity.federation/operations/authenticate.js +3 -3
- package/components/identity.federation/operations/authenticate.js.map +1 -1
- package/components/identity.federation/operations/create.js +5 -1
- package/components/identity.federation/operations/create.js.map +1 -1
- package/components/identity.federation/operations/lib/decode.js +5 -1
- package/components/identity.federation/operations/lib/decode.js.map +1 -1
- package/components/identity.federation/operations/lib/exchange.js +3 -3
- package/components/identity.federation/operations/lib/exchange.js.map +1 -1
- package/components/identity.federation/operations/list.js +2 -1
- package/components/identity.federation/operations/list.js.map +1 -1
- package/components/identity.federation/operations/types/configuration.d.ts +2 -1
- package/components/identity.federation/source/authenticate.ts +3 -3
- package/components/identity.federation/source/create.ts +5 -1
- package/components/identity.federation/source/lib/decode.ts +5 -1
- package/components/identity.federation/source/lib/exchange.ts +3 -3
- package/components/identity.federation/source/list.test.ts +1 -1
- package/components/identity.federation/source/list.ts +2 -1
- package/components/identity.federation/source/types/configuration.ts +2 -1
- package/components/identity.federation/tsconfig.tsbuildinfo +1 -1
- package/components/identity.keys/manifest.toa.yaml +18 -1
- package/components/identity.keys/operations/disable.d.ts +5 -0
- package/components/identity.keys/operations/disable.js +5 -0
- package/components/identity.keys/operations/disable.js.map +1 -0
- package/components/identity.keys/operations/revoke.d.ts +15 -0
- package/components/identity.keys/operations/revoke.js +12 -0
- package/components/identity.keys/operations/revoke.js.map +1 -0
- package/components/identity.keys/receivers/identity.bans.created.js +1 -0
- package/components/identity.keys/receivers/identity.bans.updated.js +1 -0
- package/components/identity.keys/receivers/identity.roles.deleted.js +1 -0
- package/components/identity.keys/source/disable.ts +9 -0
- package/components/identity.keys/source/revoke.ts +30 -0
- package/components/identity.keys/tsconfig.tsbuildinfo +1 -1
- package/components/identity.otp/manifest.toa.yaml +6 -0
- package/components/identity.otp/operations/authenticate.js +13 -1
- package/components/identity.otp/operations/authenticate.js.map +1 -1
- package/components/identity.otp/operations/issue.js +3 -2
- package/components/identity.otp/operations/issue.js.map +1 -1
- package/components/identity.otp/operations/lib/Context.d.ts +1 -0
- package/components/identity.otp/source/authenticate.ts +19 -1
- package/components/identity.otp/source/issue.ts +3 -2
- package/components/identity.otp/source/lib/Context.ts +1 -0
- package/components/identity.otp/tsconfig.tsbuildinfo +1 -1
- package/components/identity.passkeys/operations/authenticate.js +2 -1
- package/components/identity.passkeys/operations/authenticate.js.map +1 -1
- package/components/identity.passkeys/operations/challenge.js +3 -3
- package/components/identity.passkeys/operations/challenge.js.map +1 -1
- package/components/identity.passkeys/operations/delete.js +2 -1
- package/components/identity.passkeys/operations/delete.js.map +1 -1
- package/components/identity.passkeys/operations/list.js +2 -1
- package/components/identity.passkeys/operations/list.js.map +1 -1
- package/components/identity.passkeys/source/authenticate.ts +2 -1
- package/components/identity.passkeys/source/challenge.ts +3 -3
- package/components/identity.passkeys/source/delete.ts +2 -1
- package/components/identity.passkeys/source/list.ts +2 -1
- package/components/identity.passkeys/tsconfig.tsbuildinfo +1 -1
- package/components/identity.roles/manifest.toa.yaml +4 -0
- package/components/identity.roles/operations/grant.js +5 -2
- package/components/identity.roles/operations/grant.js.map +1 -1
- package/components/identity.roles/source/grant.ts +6 -2
- package/components/identity.roles/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/manifest.toa.yaml +3 -0
- package/components/identity.tokens/operations/authenticate.js +4 -3
- package/components/identity.tokens/operations/authenticate.js.map +1 -1
- package/components/identity.tokens/operations/decrypt.js +7 -1
- package/components/identity.tokens/operations/decrypt.js.map +1 -1
- package/components/identity.tokens/operations/encrypt.js +3 -2
- package/components/identity.tokens/operations/encrypt.js.map +1 -1
- package/components/identity.tokens/operations/issue.js +2 -1
- package/components/identity.tokens/operations/issue.js.map +1 -1
- package/components/identity.tokens/operations/lib/types.d.ts +3 -0
- package/components/identity.tokens/source/authenticate.test.ts +26 -2
- package/components/identity.tokens/source/authenticate.ts +4 -3
- package/components/identity.tokens/source/decrypt.test.ts +35 -1
- package/components/identity.tokens/source/decrypt.ts +10 -1
- package/components/identity.tokens/source/encrypt.test.ts +15 -0
- package/components/identity.tokens/source/encrypt.ts +4 -2
- package/components/identity.tokens/source/issue.ts +2 -1
- package/components/identity.tokens/source/lib/types.ts +4 -0
- package/components/identity.tokens/tsconfig.tsbuildinfo +1 -1
- package/documentation/authorities.md +3 -0
- package/documentation/components.md +31 -11
- package/documentation/identity.md +38 -6
- package/documentation/io.md +2 -2
- package/documentation/ip.md +24 -0
- package/documentation/passkeys.md +6 -0
- package/features/auth.assert.feature +2 -4
- package/features/auth.claims.feature +1 -0
- package/features/auth.incept.feature +46 -0
- package/features/authorities.feature +39 -0
- package/features/authorities.federation.feature +1 -0
- package/features/identity.bans.feature +63 -0
- package/features/identity.basic.feature +95 -3
- package/features/identity.feature +151 -0
- package/features/identity.federation.feature +5 -0
- package/features/identity.otp.feature +41 -0
- package/features/identity.roles.feature +252 -0
- package/features/identity.tokens.custom.feature +145 -0
- package/features/map.feature +2 -0
- package/features/steps/Gateway.ts +8 -2
- package/features/steps/Realtime.ts +1 -1
- package/package.json +5 -5
- package/readme.md +3 -0
- package/schemas/annotation.cos.yaml +16 -0
- package/source/Annotation.ts +14 -0
- package/source/Composition.ts +5 -5
- package/source/Directive.test.ts +3 -1
- package/source/Directive.ts +6 -2
- package/source/Endpoint.ts +4 -2
- package/source/Factory.ts +12 -9
- package/source/HTTP/Context.ts +12 -2
- package/source/HTTP/Server.ts +16 -3
- package/source/HTTP/address.test.ts +22 -0
- package/source/HTTP/address.ts +17 -0
- package/source/Query.test.ts +15 -1
- package/source/Query.ts +3 -1
- package/source/RTD/Directives.ts +10 -1
- package/source/Remotes.test.ts +7 -12
- package/source/Remotes.ts +5 -5
- package/source/const.ts +3 -0
- package/source/deployment.ts +7 -1
- package/source/directives/auth/Assert.ts +3 -0
- package/source/directives/auth/Authorization.test.ts +24 -0
- package/source/directives/auth/Authorization.ts +80 -11
- package/source/directives/auth/Incept.ts +9 -4
- package/source/directives/auth/Role.test.ts +1 -1
- package/source/directives/auth/Role.ts +2 -1
- package/source/directives/auth/schemes.test.ts +14 -0
- package/source/directives/auth/schemes.ts +14 -0
- package/source/directives/auth/types.ts +3 -0
- package/source/directives/io/IO.ts +10 -3
- package/source/directives/io/lib/throttle/Keys.ts +10 -3
- package/source/directives/io/lib/throttle/Quotas.test.ts +14 -4
- package/source/directives/io/lib/throttle/Quotas.ts +15 -2
- package/source/directives/io/lib/throttle/Sync.test.ts +7 -9
- package/source/directives/io/lib/throttle/Sync.ts +4 -7
- package/source/directives/io/lib/throttle/Warning.test.ts +32 -0
- package/source/directives/io/lib/throttle/Warning.ts +30 -0
- package/source/directives/io/lib/throttle/components/Component.ts +2 -1
- package/source/directives/io/lib/throttle/components/IP.ts +19 -28
- package/source/directives/io/lib/throttle/index.ts +1 -0
- package/source/redact.test.ts +27 -0
- package/source/redact.ts +21 -0
- package/source/schemas.test.ts +17 -0
- package/transpiled/Annotation.d.ts +10 -0
- package/transpiled/Composition.d.ts +3 -3
- package/transpiled/Composition.js +4 -4
- package/transpiled/Composition.js.map +1 -1
- package/transpiled/Directive.d.ts +3 -2
- package/transpiled/Directive.js +3 -1
- package/transpiled/Directive.js.map +1 -1
- package/transpiled/Endpoint.js +3 -2
- package/transpiled/Endpoint.js.map +1 -1
- package/transpiled/Factory.d.ts +3 -3
- package/transpiled/Factory.js +11 -8
- package/transpiled/Factory.js.map +1 -1
- package/transpiled/HTTP/Context.d.ts +4 -0
- package/transpiled/HTTP/Context.js +7 -2
- package/transpiled/HTTP/Context.js.map +1 -1
- package/transpiled/HTTP/Server.d.ts +5 -0
- package/transpiled/HTTP/Server.js +8 -3
- package/transpiled/HTTP/Server.js.map +1 -1
- package/transpiled/HTTP/address.d.ts +7 -0
- package/transpiled/HTTP/address.js +14 -0
- package/transpiled/HTTP/address.js.map +1 -0
- package/transpiled/Query.js +3 -1
- package/transpiled/Query.js.map +1 -1
- package/transpiled/RTD/Directives.d.ts +9 -1
- package/transpiled/Remotes.d.ts +3 -3
- package/transpiled/Remotes.js +4 -4
- package/transpiled/Remotes.js.map +1 -1
- package/transpiled/const.d.ts +2 -0
- package/transpiled/const.js +2 -0
- package/transpiled/const.js.map +1 -1
- package/transpiled/deployment.js +4 -0
- package/transpiled/deployment.js.map +1 -1
- package/transpiled/directives/auth/Assert.js +2 -0
- package/transpiled/directives/auth/Assert.js.map +1 -1
- package/transpiled/directives/auth/Authorization.d.ts +8 -0
- package/transpiled/directives/auth/Authorization.js +61 -11
- package/transpiled/directives/auth/Authorization.js.map +1 -1
- package/transpiled/directives/auth/Incept.d.ts +3 -1
- package/transpiled/directives/auth/Incept.js +8 -4
- package/transpiled/directives/auth/Incept.js.map +1 -1
- package/transpiled/directives/auth/Role.js +2 -1
- package/transpiled/directives/auth/Role.js.map +1 -1
- package/transpiled/directives/auth/schemes.d.ts +10 -0
- package/transpiled/directives/auth/schemes.js +12 -0
- package/transpiled/directives/auth/schemes.js.map +1 -1
- package/transpiled/directives/auth/types.d.ts +2 -0
- package/transpiled/directives/io/IO.d.ts +4 -1
- package/transpiled/directives/io/IO.js +7 -3
- package/transpiled/directives/io/IO.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Keys.d.ts +2 -1
- package/transpiled/directives/io/lib/throttle/Keys.js +7 -2
- package/transpiled/directives/io/lib/throttle/Keys.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Quotas.d.ts +3 -2
- package/transpiled/directives/io/lib/throttle/Quotas.js +8 -1
- package/transpiled/directives/io/lib/throttle/Quotas.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Sync.d.ts +2 -3
- package/transpiled/directives/io/lib/throttle/Sync.js +1 -3
- package/transpiled/directives/io/lib/throttle/Sync.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Warning.d.ts +11 -0
- package/transpiled/directives/io/lib/throttle/Warning.js +24 -0
- package/transpiled/directives/io/lib/throttle/Warning.js.map +1 -0
- package/transpiled/directives/io/lib/throttle/components/Component.d.ts +2 -1
- package/transpiled/directives/io/lib/throttle/components/IP.d.ts +10 -2
- package/transpiled/directives/io/lib/throttle/components/IP.js +18 -23
- package/transpiled/directives/io/lib/throttle/components/IP.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/index.d.ts +1 -0
- package/transpiled/directives/io/lib/throttle/index.js +1 -0
- package/transpiled/directives/io/lib/throttle/index.js.map +1 -1
- package/transpiled/redact.d.ts +5 -0
- package/transpiled/redact.js +17 -0
- package/transpiled/redact.js.map +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/components/exposition.atom/manifest.toa.yaml +0 -21
- package/components/exposition.atom/operations/meter.js +0 -5
|
@@ -54,10 +54,33 @@ The `Token` is the **primary** authentication scheme.
|
|
|
54
54
|
If request originators use an alternative authentication scheme, they will receive a response
|
|
55
55
|
containing `Token` credentials and will be required to switch to the `Token` scheme for any
|
|
56
56
|
subsequent requests.
|
|
57
|
-
Continued use of other authentication schemes will result in temporary blocking of requests.
|
|
58
57
|
|
|
59
58
|
See [`identity.tokens` component](components.md#local-tokens).
|
|
60
59
|
|
|
60
|
+
### Failed authentications
|
|
61
|
+
|
|
62
|
+
Credentials that are rejected can be metered per client address, whatever the scheme. An address
|
|
63
|
+
may fail `attempts` at once and earns them back at `attempts` per `interval` seconds; a request
|
|
64
|
+
carrying credentials from an address with nothing left is answered `429 Too Many Requests` with
|
|
65
|
+
`Retry-After`. Nothing is metered unless the exposition annotation carries `bouncer`;
|
|
66
|
+
`attempts` and `interval` default to 20 and 60. The address is the one the request context
|
|
67
|
+
resolved, see [Client address](ip.md): `bouncer` requires `ip`, in the same environment, and a
|
|
68
|
+
request without an address is not metered.
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
# context.toa.yaml
|
|
72
|
+
|
|
73
|
+
exposition:
|
|
74
|
+
ip: cf-connecting-ip
|
|
75
|
+
bouncer:
|
|
76
|
+
attempts: 20
|
|
77
|
+
interval: 60
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The count is shared by the gateway replicas through
|
|
81
|
+
[atomicity](../../../connectors/atomicity/readme.md) and decided in each process; nothing is read on
|
|
82
|
+
the request path.
|
|
83
|
+
|
|
61
84
|
### Bearer scheme
|
|
62
85
|
|
|
63
86
|
OpenID tokens issued by trusted providers.
|
|
@@ -85,13 +108,15 @@ configuration:
|
|
|
85
108
|
aud: <APPLE_CLIENT_ID>
|
|
86
109
|
secret: <APPLE_CLIENT_SECRET> # enables Authorization Code Flow
|
|
87
110
|
principal:
|
|
111
|
+
authority: example
|
|
88
112
|
iss: https://accounts.google.com
|
|
89
113
|
sub: 4218230498234
|
|
90
114
|
assert: true
|
|
91
115
|
```
|
|
92
116
|
|
|
93
|
-
`principal` specifies the values of the `iss` and `sub` claims of an Identity
|
|
94
|
-
with a `system` role.
|
|
117
|
+
`principal` specifies the authority and the values of the `iss` and `sub` claims of an Identity
|
|
118
|
+
that will be granted with a `system` role. The same subject in another authority is ordinary
|
|
119
|
+
credentials.
|
|
95
120
|
|
|
96
121
|
`assert` indicates whether the Identity should be implicitly created when valid credentials for a
|
|
97
122
|
non-existent Identity are provided (default `true`).
|
|
@@ -113,8 +138,8 @@ iss: code issuer
|
|
|
113
138
|
for: redirect URI
|
|
114
139
|
```
|
|
115
140
|
|
|
116
|
-
Trust configuration for the issuer requires
|
|
117
|
-
|
|
141
|
+
Trust configuration for the issuer requires either `secret` or `signature`
|
|
142
|
+
to enable the Authorization Code Flow.
|
|
118
143
|
|
|
119
144
|
> If `aud` is an array, the first value is used.
|
|
120
145
|
|
|
@@ -159,13 +184,15 @@ GET /identity/ HTTP/1.1
|
|
|
159
184
|
authentication: OTP dXNlcm5hbWU6MTIzNDU2
|
|
160
185
|
```
|
|
161
186
|
|
|
162
|
-
OTP expiration time
|
|
187
|
+
OTP expiration time and the number of failed attempts a username is allowed within it can be
|
|
188
|
+
configured using the `identity.otp` configuration.
|
|
163
189
|
|
|
164
190
|
```yaml
|
|
165
191
|
# context.toa.yaml
|
|
166
192
|
configuration:
|
|
167
193
|
identity.otp:
|
|
168
194
|
lifetime: 60 # seconds
|
|
195
|
+
attempts: 5
|
|
169
196
|
```
|
|
170
197
|
|
|
171
198
|
## Identity inception
|
|
@@ -223,6 +250,11 @@ Identity `2428c31ecb6e4a51a24ef52f0c4181b9` are created.
|
|
|
223
250
|
|
|
224
251
|
Inception is supported for `Basic` and `Bearer` authentication schemes.
|
|
225
252
|
|
|
253
|
+
Inception goes ahead when the request carries no credentials, or credentials the scheme verified
|
|
254
|
+
and no Identity owns, which its `authenticate` operation reports as `NOT_FOUND`. Credentials
|
|
255
|
+
rejected for any other reason, a wrong password for one, are answered with `401 Unauthorized`
|
|
256
|
+
before the endpoint is called.
|
|
257
|
+
|
|
226
258
|
## Identity assertion
|
|
227
259
|
|
|
228
260
|
`auth:assert` directive is used to ensure that given credentials are associated with an existing
|
package/documentation/io.md
CHANGED
|
@@ -97,8 +97,8 @@ and reports what it could not the next time it gets through.
|
|
|
97
97
|
What a request is metered against. Give one, or a list — a list keys on the combination, so
|
|
98
98
|
`[route, ip]` meters each address separately on each route.
|
|
99
99
|
|
|
100
|
-
- `ip` — the client address,
|
|
101
|
-
|
|
100
|
+
- `ip` — the client address, as the request context resolved it. See [Client address](ip.md) for
|
|
101
|
+
where it is read from and why.
|
|
102
102
|
- `path` — the path the request came in on, `/users/1`.
|
|
103
103
|
- `route` — the route as declared, `/users/:id`. Every path matching the route shares one budget,
|
|
104
104
|
which `path` cannot do: keyed on `path`, walking ids is a way around the limit.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Client address
|
|
2
|
+
|
|
3
|
+
The address a request comes from is resolved once, into the request context, and read from there
|
|
4
|
+
by whatever keys on it: the meter of [failed authentications](identity.md#failed-authentications)
|
|
5
|
+
and the `ip` key of [`io:throttle`](io.md#key-components).
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
# context.toa.yaml
|
|
9
|
+
|
|
10
|
+
exposition:
|
|
11
|
+
ip: cf-connecting-ip
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`ip` names the header the address is read from. In production the gateway sits behind a load
|
|
15
|
+
balancer, an ingress or a CDN: the connection it accepts comes from that machine, so every client
|
|
16
|
+
shares one address and nothing tells them apart. The edge is the one that saw the client connect,
|
|
17
|
+
and it writes the client's address into a header of its own, `CF-Connecting-IP`, `X-Real-IP` or
|
|
18
|
+
`X-Forwarded-For`, depending on the infrastructure. A client may send any of these headers too, so
|
|
19
|
+
the gateway trusts none of them on its own: the deployment names the one its edge overwrites, and
|
|
20
|
+
where the header holds a list, the last value is the one the edge appended.
|
|
21
|
+
|
|
22
|
+
The connection's address is never used. Without `ip`, or for a request that does not carry the
|
|
23
|
+
header, the request has no address: the bouncer and a throttle keyed on `ip` let it through and
|
|
24
|
+
say so in the log, once per hundred seconds rather than once per request.
|
|
@@ -3,3 +3,9 @@
|
|
|
3
3
|
- [Standard](https://www.w3.org/TR/webauthn-2/)
|
|
4
4
|
- [Features](../features/passkeys.feature)
|
|
5
5
|
- [Credential management](credentials.md#passkeys)
|
|
6
|
+
|
|
7
|
+
## Origin
|
|
8
|
+
|
|
9
|
+
The relying party is the client. The origin a passkey is registered under, and the RP ID derived
|
|
10
|
+
from it, come from the request, so a passkey belongs to the origin of the client that registered
|
|
11
|
+
it, and a client on another origin does not see it.
|
|
@@ -41,7 +41,7 @@ Feature: Identity assertion
|
|
|
41
41
|
authorization: Token ${{ user.token }}
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
|
-
#
|
|
44
|
+
# wrong password for the credentials just created
|
|
45
45
|
When the following request is received:
|
|
46
46
|
"""
|
|
47
47
|
GET /echo/ HTTP/1.1
|
|
@@ -51,7 +51,5 @@ Feature: Identity assertion
|
|
|
51
51
|
"""
|
|
52
52
|
Then the following reply is sent:
|
|
53
53
|
"""
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
code: INVALID_PASSWORD
|
|
54
|
+
401 Unauthorized
|
|
57
55
|
"""
|
|
@@ -118,3 +118,49 @@ Feature: Identity inception
|
|
|
118
118
|
id: ${{ identity.id }}
|
|
119
119
|
foo: bar
|
|
120
120
|
"""
|
|
121
|
+
|
|
122
|
+
Scenario: Inception with a wrong password for existing credentials
|
|
123
|
+
Given the `identity.basic` database contains:
|
|
124
|
+
| _id | authority | username | password | _version |
|
|
125
|
+
| efe3a65ebbee47ed95a73edd911ea328 | nex | developer | $2b$10$ZRSKkgZoGnrcTNA5w5eCcu3pxDzdTduhteVYXcp56AaNcilNkwJ.O | 1 |
|
|
126
|
+
And the `users` is running with the following manifest:
|
|
127
|
+
"""yaml
|
|
128
|
+
exposition:
|
|
129
|
+
/:
|
|
130
|
+
POST:
|
|
131
|
+
io:input: [name]
|
|
132
|
+
io:output: true
|
|
133
|
+
incept: id
|
|
134
|
+
query: ~
|
|
135
|
+
endpoint: transit
|
|
136
|
+
"""
|
|
137
|
+
# developer:wrong
|
|
138
|
+
When the following request is received:
|
|
139
|
+
"""
|
|
140
|
+
POST /users/ HTTP/1.1
|
|
141
|
+
host: nex.toa.io
|
|
142
|
+
authorization: Basic ZGV2ZWxvcGVyOndyb25n
|
|
143
|
+
accept: application/yaml
|
|
144
|
+
content-type: application/yaml
|
|
145
|
+
|
|
146
|
+
name: Bill Smith
|
|
147
|
+
"""
|
|
148
|
+
Then the following reply is sent:
|
|
149
|
+
"""
|
|
150
|
+
401 Unauthorized
|
|
151
|
+
"""
|
|
152
|
+
# a token that does not decrypt
|
|
153
|
+
When the following request is received:
|
|
154
|
+
"""
|
|
155
|
+
POST /users/ HTTP/1.1
|
|
156
|
+
host: nex.toa.io
|
|
157
|
+
authorization: Token garbage
|
|
158
|
+
accept: application/yaml
|
|
159
|
+
content-type: application/yaml
|
|
160
|
+
|
|
161
|
+
name: Bill Smith
|
|
162
|
+
"""
|
|
163
|
+
Then the following reply is sent:
|
|
164
|
+
"""
|
|
165
|
+
401 Unauthorized
|
|
166
|
+
"""
|
|
@@ -30,3 +30,42 @@ Feature: Authorities
|
|
|
30
30
|
"""
|
|
31
31
|
200 OK
|
|
32
32
|
"""
|
|
33
|
+
|
|
34
|
+
Scenario: Rejecting a malformed authority
|
|
35
|
+
Given the annotation:
|
|
36
|
+
"""yaml
|
|
37
|
+
/:
|
|
38
|
+
anonymous: true
|
|
39
|
+
GET:
|
|
40
|
+
dev:stub: Hello
|
|
41
|
+
"""
|
|
42
|
+
When the following request is received:
|
|
43
|
+
"""
|
|
44
|
+
GET / HTTP/1.1
|
|
45
|
+
host: zzz,identity==abc,authority==q
|
|
46
|
+
"""
|
|
47
|
+
Then the following reply is sent:
|
|
48
|
+
"""
|
|
49
|
+
400 Bad Request
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
Scenario: Matching an authority regardless of case
|
|
53
|
+
Given the annotation:
|
|
54
|
+
"""yaml
|
|
55
|
+
authorities:
|
|
56
|
+
example: the.example.com
|
|
57
|
+
/:
|
|
58
|
+
anonymous: true
|
|
59
|
+
GET:
|
|
60
|
+
map:authority: authority
|
|
61
|
+
dev:stub: Hello
|
|
62
|
+
"""
|
|
63
|
+
When the following request is received:
|
|
64
|
+
"""
|
|
65
|
+
GET / HTTP/1.1
|
|
66
|
+
host: The.Example.COM
|
|
67
|
+
"""
|
|
68
|
+
Then the following reply is sent:
|
|
69
|
+
"""
|
|
70
|
+
200 OK
|
|
71
|
+
"""
|
|
@@ -135,3 +135,66 @@ Feature: Bans
|
|
|
135
135
|
"""
|
|
136
136
|
401 Unauthorized
|
|
137
137
|
"""
|
|
138
|
+
|
|
139
|
+
Scenario: Banning an Identity revokes its custom tokens
|
|
140
|
+
Given the `identity.roles` database contains:
|
|
141
|
+
| _id | identity | role |
|
|
142
|
+
| 775a648d054e4ce1a65f8f17e5b51803 | efe3a65ebbee47ed95a73edd911ea328 | system:identity:bans |
|
|
143
|
+
And the `identity.keys` database is empty
|
|
144
|
+
And the `identity.tokens` configuration:
|
|
145
|
+
"""yaml
|
|
146
|
+
cache:
|
|
147
|
+
ttl: 1
|
|
148
|
+
"""
|
|
149
|
+
When the following request is received:
|
|
150
|
+
"""
|
|
151
|
+
POST /identity/tokens/e8e4f9c2a68d419b861403d71fabc915/ HTTP/1.1
|
|
152
|
+
host: nex.toa.io
|
|
153
|
+
authorization: Basic dXNlcjoxMjM0NQ==
|
|
154
|
+
accept: application/yaml
|
|
155
|
+
content-type: application/yaml
|
|
156
|
+
|
|
157
|
+
label: Forever token
|
|
158
|
+
lifetime: 0
|
|
159
|
+
"""
|
|
160
|
+
Then the following reply is sent:
|
|
161
|
+
"""
|
|
162
|
+
201 Created
|
|
163
|
+
|
|
164
|
+
token: ${{ token }}
|
|
165
|
+
"""
|
|
166
|
+
When the following request is received:
|
|
167
|
+
"""
|
|
168
|
+
GET /identity/ HTTP/1.1
|
|
169
|
+
host: nex.toa.io
|
|
170
|
+
authorization: Token ${{ token }}
|
|
171
|
+
"""
|
|
172
|
+
Then the following reply is sent:
|
|
173
|
+
"""
|
|
174
|
+
200 OK
|
|
175
|
+
"""
|
|
176
|
+
When the following request is received:
|
|
177
|
+
"""
|
|
178
|
+
PUT /identity/bans/e8e4f9c2a68d419b861403d71fabc915/ HTTP/1.1
|
|
179
|
+
host: nex.toa.io
|
|
180
|
+
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
181
|
+
content-type: application/yaml
|
|
182
|
+
|
|
183
|
+
banned: true
|
|
184
|
+
"""
|
|
185
|
+
Then the following reply is sent:
|
|
186
|
+
"""
|
|
187
|
+
200 OK
|
|
188
|
+
"""
|
|
189
|
+
# the key is revoked eventually, and the runtime forgets it after `cache.ttl`
|
|
190
|
+
Then after 2 seconds
|
|
191
|
+
When the following request is received:
|
|
192
|
+
"""
|
|
193
|
+
GET /identity/ HTTP/1.1
|
|
194
|
+
host: nex.toa.io
|
|
195
|
+
authorization: Token ${{ token }}
|
|
196
|
+
"""
|
|
197
|
+
Then the following reply is sent:
|
|
198
|
+
"""
|
|
199
|
+
401 Unauthorized
|
|
200
|
+
"""
|
|
@@ -88,7 +88,7 @@ Feature: Basic authentication
|
|
|
88
88
|
200 OK
|
|
89
89
|
"""
|
|
90
90
|
|
|
91
|
-
# username is taken
|
|
91
|
+
# username is taken: a wrong password for existing credentials is refused before the call
|
|
92
92
|
When the following request is received:
|
|
93
93
|
"""
|
|
94
94
|
POST /users/ HTTP/1.1
|
|
@@ -101,7 +101,7 @@ Feature: Basic authentication
|
|
|
101
101
|
"""
|
|
102
102
|
Then the following reply is sent:
|
|
103
103
|
"""
|
|
104
|
-
|
|
104
|
+
401 Unauthorized
|
|
105
105
|
"""
|
|
106
106
|
|
|
107
107
|
# credentials already exists
|
|
@@ -246,7 +246,9 @@ Feature: Basic authentication
|
|
|
246
246
|
Scenario: Granting a `system` role to a Principal
|
|
247
247
|
Given the `identity.basic` configuration:
|
|
248
248
|
"""yaml
|
|
249
|
-
principal:
|
|
249
|
+
principal:
|
|
250
|
+
authority: nex
|
|
251
|
+
username: root
|
|
250
252
|
"""
|
|
251
253
|
And the annotation:
|
|
252
254
|
"""yaml
|
|
@@ -321,6 +323,64 @@ Feature: Basic authentication
|
|
|
321
323
|
message: Principal username cannot be changed
|
|
322
324
|
"""
|
|
323
325
|
|
|
326
|
+
Scenario: Principal username in another authority is ordinary credentials
|
|
327
|
+
Given the `identity.basic` configuration:
|
|
328
|
+
"""yaml
|
|
329
|
+
principal:
|
|
330
|
+
authority: nex
|
|
331
|
+
username: root
|
|
332
|
+
"""
|
|
333
|
+
And the annotation:
|
|
334
|
+
"""yaml
|
|
335
|
+
/:
|
|
336
|
+
io:output: true
|
|
337
|
+
GET:
|
|
338
|
+
auth:role: system:stub
|
|
339
|
+
dev:stub:
|
|
340
|
+
access: granted!
|
|
341
|
+
"""
|
|
342
|
+
When the following request is received:
|
|
343
|
+
"""
|
|
344
|
+
POST /identity/basic/ HTTP/1.1
|
|
345
|
+
host: the.other.com
|
|
346
|
+
accept: application/yaml
|
|
347
|
+
content-type: application/yaml
|
|
348
|
+
|
|
349
|
+
username: root
|
|
350
|
+
password: secret#1234
|
|
351
|
+
"""
|
|
352
|
+
Then the following reply is sent:
|
|
353
|
+
"""
|
|
354
|
+
201 Created
|
|
355
|
+
|
|
356
|
+
id: ${{ id }}
|
|
357
|
+
"""
|
|
358
|
+
Then after 0.1 seconds
|
|
359
|
+
When the following request is received:
|
|
360
|
+
"""
|
|
361
|
+
GET /identity/roles/${{ id }}/ HTTP/1.1
|
|
362
|
+
host: the.other.com
|
|
363
|
+
authorization: Basic cm9vdDpzZWNyZXQjMTIzNA==
|
|
364
|
+
accept: application/yaml
|
|
365
|
+
"""
|
|
366
|
+
Then the following reply is sent:
|
|
367
|
+
"""
|
|
368
|
+
200 OK
|
|
369
|
+
|
|
370
|
+
[]
|
|
371
|
+
"""
|
|
372
|
+
When the following request is received:
|
|
373
|
+
"""
|
|
374
|
+
GET / HTTP/1.1
|
|
375
|
+
host: the.other.com
|
|
376
|
+
authorization: Basic cm9vdDpzZWNyZXQjMTIzNA==
|
|
377
|
+
accept: application/yaml
|
|
378
|
+
"""
|
|
379
|
+
Then the following reply is sent:
|
|
380
|
+
"""
|
|
381
|
+
403 Forbidden
|
|
382
|
+
"""
|
|
383
|
+
|
|
324
384
|
Scenario: Creating an Identity using inception with existing credentials
|
|
325
385
|
Given the `users` is running with the following manifest:
|
|
326
386
|
"""yaml
|
|
@@ -528,3 +588,35 @@ Feature: Basic authentication
|
|
|
528
588
|
|
|
529
589
|
id: ${{ identity.id }}
|
|
530
590
|
"""
|
|
591
|
+
|
|
592
|
+
Scenario: Password containing colons
|
|
593
|
+
When the following request is received:
|
|
594
|
+
"""
|
|
595
|
+
POST /identity/basic/ HTTP/1.1
|
|
596
|
+
host: nex.toa.io
|
|
597
|
+
accept: application/yaml
|
|
598
|
+
content-type: application/yaml
|
|
599
|
+
|
|
600
|
+
username: colon
|
|
601
|
+
password: pa:ss:word
|
|
602
|
+
"""
|
|
603
|
+
Then the following reply is sent:
|
|
604
|
+
"""
|
|
605
|
+
201 Created
|
|
606
|
+
|
|
607
|
+
id: ${{ id }}
|
|
608
|
+
"""
|
|
609
|
+
# colon:pa:ss:word
|
|
610
|
+
When the following request is received:
|
|
611
|
+
"""
|
|
612
|
+
GET /identity/ HTTP/1.1
|
|
613
|
+
host: nex.toa.io
|
|
614
|
+
authorization: Basic Y29sb246cGE6c3M6d29yZA==
|
|
615
|
+
accept: application/yaml
|
|
616
|
+
"""
|
|
617
|
+
Then the following reply is sent:
|
|
618
|
+
"""
|
|
619
|
+
200 OK
|
|
620
|
+
|
|
621
|
+
id: ${{ id }}
|
|
622
|
+
"""
|
|
@@ -87,3 +87,154 @@ Feature: Identity resource
|
|
|
87
87
|
"""
|
|
88
88
|
401 Unauthorized
|
|
89
89
|
"""
|
|
90
|
+
|
|
91
|
+
Scenario: Authenticating with a scheme named after an object property
|
|
92
|
+
When the following request is received:
|
|
93
|
+
"""
|
|
94
|
+
GET /identity/ HTTP/1.1
|
|
95
|
+
host: nex.toa.io
|
|
96
|
+
authorization: Constructor abc
|
|
97
|
+
"""
|
|
98
|
+
Then the following reply is sent:
|
|
99
|
+
"""
|
|
100
|
+
401 Unauthorized
|
|
101
|
+
"""
|
|
102
|
+
When the following request is received:
|
|
103
|
+
"""
|
|
104
|
+
GET /identity/ HTTP/1.1
|
|
105
|
+
host: nex.toa.io
|
|
106
|
+
authorization: __proto__ abc
|
|
107
|
+
"""
|
|
108
|
+
Then the following reply is sent:
|
|
109
|
+
"""
|
|
110
|
+
401 Unauthorized
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
Scenario: Failing authentication repeatedly
|
|
114
|
+
Given the annotation:
|
|
115
|
+
"""yaml
|
|
116
|
+
ip: x-real-ip
|
|
117
|
+
bouncer:
|
|
118
|
+
attempts: 2
|
|
119
|
+
interval: 60
|
|
120
|
+
"""
|
|
121
|
+
# developer:wrong
|
|
122
|
+
When the following request is received:
|
|
123
|
+
"""
|
|
124
|
+
GET /identity/ HTTP/1.1
|
|
125
|
+
host: nex.toa.io
|
|
126
|
+
x-real-ip: 203.0.113.9
|
|
127
|
+
authorization: Basic ZGV2ZWxvcGVyOndyb25n
|
|
128
|
+
"""
|
|
129
|
+
Then the following reply is sent:
|
|
130
|
+
"""
|
|
131
|
+
401 Unauthorized
|
|
132
|
+
"""
|
|
133
|
+
When the following request is received:
|
|
134
|
+
"""
|
|
135
|
+
GET /identity/ HTTP/1.1
|
|
136
|
+
host: nex.toa.io
|
|
137
|
+
x-real-ip: 203.0.113.9
|
|
138
|
+
authorization: Basic ZGV2ZWxvcGVyOndyb25n
|
|
139
|
+
"""
|
|
140
|
+
Then the following reply is sent:
|
|
141
|
+
"""
|
|
142
|
+
401 Unauthorized
|
|
143
|
+
"""
|
|
144
|
+
# the address has spent its attempts, and earns one back in interval / attempts seconds
|
|
145
|
+
When the following request is received:
|
|
146
|
+
"""
|
|
147
|
+
GET /identity/ HTTP/1.1
|
|
148
|
+
host: nex.toa.io
|
|
149
|
+
x-real-ip: 203.0.113.9
|
|
150
|
+
authorization: Basic ZGV2ZWxvcGVyOndyb25n
|
|
151
|
+
"""
|
|
152
|
+
Then the following reply is sent:
|
|
153
|
+
"""
|
|
154
|
+
429 Too Many Requests
|
|
155
|
+
retry-after: 30
|
|
156
|
+
"""
|
|
157
|
+
# a request without credentials is not metered
|
|
158
|
+
When the following request is received:
|
|
159
|
+
"""
|
|
160
|
+
GET /identity/ HTTP/1.1
|
|
161
|
+
host: nex.toa.io
|
|
162
|
+
"""
|
|
163
|
+
Then the following reply is sent:
|
|
164
|
+
"""
|
|
165
|
+
201 Created
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
Scenario: Failing authentication behind a trusted proxy
|
|
169
|
+
Given the annotation:
|
|
170
|
+
"""yaml
|
|
171
|
+
ip: x-real-ip
|
|
172
|
+
bouncer:
|
|
173
|
+
attempts: 1
|
|
174
|
+
interval: 60
|
|
175
|
+
"""
|
|
176
|
+
# developer:wrong
|
|
177
|
+
When the following request is received:
|
|
178
|
+
"""
|
|
179
|
+
GET /identity/ HTTP/1.1
|
|
180
|
+
host: nex.toa.io
|
|
181
|
+
x-real-ip: 203.0.113.1
|
|
182
|
+
authorization: Basic ZGV2ZWxvcGVyOndyb25n
|
|
183
|
+
"""
|
|
184
|
+
Then the following reply is sent:
|
|
185
|
+
"""
|
|
186
|
+
401 Unauthorized
|
|
187
|
+
"""
|
|
188
|
+
When the following request is received:
|
|
189
|
+
"""
|
|
190
|
+
GET /identity/ HTTP/1.1
|
|
191
|
+
host: nex.toa.io
|
|
192
|
+
x-real-ip: 203.0.113.1
|
|
193
|
+
authorization: Basic ZGV2ZWxvcGVyOndyb25n
|
|
194
|
+
"""
|
|
195
|
+
Then the following reply is sent:
|
|
196
|
+
"""
|
|
197
|
+
429 Too Many Requests
|
|
198
|
+
"""
|
|
199
|
+
# another address, as the proxy reports it
|
|
200
|
+
When the following request is received:
|
|
201
|
+
"""
|
|
202
|
+
GET /identity/ HTTP/1.1
|
|
203
|
+
host: nex.toa.io
|
|
204
|
+
x-real-ip: 203.0.113.2
|
|
205
|
+
authorization: Basic ZGV2ZWxvcGVyOndyb25n
|
|
206
|
+
"""
|
|
207
|
+
Then the following reply is sent:
|
|
208
|
+
"""
|
|
209
|
+
401 Unauthorized
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
Scenario: Failing authentication without a client address
|
|
213
|
+
Given the annotation:
|
|
214
|
+
"""yaml
|
|
215
|
+
ip: x-real-ip
|
|
216
|
+
bouncer:
|
|
217
|
+
attempts: 1
|
|
218
|
+
interval: 60
|
|
219
|
+
"""
|
|
220
|
+
# the header the address is read from is not sent, so nothing is metered
|
|
221
|
+
When the following request is received:
|
|
222
|
+
"""
|
|
223
|
+
GET /identity/ HTTP/1.1
|
|
224
|
+
host: nex.toa.io
|
|
225
|
+
authorization: Basic ZGV2ZWxvcGVyOndyb25n
|
|
226
|
+
"""
|
|
227
|
+
Then the following reply is sent:
|
|
228
|
+
"""
|
|
229
|
+
401 Unauthorized
|
|
230
|
+
"""
|
|
231
|
+
When the following request is received:
|
|
232
|
+
"""
|
|
233
|
+
GET /identity/ HTTP/1.1
|
|
234
|
+
host: nex.toa.io
|
|
235
|
+
authorization: Basic ZGV2ZWxvcGVyOndyb25n
|
|
236
|
+
"""
|
|
237
|
+
Then the following reply is sent:
|
|
238
|
+
"""
|
|
239
|
+
401 Unauthorized
|
|
240
|
+
"""
|
|
@@ -10,6 +10,7 @@ Feature: Identity Federation
|
|
|
10
10
|
"""yaml
|
|
11
11
|
trust:
|
|
12
12
|
- iss: http://localhost:44444
|
|
13
|
+
aud: test
|
|
13
14
|
"""
|
|
14
15
|
And the IDP token for User is issued
|
|
15
16
|
When the following request is received:
|
|
@@ -75,6 +76,7 @@ Feature: Identity Federation
|
|
|
75
76
|
"""yaml
|
|
76
77
|
trust:
|
|
77
78
|
- iss: http://localhost:44444
|
|
79
|
+
aud: test
|
|
78
80
|
assert: false
|
|
79
81
|
"""
|
|
80
82
|
Given the `users` is running with the following manifest:
|
|
@@ -170,7 +172,9 @@ Feature: Identity Federation
|
|
|
170
172
|
"""yaml
|
|
171
173
|
trust:
|
|
172
174
|
- iss: http://localhost:44444
|
|
175
|
+
aud: test
|
|
173
176
|
principal:
|
|
177
|
+
authority: nex
|
|
174
178
|
iss: http://localhost:44444
|
|
175
179
|
sub: root
|
|
176
180
|
"""
|
|
@@ -218,6 +222,7 @@ Feature: Identity Federation
|
|
|
218
222
|
"""yaml
|
|
219
223
|
trust:
|
|
220
224
|
- iss: http://localhost:44444
|
|
225
|
+
aud: test
|
|
221
226
|
"""
|
|
222
227
|
And the `identity.basic` database is empty
|
|
223
228
|
|