@toa.io/extensions.exposition 1.0.0-alpha.21 → 1.0.0-alpha.23
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/context.toa.yaml +2 -2
- package/components/identity.basic/manifest.toa.yaml +18 -9
- package/components/identity.basic/operations/authenticate.d.ts +5 -1
- 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.d.ts +11 -0
- package/components/identity.basic/operations/incept.js +13 -0
- package/components/identity.basic/operations/incept.js.map +1 -0
- package/components/identity.basic/operations/transit.d.ts +3 -3
- package/components/identity.basic/operations/transit.js +5 -3
- package/components/identity.basic/operations/transit.js.map +1 -1
- package/components/identity.basic/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.basic/operations/types.d.ts +2 -0
- package/components/identity.basic/source/authenticate.ts +12 -5
- package/components/identity.basic/source/incept.ts +22 -0
- package/components/identity.basic/source/transit.ts +7 -5
- package/components/identity.basic/source/types.ts +2 -0
- package/components/identity.federation/manifest.toa.yaml +28 -11
- package/components/identity.federation/operations/authenticate.d.ts +2 -2
- package/components/identity.federation/operations/authenticate.js +6 -5
- package/components/identity.federation/operations/authenticate.js.map +1 -1
- package/components/identity.federation/operations/incept.d.ts +11 -0
- package/components/identity.federation/operations/{create.js → incept.js} +6 -7
- package/components/identity.federation/operations/incept.js.map +1 -0
- package/components/identity.federation/operations/lib/jwt.js +3 -3
- package/components/identity.federation/operations/lib/jwt.js.map +1 -1
- package/components/identity.federation/operations/schemas.d.ts +7 -3
- package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/operations/types.d.ts +5 -0
- package/components/identity.federation/source/authenticate.ts +9 -6
- package/components/identity.federation/source/{create.ts → incept.ts} +10 -9
- package/components/identity.federation/source/lib/jwt.test.ts +2 -2
- package/components/identity.federation/source/lib/jwt.ts +3 -3
- package/components/identity.federation/source/schemas.ts +7 -3
- package/components/identity.federation/source/types.ts +6 -0
- package/components/identity.tokens/manifest.toa.yaml +7 -1
- package/components/identity.tokens/operations/authenticate.d.ts +2 -2
- package/components/identity.tokens/operations/authenticate.js +5 -2
- package/components/identity.tokens/operations/authenticate.js.map +1 -1
- package/components/identity.tokens/operations/decrypt.js +1 -0
- package/components/identity.tokens/operations/decrypt.js.map +1 -1
- package/components/identity.tokens/operations/encrypt.js +1 -0
- package/components/identity.tokens/operations/encrypt.js.map +1 -1
- package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/operations/types.d.ts +7 -0
- package/components/identity.tokens/source/authenticate.test.ts +11 -4
- package/components/identity.tokens/source/authenticate.ts +7 -3
- package/components/identity.tokens/source/decrypt.test.ts +5 -3
- package/components/identity.tokens/source/decrypt.ts +9 -8
- package/components/identity.tokens/source/encrypt.test.ts +4 -1
- package/components/identity.tokens/source/encrypt.ts +1 -0
- package/components/identity.tokens/source/types.ts +8 -0
- package/components/octets.storage/manifest.toa.yaml +0 -6
- package/documentation/authorities.md +53 -0
- package/documentation/components.md +3 -3
- package/documentation/identity.md +17 -22
- package/documentation/vary.md +5 -11
- package/features/access.feature +55 -7
- package/features/annotation.feature +1 -0
- package/features/authorities.basic.feature +140 -0
- package/features/authorities.feature +32 -0
- package/features/authorities.federation.feature +99 -0
- package/features/authorities.tokens.feature +118 -0
- package/features/body.feature +2 -0
- package/features/cache.feature +39 -5
- package/features/cors.feature +4 -0
- package/features/directives.feature +3 -0
- package/features/dynamic.feature +4 -0
- package/features/errors.feature +12 -1
- package/features/etag.feature +6 -0
- package/features/identity.bans.feature +12 -3
- package/features/identity.basic.feature +34 -15
- package/features/identity.feature +7 -2
- package/features/identity.federation.feature +14 -4
- package/features/identity.roles.feature +29 -17
- package/features/identity.tokens.feature +18 -6
- package/features/io.feature +9 -0
- package/features/octets.entries.feature +8 -0
- package/features/octets.feature +17 -54
- package/features/octets.meta.feature +3 -0
- package/features/octets.workflows.feature +13 -0
- package/features/queries.feature +8 -0
- package/features/require.feature +3 -0
- package/features/response.feature +5 -2
- package/features/routes.feature +7 -0
- package/features/steps/Gateway.ts +23 -6
- package/features/streams.feature +1 -0
- package/features/timing.feature +3 -0
- package/features/vary.feature +49 -0
- package/package.json +7 -7
- package/readme.md +19 -14
- package/schemas/annotation.cos.yaml +1 -1
- package/source/Annotation.ts +3 -3
- package/source/Endpoint.ts +1 -1
- package/source/Factory.ts +8 -10
- package/source/Gateway.ts +2 -6
- package/source/HTTP/Context.ts +3 -1
- package/source/HTTP/Server.ts +23 -26
- package/source/HTTP/exceptions.ts +6 -0
- package/source/Query.ts +9 -5
- package/source/deployment.ts +25 -21
- package/source/directives/auth/Authorization.ts +18 -8
- package/source/directives/auth/Incept.ts +2 -1
- package/source/directives/octets/Octets.ts +0 -2
- package/source/directives/vary/embeddings/Authority.ts +8 -0
- package/source/directives/vary/embeddings/index.ts +3 -1
- package/source/schemas.ts +1 -1
- package/transpiled/Annotation.d.ts +3 -3
- package/transpiled/Endpoint.js +1 -1
- package/transpiled/Endpoint.js.map +1 -1
- package/transpiled/Factory.js +9 -8
- package/transpiled/Factory.js.map +1 -1
- package/transpiled/Gateway.js.map +1 -1
- package/transpiled/HTTP/Context.d.ts +2 -1
- package/transpiled/HTTP/Context.js +3 -1
- package/transpiled/HTTP/Context.js.map +1 -1
- package/transpiled/HTTP/Server.d.ts +8 -1
- package/transpiled/HTTP/Server.js +14 -20
- package/transpiled/HTTP/Server.js.map +1 -1
- package/transpiled/HTTP/exceptions.d.ts +3 -0
- package/transpiled/HTTP/exceptions.js +7 -1
- package/transpiled/HTTP/exceptions.js.map +1 -1
- package/transpiled/Query.js +2 -2
- package/transpiled/Query.js.map +1 -1
- package/transpiled/deployment.d.ts +1 -1
- package/transpiled/deployment.js +21 -19
- package/transpiled/deployment.js.map +1 -1
- package/transpiled/directives/auth/Authorization.js +9 -4
- package/transpiled/directives/auth/Authorization.js.map +1 -1
- package/transpiled/directives/auth/Incept.js +2 -1
- package/transpiled/directives/auth/Incept.js.map +1 -1
- package/transpiled/directives/octets/Octets.js +0 -2
- package/transpiled/directives/octets/Octets.js.map +1 -1
- package/transpiled/directives/vary/embeddings/Authority.d.ts +5 -0
- package/transpiled/directives/vary/embeddings/Authority.js +10 -0
- package/transpiled/directives/vary/embeddings/Authority.js.map +1 -0
- package/transpiled/directives/vary/embeddings/index.js +3 -1
- package/transpiled/directives/vary/embeddings/index.js.map +1 -1
- package/transpiled/schemas.d.ts +1 -1
- package/transpiled/schemas.js +2 -2
- package/transpiled/schemas.js.map +1 -1
- package/transpiled/tsconfig.tsbuildinfo +1 -1
- package/components/identity.basic/operations/create.d.ts +0 -10
- package/components/identity.basic/operations/create.js +0 -10
- package/components/identity.basic/operations/create.js.map +0 -1
- package/components/identity.basic/source/create.ts +0 -18
- package/components/identity.federation/operations/create.d.ts +0 -10
- package/components/identity.federation/operations/create.js.map +0 -1
- package/components/octets.storage/operations/permute.js +0 -7
- package/source/HTTP/Server.test.ts +0 -126
- package/source/directives/octets/Permute.ts +0 -44
- package/transpiled/directives/octets/Permute.d.ts +0 -11
- package/transpiled/directives/octets/Permute.js +0 -58
- package/transpiled/directives/octets/Permute.js.map +0 -1
|
@@ -8,6 +8,7 @@ let output: DecryptOutput
|
|
|
8
8
|
let authenticate: Authenticate
|
|
9
9
|
|
|
10
10
|
const identity: Identity = { id: generate() }
|
|
11
|
+
const authority = generate()
|
|
11
12
|
|
|
12
13
|
beforeEach(() => {
|
|
13
14
|
configuration = {
|
|
@@ -36,9 +37,12 @@ it.each([
|
|
|
36
37
|
const iat = new Date(now - configuration.refresh * 1000 + shift).toISOString()
|
|
37
38
|
const exp = new Date(now + 1000).toISOString()
|
|
38
39
|
|
|
39
|
-
output = { identity, exp, iat, refresh: false }
|
|
40
|
+
output = { authority, identity, exp, iat, refresh: false }
|
|
40
41
|
|
|
41
|
-
const result = await authenticate.execute(
|
|
42
|
+
const result = await authenticate.execute({
|
|
43
|
+
authority,
|
|
44
|
+
credentials: ''
|
|
45
|
+
})
|
|
42
46
|
|
|
43
47
|
expect(result).toEqual({ identity, refresh: expected })
|
|
44
48
|
})
|
|
@@ -48,9 +52,12 @@ it.each([true, false])('should return stale: %s',
|
|
|
48
52
|
const iat = new Date().toISOString()
|
|
49
53
|
const exp = new Date(Date.now() + 1000).toISOString()
|
|
50
54
|
|
|
51
|
-
output = { identity, exp, iat, refresh }
|
|
55
|
+
output = { authority, identity, exp, iat, refresh }
|
|
52
56
|
|
|
53
|
-
const result = await authenticate.execute(
|
|
57
|
+
const result = await authenticate.execute({
|
|
58
|
+
authority,
|
|
59
|
+
credentials: ''
|
|
60
|
+
})
|
|
54
61
|
|
|
55
62
|
expect(result).toEqual({ identity, refresh })
|
|
56
63
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Maybe, type Operation } from '@toa.io/types'
|
|
2
|
-
import {
|
|
2
|
+
import type { AuthenticateInput, AuthenticateOutput, Context } from './types'
|
|
3
3
|
|
|
4
4
|
export class Computation implements Operation {
|
|
5
5
|
private refresh: number = 0
|
|
@@ -12,12 +12,15 @@ export class Computation implements Operation {
|
|
|
12
12
|
this.observe = context.local.observe
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
public async execute (
|
|
16
|
-
const claim = await this.decrypt({ input:
|
|
15
|
+
public async execute (input: AuthenticateInput): Promise<Maybe<AuthenticateOutput>> {
|
|
16
|
+
const claim = await this.decrypt({ input: input.credentials })
|
|
17
17
|
|
|
18
18
|
if (claim instanceof Error)
|
|
19
19
|
return claim
|
|
20
20
|
|
|
21
|
+
if (claim.authority !== input.authority)
|
|
22
|
+
return ERR_AUTHORITY
|
|
23
|
+
|
|
21
24
|
const identity = claim.identity
|
|
22
25
|
const iat = new Date(claim.iat).getTime()
|
|
23
26
|
const transient = claim.exp !== undefined
|
|
@@ -39,4 +42,5 @@ export class Computation implements Operation {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
const ERR_AUTHORITY = new Error('AUTHORITY_MISMATCH')
|
|
42
46
|
const ERR_TOKEN_REVOKED = new Error('TOKEN_REVOKED')
|
|
@@ -7,6 +7,8 @@ let configuration: Configuration
|
|
|
7
7
|
let context: Context
|
|
8
8
|
let encrypt: Encrypt
|
|
9
9
|
|
|
10
|
+
const authority = generate()
|
|
11
|
+
|
|
10
12
|
beforeEach(() => {
|
|
11
13
|
configuration = {
|
|
12
14
|
key0: 'k3.local.m28p8SrbS467t-2IUjQuSOqmjvi24TbXhyjAW_dOrog',
|
|
@@ -25,14 +27,14 @@ it('should decrypt', async () => {
|
|
|
25
27
|
const identity: Identity = { id: generate() }
|
|
26
28
|
const lifetime = 100
|
|
27
29
|
|
|
28
|
-
const reply = await encrypt.execute({ identity, lifetime })
|
|
30
|
+
const reply = await encrypt.execute({ authority, identity, lifetime })
|
|
29
31
|
|
|
30
32
|
if (reply === undefined)
|
|
31
33
|
throw new Error('?')
|
|
32
34
|
|
|
33
35
|
const decrypted = await decrypt(reply, context)
|
|
34
36
|
|
|
35
|
-
expect(decrypted).toMatchObject({ identity, refresh: false })
|
|
37
|
+
expect(decrypted).toMatchObject({ authority, identity, refresh: false })
|
|
36
38
|
})
|
|
37
39
|
|
|
38
40
|
it('should decrypt with key1', async () => {
|
|
@@ -48,7 +50,7 @@ it('should decrypt with key1', async () => {
|
|
|
48
50
|
const identity: Identity = { id: generate() }
|
|
49
51
|
const lifetime = 100
|
|
50
52
|
|
|
51
|
-
const encrypted = await encrypt.execute({ identity, lifetime })
|
|
53
|
+
const encrypted = await encrypt.execute({ authority, identity, lifetime })
|
|
52
54
|
|
|
53
55
|
if (encrypted === undefined)
|
|
54
56
|
throw new Error('?')
|
|
@@ -2,8 +2,7 @@ import { V3 } from 'paseto'
|
|
|
2
2
|
import { type Maybe } from '@toa.io/types'
|
|
3
3
|
import { type Context, type Claim, type DecryptOutput } from './types'
|
|
4
4
|
|
|
5
|
-
export async function computation (token: string, context: Context):
|
|
6
|
-
Promise<Maybe<DecryptOutput>> {
|
|
5
|
+
export async function computation (token: string, context: Context): Promise<Maybe<DecryptOutput>> {
|
|
7
6
|
let refresh = false
|
|
8
7
|
let claim = await decrypt(token, context.configuration.key0)
|
|
9
8
|
|
|
@@ -14,12 +13,14 @@ Promise<Maybe<DecryptOutput>> {
|
|
|
14
13
|
|
|
15
14
|
if (claim === null)
|
|
16
15
|
return ERR_INVALID_TOKEN
|
|
17
|
-
else
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
else
|
|
17
|
+
return {
|
|
18
|
+
authority: claim.aud,
|
|
19
|
+
identity: claim.identity,
|
|
20
|
+
iat: claim.iat,
|
|
21
|
+
exp: claim.exp,
|
|
22
|
+
refresh
|
|
23
|
+
}
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
async function decrypt (token: string, key: string): Promise<Claim | null> {
|
|
@@ -8,6 +8,7 @@ import { type Context, type Identity } from './types'
|
|
|
8
8
|
let encrypt: Encrypt
|
|
9
9
|
|
|
10
10
|
const context: Context = {} as unknown as Context
|
|
11
|
+
const authority = generate()
|
|
11
12
|
|
|
12
13
|
beforeEach(() => {
|
|
13
14
|
context.configuration = {
|
|
@@ -25,6 +26,7 @@ it('should encrypt with given lifetime', async () => {
|
|
|
25
26
|
const lifetime = 0.1
|
|
26
27
|
|
|
27
28
|
const encrypted = await encrypt.execute({
|
|
29
|
+
authority,
|
|
28
30
|
identity,
|
|
29
31
|
lifetime
|
|
30
32
|
})
|
|
@@ -32,7 +34,7 @@ it('should encrypt with given lifetime', async () => {
|
|
|
32
34
|
if (encrypted === undefined)
|
|
33
35
|
throw new Error('?')
|
|
34
36
|
|
|
35
|
-
await expect(decrypt(encrypted, context)).resolves.toMatchObject({ identity })
|
|
37
|
+
await expect(decrypt(encrypted, context)).resolves.toMatchObject({ authority, identity })
|
|
36
38
|
|
|
37
39
|
await timeout(lifetime * 1000)
|
|
38
40
|
|
|
@@ -44,6 +46,7 @@ it('should encrypt without lifetime INSECURE', async () => {
|
|
|
44
46
|
const lifetime = 0
|
|
45
47
|
|
|
46
48
|
const encrypted = await encrypt.execute({
|
|
49
|
+
authority,
|
|
47
50
|
identity,
|
|
48
51
|
lifetime
|
|
49
52
|
})
|
|
@@ -23,17 +23,24 @@ export interface Identity extends Record<string, any> {
|
|
|
23
23
|
id: string
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export interface AuthenticateInput {
|
|
27
|
+
authority: string
|
|
28
|
+
credentials: string
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
export interface AuthenticateOutput {
|
|
27
32
|
identity: Identity
|
|
28
33
|
refresh: boolean
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
export interface EncryptInput {
|
|
37
|
+
authority: string
|
|
32
38
|
identity: Identity
|
|
33
39
|
lifetime?: number
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
export interface DecryptOutput {
|
|
43
|
+
authority: string
|
|
37
44
|
identity: Identity
|
|
38
45
|
iat: string
|
|
39
46
|
exp?: string
|
|
@@ -42,6 +49,7 @@ export interface DecryptOutput {
|
|
|
42
49
|
|
|
43
50
|
export interface Claim {
|
|
44
51
|
identity: Identity
|
|
52
|
+
aud: string
|
|
45
53
|
iat: string
|
|
46
54
|
exp?: string
|
|
47
55
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Authorities
|
|
2
|
+
|
|
3
|
+
Authorities are a mechanism that allows serving multiple domains from a single instance of the
|
|
4
|
+
application.
|
|
5
|
+
|
|
6
|
+
## Definition
|
|
7
|
+
|
|
8
|
+
The `authorities` definition is a map of authority identifiers to the `:authority` pseudo-header
|
|
9
|
+
values.
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
# context.toa.yaml
|
|
13
|
+
|
|
14
|
+
exposition:
|
|
15
|
+
authorities:
|
|
16
|
+
one: the.one.com
|
|
17
|
+
two: the.two.com
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Ingress
|
|
21
|
+
|
|
22
|
+
Each host in the authority definition is used to create a Kubernetes Ingress resource.
|
|
23
|
+
|
|
24
|
+
> If the application is accessed with the `:authority` that does not match the authority definition,
|
|
25
|
+
> the response with `404` status code is returned.
|
|
26
|
+
|
|
27
|
+
## Embedding
|
|
28
|
+
|
|
29
|
+
To pass the requested authority to the operation call, [`vary:embed` directive](vary.md#embeddings)
|
|
30
|
+
can be used.
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
# manifest.toa.yaml
|
|
34
|
+
|
|
35
|
+
exposition:
|
|
36
|
+
/:
|
|
37
|
+
GET:
|
|
38
|
+
vary:embed:
|
|
39
|
+
app: authority
|
|
40
|
+
endpoint: observe
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Identity
|
|
44
|
+
|
|
45
|
+
Credentials stored or issued by the [authentication system](identity.md) are associated with an
|
|
46
|
+
authority.
|
|
47
|
+
Credentials in one authority are not valid in another,
|
|
48
|
+
or may be associated with a different Identity; in other words, Identity exists in the context of an
|
|
49
|
+
authority.
|
|
50
|
+
|
|
51
|
+
> :warning:<br/>
|
|
52
|
+
> Changing the authority identifier will break compatibility with existing stored or issued
|
|
53
|
+
> credentials.
|
|
@@ -20,7 +20,7 @@ and pepper.
|
|
|
20
20
|
configuration:
|
|
21
21
|
identity.basic:
|
|
22
22
|
rounds: 10 # salt rounds
|
|
23
|
-
|
|
23
|
+
pepper: '' # hashing pepper
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
### Credentials constraints
|
|
@@ -111,8 +111,8 @@ secrets.
|
|
|
111
111
|
configuration:
|
|
112
112
|
identity.federation:
|
|
113
113
|
trust:
|
|
114
|
-
-
|
|
115
|
-
|
|
114
|
+
- iss: https://token.actions.githubusercontent.com
|
|
115
|
+
aud:
|
|
116
116
|
- https://github.com/tinovyatkin
|
|
117
117
|
- https://github.com/temich
|
|
118
118
|
|
|
@@ -1,36 +1,30 @@
|
|
|
1
1
|
# Identity
|
|
2
2
|
|
|
3
3
|
Identity is the fundamental entity within an authentication system that represents the **unique
|
|
4
|
-
identifier** of an
|
|
5
|
-
individual, organization, application or device.
|
|
4
|
+
identifier** of an individual, organization, application or device.
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Identity.
|
|
6
|
+
To prove its Identity, the request originator must provide a valid _credentials_ that are associated
|
|
7
|
+
with that Identity.
|
|
10
8
|
|
|
11
9
|
Identity is intrinsically linked to credentials, as an Identity is established only when the first
|
|
12
|
-
set of credentials
|
|
13
|
-
for that Identity is created.
|
|
10
|
+
set of credentials for that Identity is created.
|
|
14
11
|
In other words, the creation of credentials marks the inception of an Identity.
|
|
15
12
|
Once the last credentials are removed from the Identity, it ceases to exist.
|
|
16
13
|
Without credentials, there is no basis for defining or asserting an Identity.
|
|
17
14
|
|
|
18
15
|
## Authentication
|
|
19
16
|
|
|
20
|
-
The
|
|
21
|
-
authentication
|
|
22
|
-
schemes.
|
|
17
|
+
The Authentication system resolves provided credentials to an Identity using one of the supported
|
|
18
|
+
authentication schemes.
|
|
23
19
|
|
|
24
20
|
The Authentication is request-agnostic, meaning it does not depend on the specific URL being
|
|
25
|
-
requested or the content of
|
|
26
|
-
the request body.
|
|
21
|
+
requested or the content of the request body.
|
|
27
22
|
The only information it handles is the value of the `Authorization` header.
|
|
28
23
|
|
|
29
|
-
> Except for its own [management resources](
|
|
24
|
+
> Except for its own [management resources](components.md).
|
|
30
25
|
|
|
31
26
|
If the provided credentials are not valid or not associated with an Identity, then Authentication
|
|
32
|
-
interrupts request
|
|
33
|
-
processing and responds with an authentication error.
|
|
27
|
+
interrupts request processing and responds with an authentication error.
|
|
34
28
|
|
|
35
29
|
### Basic scheme
|
|
36
30
|
|
|
@@ -52,8 +46,8 @@ Authrization: Token v4.local.eyJzdWIiOiJqb2hu...
|
|
|
52
46
|
|
|
53
47
|
The `Token` is the **primary** authentication scheme.
|
|
54
48
|
If request originators use an alternative authentication scheme, they will receive a response
|
|
55
|
-
containing `Token`
|
|
56
|
-
|
|
49
|
+
containing `Token`credentials and will be required to switch to the `Token` scheme for any
|
|
50
|
+
subsequent requests.
|
|
57
51
|
Continued use of other authentication schemes will result in temporary blocking of requests.
|
|
58
52
|
|
|
59
53
|
See [`identity.tokens` component](components.md#stateless-tokens).
|
|
@@ -69,7 +63,8 @@ to [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.ht
|
|
|
69
63
|
Authorization: Bearer eyJhbGciOiJIUzI1...
|
|
70
64
|
```
|
|
71
65
|
|
|
72
|
-
Trusted providers are specified using the `identity.federation` property within the configuration
|
|
66
|
+
Trusted providers are specified using the `identity.federation` property within the configuration
|
|
67
|
+
annotation.
|
|
73
68
|
|
|
74
69
|
```yaml
|
|
75
70
|
# context.toa.yaml
|
|
@@ -77,13 +72,13 @@ Trusted providers are specified using the `identity.federation` property within
|
|
|
77
72
|
configuration:
|
|
78
73
|
identity.federation:
|
|
79
74
|
trust:
|
|
80
|
-
-
|
|
81
|
-
|
|
75
|
+
- iss: https://accounts.google.com
|
|
76
|
+
aud:
|
|
82
77
|
- <GOOGLE_CLIENT_ID>
|
|
83
78
|
|
|
84
|
-
-
|
|
79
|
+
- iss: https://appleid.apple.com
|
|
85
80
|
|
|
86
|
-
-
|
|
81
|
+
- iss: private.entity
|
|
87
82
|
secrets:
|
|
88
83
|
HS384:
|
|
89
84
|
key0: <THE-SECRET-STRING-FOR-HS384>
|
package/documentation/vary.md
CHANGED
|
@@ -7,17 +7,15 @@ operation call.
|
|
|
7
7
|
|
|
8
8
|
```yaml
|
|
9
9
|
exposition:
|
|
10
|
-
realms:
|
|
11
|
-
toa: the.toa.io
|
|
12
10
|
/:group:
|
|
13
11
|
vary:languages: [en, fr]
|
|
14
12
|
GET:
|
|
15
13
|
vary:embed:
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
app: authority # predefined embeddings
|
|
15
|
+
lang: language
|
|
18
16
|
token: :x-access-token # raw header value
|
|
19
17
|
group: /:group # route parameter
|
|
20
|
-
endpoint:
|
|
18
|
+
endpoint: observe
|
|
21
19
|
```
|
|
22
20
|
|
|
23
21
|
## Embeddings
|
|
@@ -31,13 +29,9 @@ If the value is an array, the first non-empty embedding function's result is use
|
|
|
31
29
|
> If a property is already present in the input, the embedded value will overwrite its current
|
|
32
30
|
> value.
|
|
33
31
|
|
|
34
|
-
###
|
|
32
|
+
### Authority
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
The list of domains is defined by the `vary:realms` directive,
|
|
38
|
-
which is a map of realm names to their domain names.
|
|
39
|
-
|
|
40
|
-
The `realm` embedding substitutes the realm identified based on the `host` request header.
|
|
34
|
+
The `authority` embedding substitutes request [authority identifier](authorities.md).
|
|
41
35
|
|
|
42
36
|
### Language
|
|
43
37
|
|
package/features/access.feature
CHANGED
|
@@ -5,9 +5,9 @@ Feature: Access authorization
|
|
|
5
5
|
Given the `identity.basic` database contains:
|
|
6
6
|
# developer:secret
|
|
7
7
|
# user:12345
|
|
8
|
-
| _id | username | password |
|
|
9
|
-
| efe3a65ebbee47ed95a73edd911ea328 | developer | $2b$10$ZRSKkgZoGnrcTNA5w5eCcu3pxDzdTduhteVYXcp56AaNcilNkwJ.O |
|
|
10
|
-
| e8e4f9c2a68d419b861403d71fabc915 | user | $2b$10$Frszmrmsz9iwSXzBbRRMKeDVKsNxozkrLNSsN.SnVC.KPxLtQr/bK |
|
|
8
|
+
| _id | authority | username | password |
|
|
9
|
+
| efe3a65ebbee47ed95a73edd911ea328 | nex | developer | $2b$10$ZRSKkgZoGnrcTNA5w5eCcu3pxDzdTduhteVYXcp56AaNcilNkwJ.O |
|
|
10
|
+
| e8e4f9c2a68d419b861403d71fabc915 | nex | user | $2b$10$Frszmrmsz9iwSXzBbRRMKeDVKsNxozkrLNSsN.SnVC.KPxLtQr/bK |
|
|
11
11
|
And the `identity.bans` database is empty
|
|
12
12
|
|
|
13
13
|
Scenario: Deny by default
|
|
@@ -21,6 +21,7 @@ Feature: Access authorization
|
|
|
21
21
|
When the following request is received:
|
|
22
22
|
"""
|
|
23
23
|
GET / HTTP/1.1
|
|
24
|
+
host: nex.toa.io
|
|
24
25
|
"""
|
|
25
26
|
Then the following reply is sent:
|
|
26
27
|
"""
|
|
@@ -40,6 +41,7 @@ Feature: Access authorization
|
|
|
40
41
|
When the following request is received:
|
|
41
42
|
"""
|
|
42
43
|
GET / HTTP/1.1
|
|
44
|
+
host: nex.toa.io
|
|
43
45
|
accept: application/yaml
|
|
44
46
|
"""
|
|
45
47
|
Then the following reply is sent:
|
|
@@ -62,6 +64,7 @@ Feature: Access authorization
|
|
|
62
64
|
When the following request is received:
|
|
63
65
|
"""
|
|
64
66
|
GET / HTTP/1.1
|
|
67
|
+
host: nex.toa.io
|
|
65
68
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
66
69
|
"""
|
|
67
70
|
Then the following reply is sent:
|
|
@@ -83,6 +86,7 @@ Feature: Access authorization
|
|
|
83
86
|
When the following request is received:
|
|
84
87
|
"""
|
|
85
88
|
GET /efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
89
|
+
host: nex.toa.io
|
|
86
90
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
87
91
|
accept: application/yaml
|
|
88
92
|
"""
|
|
@@ -96,6 +100,7 @@ Feature: Access authorization
|
|
|
96
100
|
When the following request is received:
|
|
97
101
|
"""
|
|
98
102
|
GET /efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
103
|
+
host: nex.toa.io
|
|
99
104
|
authorization: Basic dXNlcjoxMjM0NQ==
|
|
100
105
|
accept: application/yaml
|
|
101
106
|
"""
|
|
@@ -122,6 +127,7 @@ Feature: Access authorization
|
|
|
122
127
|
# identity with `developer` and `user` roles
|
|
123
128
|
"""
|
|
124
129
|
GET / HTTP/1.1
|
|
130
|
+
host: nex.toa.io
|
|
125
131
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
126
132
|
accept: application/yaml
|
|
127
133
|
"""
|
|
@@ -136,6 +142,7 @@ Feature: Access authorization
|
|
|
136
142
|
# identity with no roles
|
|
137
143
|
"""
|
|
138
144
|
GET / HTTP/1.1
|
|
145
|
+
host: nex.toa.io
|
|
139
146
|
authorization: Basic dXNlcjoxMjM0NQ==
|
|
140
147
|
"""
|
|
141
148
|
Then the following reply is sent:
|
|
@@ -164,6 +171,7 @@ Feature: Access authorization
|
|
|
164
171
|
When the following request is received:
|
|
165
172
|
"""
|
|
166
173
|
GET /nested/ HTTP/1.1
|
|
174
|
+
host: nex.toa.io
|
|
167
175
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
168
176
|
accept: text/plain
|
|
169
177
|
"""
|
|
@@ -177,6 +185,7 @@ Feature: Access authorization
|
|
|
177
185
|
When the following request is received:
|
|
178
186
|
"""
|
|
179
187
|
GET /javascript/ HTTP/1.1
|
|
188
|
+
host: nex.toa.io
|
|
180
189
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
181
190
|
"""
|
|
182
191
|
Then the following reply is sent:
|
|
@@ -203,6 +212,7 @@ Feature: Access authorization
|
|
|
203
212
|
# identity with `developer` and `user` roles
|
|
204
213
|
"""
|
|
205
214
|
GET / HTTP/1.1
|
|
215
|
+
host: nex.toa.io
|
|
206
216
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
207
217
|
accept: application/yaml
|
|
208
218
|
"""
|
|
@@ -240,6 +250,7 @@ Feature: Access authorization
|
|
|
240
250
|
When the following request is received:
|
|
241
251
|
"""
|
|
242
252
|
GET /rust/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
253
|
+
host: nex.toa.io
|
|
243
254
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
244
255
|
accept: application/yaml
|
|
245
256
|
"""
|
|
@@ -253,6 +264,7 @@ Feature: Access authorization
|
|
|
253
264
|
When the following request is received:
|
|
254
265
|
"""
|
|
255
266
|
GET /javascript/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
267
|
+
host: nex.toa.io
|
|
256
268
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
257
269
|
"""
|
|
258
270
|
Then the following reply is sent:
|
|
@@ -273,8 +285,37 @@ Feature: Access authorization
|
|
|
273
285
|
"""
|
|
274
286
|
When the following request is received:
|
|
275
287
|
"""
|
|
276
|
-
GET /
|
|
277
|
-
|
|
288
|
+
GET /identity/ HTTP/1.1
|
|
289
|
+
host: nex.toa.io
|
|
290
|
+
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
291
|
+
accept: application/yaml
|
|
292
|
+
"""
|
|
293
|
+
Then the following reply is sent:
|
|
294
|
+
"""
|
|
295
|
+
200 OK
|
|
296
|
+
authorization: Token ${{ developer.token }}
|
|
297
|
+
|
|
298
|
+
id: ${{ developer.id }}
|
|
299
|
+
"""
|
|
300
|
+
When the following request is received:
|
|
301
|
+
"""
|
|
302
|
+
GET /identity/ HTTP/1.1
|
|
303
|
+
host: nex.toa.io
|
|
304
|
+
authorization: Basic dXNlcjoxMjM0NQ==
|
|
305
|
+
accept: application/yaml
|
|
306
|
+
"""
|
|
307
|
+
Then the following reply is sent:
|
|
308
|
+
"""
|
|
309
|
+
200 OK
|
|
310
|
+
authorization: Token ${{ user.token }}
|
|
311
|
+
|
|
312
|
+
id: ${{ user.id }}
|
|
313
|
+
"""
|
|
314
|
+
When the following request is received:
|
|
315
|
+
"""
|
|
316
|
+
GET /${{ developer.id }}/ HTTP/1.1
|
|
317
|
+
host: nex.toa.io
|
|
318
|
+
authorization: Token ${{ developer.token }}
|
|
278
319
|
accept: application/yaml
|
|
279
320
|
"""
|
|
280
321
|
Then the following reply is sent:
|
|
@@ -290,8 +331,9 @@ Feature: Access authorization
|
|
|
290
331
|
"""
|
|
291
332
|
When the following request is received:
|
|
292
333
|
"""
|
|
293
|
-
GET /
|
|
294
|
-
|
|
334
|
+
GET /${{ user.id }}/ HTTP/1.1
|
|
335
|
+
host: nex.toa.io
|
|
336
|
+
authorization: Token ${{ developer.token }}
|
|
295
337
|
accept: application/yaml
|
|
296
338
|
"""
|
|
297
339
|
Then the following reply is sent:
|
|
@@ -315,6 +357,7 @@ Feature: Access authorization
|
|
|
315
357
|
When the following request is received:
|
|
316
358
|
"""
|
|
317
359
|
GET / HTTP/1.1
|
|
360
|
+
host: nex.toa.io
|
|
318
361
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
319
362
|
accept: application/yaml
|
|
320
363
|
"""
|
|
@@ -329,6 +372,7 @@ Feature: Access authorization
|
|
|
329
372
|
When the following request is received:
|
|
330
373
|
"""
|
|
331
374
|
GET / HTTP/1.1
|
|
375
|
+
host: nex.toa.io
|
|
332
376
|
authorization: Token ${{ token }}
|
|
333
377
|
accept: application/yaml
|
|
334
378
|
"""
|
|
@@ -355,6 +399,7 @@ Feature: Access authorization
|
|
|
355
399
|
When the following request is received:
|
|
356
400
|
"""
|
|
357
401
|
GET /efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
402
|
+
host: nex.toa.io
|
|
358
403
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
359
404
|
accept: application/yaml
|
|
360
405
|
"""
|
|
@@ -368,6 +413,7 @@ Feature: Access authorization
|
|
|
368
413
|
When the following request is received:
|
|
369
414
|
"""
|
|
370
415
|
GET /efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
416
|
+
host: nex.toa.io
|
|
371
417
|
authorization: Token v3.local.9oEtVJkfRw4cOJ8M4DxuVuAN29dGT26XMYyPAoXtwrkdkiJVSVj46sMNAOdlxwKGszJZV_ReOL26dxDVlsQ7QAIuRhRPlvsHYNOhcD-LApoAXV0S3IK16EMoEv7tE9z70FCLC3WoIW9RIQ8PR3uZhAdhSgBilsVOpWrk4XtnfCIlVwhYMKu79a66oZZhV2Q7Kl3nfYsf84-6rAL_1H0MsqCDUHVXuIg
|
|
372
418
|
accept: text/plain
|
|
373
419
|
"""
|
|
@@ -390,6 +436,7 @@ Feature: Access authorization
|
|
|
390
436
|
When the following request is received:
|
|
391
437
|
"""
|
|
392
438
|
POST /identity/roles/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
439
|
+
host: nex.toa.io
|
|
393
440
|
content-type: application/yaml
|
|
394
441
|
|
|
395
442
|
role: developer
|
|
@@ -414,6 +461,7 @@ Feature: Access authorization
|
|
|
414
461
|
When the following request is received:
|
|
415
462
|
"""
|
|
416
463
|
GET /echo/ HTTP/1.1
|
|
464
|
+
host: nex.toa.io
|
|
417
465
|
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
418
466
|
accept: application/yaml
|
|
419
467
|
"""
|