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 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
|
# Token Based Authentication <!-- omit in toc -->
In general it is desirable to use token based authentication and
[JSON Web Tokens (JWT)][JWT]
for the format of the tokens. It allows to implement *stateless* authentication
and therefore to split the authentication into another service.
A service getting the JWT from the client has to verify the token
signature only and can afterwards trust its content. The content of the JWT can
contain arbitrary data which in our case should be the user's permissions.
- [JWT Format](#jwt-format)
- [GMP Authentication](#gmp-authentication)
- [GMP Requests with Token](#gmp-requests-with-token)
- [Authentication Workflow](#authentication-workflow)
- [Step 1](#step-1)
- [Step 2](#step-2)
## JWT Format
The JWT should use the user id as subject (`sub`) and add [claims](https://en.wikipedia.org/wiki/JSON_Web_Token#Standard_fields)
for the user name and permissions. Optionally the roles and groups could be
added to if necessary. The permissions, roles and groups can be used in the
services to decide whether a user is allowed to access a route.
Proposed JWT format
```json
{
"sub": "<user id>",
"exp": "<unix timestamp of current datetime + X>",
"iat": "<unix timestamp of current datetime>",
"username": "<username>",
"permissions": [
"<permissions of the user, for example>",
"get_tasks",
"create_task",
"..."
]
"roles": [
{"id": "<role-id-1>", "name": "<role-name-1>"},
{"id": "7a8cb5b4-b74d-11e2-8187-406186ea4fc5", "name": "Admin"},
{"id": "8d453140-b74d-11e2-b0be-406186ea4fc5", "name": "User"}
],
"groups": [
{"id": "<group-id-1>", "name": "<group-name-1>"},
{"id": "45cf04ee-001f-4d60-99c6-02989d7dcd59", "name": "SomeGroup"},
{"id": "6efc8ffd-2195-4d82-8bab-2b4a471035d8", "name": "AnotherGroup"}
]
}
```
The expiry duration X should be between 5 and 15 minutes and should be
adjustable via a setting.
> [!NOTE]
> Adding the roles and permission and extending GMP with [token authentication](#gmp-authentication)
> would allow to remove permission queries from gvmd.
## GMP Authentication
Possible GMP extension of the current authentication workflow using tokens.
Client Request
```xml
<authenticate token="1">
<credentials>
<username>sally</username>
<password>secret</password>
</credentials>
</authenticate>
```
Response
```xml
<authenticate_response status="200"
status_text="OK">
<role>User</role>
<timezone>UTC</timezone>
<token><!-- JSON Web Token --></token>
</authenticate_response>
```
Only return `<token>` with a JWT if the client requested it explicitly via
the `token` attribute. If it is equal "1" a JWT is returned.
## GMP Requests with Token
To support a single authentication mechanism GMP might be extended for token
based authentication.
```mermaid
---
title: GMP Request with Token
---
flowchart LR
client["GMP Client"]
gvmd["gvmd"]
client-->|GMP command + JWT|gvmd
gvmd-->|GMP response|client
```
Adding a new Root Element with token as first sub-element
```xml
<request>
<token><!-- JSON Web Token --></token>
<!-- standard GMP commands for example get_tasks -->
<get_tasks ...>...</get_tasks>
</request>
```
> [!NOTE]
> `<token>` needs to be the first sub-element to be able to work with gvmd's
> state machine at the moment.
## Authentication Workflow
It is intended to support generating [JSON Web Tokens][JWT] in gvmd and also to
use it as an authentication mechanism in gvmd.
We can implement this solution in two steps
1. Provide a JWT from [GMP authentication](#gmp-authentication)
2. Allow to use JWT in [GMP commands](#gmp-requests-with-token)
In an additional later step the generation of the JWT can be moved into an own
service.
>[!NOTE]
> An idea is to implement JWT generation and validation in a Rust library and
> call it from C in gvmd. This will allow for an easy migration to a Rust based
> authentication service in future.
### Step 1
gvmd creates token on [request for a client](#gmp-authentication). It doesn't
support [using token in GMP requests](#gmp-requests-with-token) yet.
```mermaid
---
title: Authentication and getting the List of Tasks (JWT generation support)
---
sequenceDiagram
actor User
participant GSA
participant gsad
participant gvmd
User-->>GSA: Login with username+password
activate GSA
GSA-->>gsad: username+password
activate gsad
gsad-->>gvmd: GMP authenticate with username+password (token="1")
activate gvmd
gvmd-->>gsad: GMP authenticate response with JWT
deactivate gvmd
gsad-->>gsad: Store JWT as Session Token
gsad-->>GSA: JWT
deactivate gsad
GSA-->>User: Login Successful
deactivate GSA
User-->>GSA: List Tasks
activate GSA
GSA-->>gsad: Request with JWT
activate gsad
gsad-->>gsad: Use JWT to get username+password from Session Store
gsad-->>gvmd: GMP authenticate request with username+password (token="0")
activate gvmd
alt username+password is valid
gvmd-->>gsad: GMP authenticate response OK
gsad-->>gvmd: GMP get_tasks request
gvmd-->>gsad: GMP get_tasks response
deactivate gvmd
gsad-->>GSA: Response
deactivate gsad
GSA-->>User: List Tasks
deactivate GSA
else username+password are invalid
gvmd-->>gsad: GMP authenticate response error
gsad-->>GSA: Error
GSA-->>User: Login Page
end
```
### Step 2
gvmd creates token on [request for a client](#gmp-authentication) and supports
[using token in GMP requests](#gmp-requests-with-token) now.
```mermaid
---
title: Authentication and getting the List of Tasks (full JWT support)
---
sequenceDiagram
actor User
participant GSA
participant gsad
participant gvmd
User-->>GSA: Login with username+password
activate GSA
GSA-->>gsad: username+password
activate gsad
gsad-->>gvmd: GMP authenticate with username+password
activate gvmd
gvmd-->>gsad: GMP authenticate response with JWT
deactivate gvmd
gsad-->>GSA: JWT
deactivate gsad
GSA-->>User: Login Successful
deactivate GSA
User-->>GSA: List Tasks
activate GSA
GSA-->>gsad: Request with JWT
activate gsad
gsad-->>gvmd: GMP get_tasks Request with JWT
activate gvmd
alt JWT is valid
gvmd-->>gsad: GMP get_tasks Response OK
gsad-->>GSA: Response
GSA-->>User: List of Tasks
else JWT not valid
gvmd-->>gsad: GMP get_tasks Response Error Unauthenticated
deactivate gvmd
gsad-->>GSA: Error Unauthenticated
deactivate gsad
GSA-->>User: Login Page
deactivate GSA
end
```
[JWT]: https://en.wikipedia.org/wiki/JSON_Web_Token
|