File: token-based-authentication.md

package info (click to toggle)
gvmd 26.19.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 9,384 kB
  • sloc: ansic: 141,918; sh: 4,171; xml: 1,860; python: 301; makefile: 24
file content (238 lines) | stat: -rw-r--r-- 6,749 bytes parent folder | download
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