blob: 189f7794e21ef24ba49a9db9e115b613e196d95e (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
# Design
## Current
### Architecture
```plaintext
-------------
| user-agent |
-------------
|
V
----|:443|------------------------------
|
V------------|
| |
|------| |
V V V
| ---------------------------
|--->| IdP | CI | ... | Policy |
V |-------------------------|
|--->| UI | REST API | ... |
| ---------------------------
V A
| |
|---->---->---
```
## Proposed
### Architecture
```plaintext
-------------
| user-agent |
-------------
|
V
----|:8080|-----------------------------------------------
|
V
---------------
| API Gateway |
---------------
|
| -----------------------------
|--->| IdP (saml, oidc) |
| -----------------------------
| | :http | :grpc (Policy| |
| -----------------------------
| A A
----------- | |
| | | |
V V | |
------ ------------ |
| UI | | REST API |----|
------ ------------
[UI]: ui.example.com
[REST API]: api.example.com
[IdP]: idp.example.com
```
SAML Login Flow
```plantuml
@startuml
Browser -> UI: Get dashboard
UI --> Browser: Generate SAML <AuthnRequest /> and redirect to IdP
Browser -> IdP: Deliver SAML <AuthnRequest />
IdP --> Browser: Redirect to Login Page
Browser -> IdP: Login
IdP --> Browser: Generate SAML <AuthnResponse /> with <Assertion /> and redirect to UI
Browser -> UI: Deliver SAML <AuthnResponse />
UI -> IdP: Exchange <Assertion /> for Tokens
IdP --> UI: Return `access_token` and `refresh_token`
UI --> Browser: Redirect to dashboard
Browser -> UI: Get dashboard
UI -> API: Request list of projects and provide Access Token
API -> IdP: Check if token is valid and check declarative policy
IdP --> API: Return result of `Ability.allowed?`
API --> UI: Return list of projects as JSON
UI --> Browser: Return list of projects as HTML
@enduml
```
1. `GET http://ui.example.com/saml/new`
1. `POST http://idp.example.com/saml/new`
1. `GET http://idp.example.com/sessions/new?redirect_back=/saml/continue`
1. `POST http://idp.example.com/sessions`
1. `GET http://idp.example.com/saml/continue`
1. `POST http://ui.example.com/saml/assertions`
1. `POST http://idp.example.com/oauth/token`
1. `GET http://api.example.com/groups.json`
1. `GET grpc://idp.example.com/twirp/authx.rpc.Ability/Allowed`
OIDC Login Flow
```plantuml
@startuml
Browser -> UI: Get dashboard
UI --> Browser: Generate OAuth Grant Request and redirect to IdP
Browser -> IdP: Deliver OAuth Grant Request
IdP --> Browser: Redirect to Login Page
Browser -> IdP: Login
IdP --> Browser: Generate Consent Screen for Authorization Code flow
Browser -> IdP: Consent
IdP --> Browser: Generate Authorization Code and redirect to UI
Browser -> UI: Deliver Authorization Code Grant
UI -> IdP: Exchange Authorization Code Grant for Tokens
IdP --> UI: Return `access_token` and `refresh_token`
UI --> Browser: Redirect to dashboard
Browser -> UI: Get dashboard
UI -> API: Request list of projects and provide Access Token
API -> IdP: Check if token is valid and check declarative policy
IdP --> API: Return result of `Ability.allowed?`
API --> UI: Return list of projects as JSON
UI --> Browser: Return list of projects as HTML
@enduml
```
1. `GET http://ui.example.com/oidc/new`
1. `GET http://idp.example.com/oauth/authorize`
1. `GET http://idp.example.com/sessions/new?redirect_back=/oauth/authorize/continue`
1. `POST http://idp.example.com/sessions`
1. `GET http://idp.example.com/oauth/authorize/continue`
1. `POST http://idp.example.com/oauth/authorize`
1. `GET http://ui.example.com/oauth/callback`
1. `POST http://idp.example.com/oauth/token`
1. `GET http://api.example.com/groups.json`
1. `GET grpc://idp.example.com/twirp/authx.rpc.Ability/Allowed`
### Permissions
#### Option 1
| permission | scope | description |
| ---------- | ----- | ----------- |
| `read` | `gid://app/Organization/1` | Can read Org 1 resource |
| `read` | `gid://app/Organization/1/*` | Can read every resource below Org 1 hierarchy |
| `read` | `gid://app/Organization/1/Group/1` | Can read Group 1 resource |
| `read` | `gid://app/Organization/1/Group/1/*` | Can read every resource below Group 1 hierarchy |
| `read` | `gid://app/Organization/1/Group/1/Project/1` | Can read project 1 |
| `read` | `gid://app/Project/1` | Can read project 1 resource (short circuit example) |
| `read` | `gid://app/Organization/1/Group/1?attributes[]=name&attributes[]=description` | Can read name and description of Group 1 resource |
Example:
The following example allows the subject of the token to read all of the descendant resources of `Project 1` and `Project 2` and it can read `Project 3`.
```json
{
"sub": "gid://User/17",
"scope": {
"read": [
"gid://app/Organization/1/Group/1/Project/1/*",
"gid://app/Organization/1/Group/1/Project/2/*",
"gid://app/Organization/1/Group/2/Project/3"
]
}
}
```
#### Option 2
Encode access and scope directly into the name of the permission.
| permission | description |
| ---------- | ----------- |
| `read:organization:1` | Can read Org 1 resource |
| `read:organization:1:*` | Can read every resource below Org 1 hierarchy |
| `read:organization:1:group:*` | Can read Group 1 resource |
| `read:organization:1:group:1:*` | Can read every resource below Group 1 hierarchy |
| `read:organization:1:group:1:project:1` | Can read project 1 |
| `read:project:1` | Can read project 1 resource (short circuit example) |
| `read:organization:1:group:1:attributes[]=name&attributes[]=description` | Can read name and description of Group 1 resource |
Example:
```json
{
"sub": "gid://User/17",
"scope": [
"read:organization:1:group:1:project:1:*",
"read:organization:1:group:1:project:2:*",
"read:organization:1:group:2:project:3"
]
}
```
|