summaryrefslogtreecommitdiff
path: root/doc/arch.mdwn
blob: 62e46c95af61ed49cfb1f3161c0312bea7e19a9d (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
---
title: "Architecture of Qvisqve, an authorization server"
author: QvarnLabs Ab
date: work-in-progress
...

# Introduction

**What.** Qvisqve is an authorization server. At this stage, it is an
[OAuth2][] authorization server, but later on it will grow into a
provider for [OpenID Connect][]. Qvisqve controls access to a web API:
the API client authenticates itself to Qvisqve, gets an access token
from Qvisqve, and gives the access token to the API server. This
de-couples the acts of authentication and authorization and resource
access, which simplifies the individual software components.

[OAuth2]: https://en.wikipedia.org/wiki/OAuth
[OpenID Connect]: https://en.wikipedia.org/wiki/OpenID_Connect

**Why.** Qvisqve is not the first server of its kind. We wrote Qvisqve
because we wanted something we liked:

* is fully free, open source software
* has a simple, clear architecture and implementation
* has a chance of being accepted into the Debian distribution
* is simple and fast to install, and configure
* is simple, transparent to operate
* scales to many requests per second, many identities
* is flexible and easily extensible, as far as authentication methods
  go
* is robust and reliable
* is stable

**Web, not enterprise.** We operate in a "web environment, which is
different from a typical enterprise or large organisation environment.
We do not care about "single sign-on" across unrelated services, for
example.

**Why not an alternative.** We've used [Gluu][], but for our uses it
is cumbersome, and not simple.

[Gluu]: https://www.gluu.org/

**Usage driven development.** We develop Qvisqve mainly based on the
needs of actual users, not to complete feature comparsion matrices.

## Glossary

* access token
* Qvarn: a program for storing structured data, especially personal
  data, and providing access control. See <http://qvarn.org/>.

# Current state

**Currently, alpha level.** Qvisqve is an OAuth2 authorization server
that supports the client credential grant only. This means only the
API client authenticates itself to Qvisqve, but not the actual
end-user. This is so that we can use Qvisqve with the [Qvarn][] server
and have the Qvarn API tests pass.

[Qvarn]: http://qvarn.org/

Further, the first development phase aims for a simplistic OAuth2
server. For example, the list of API clients will be hardcoded in the
configuration file. This is acceptable to get development started, but
soon after that we will add features such as dynamically registering
clients.

## Vision for the future

In the longer term, we aim for Qvisqve to be an OpenID provider using
the OpenID Connect protocol. This includes being able to have the
end-user authenticate and authorize use of resources. We will make it
simple and flexible to provide authentication methods (such as
username/password, client-side certificates, and U2F tokens).

We will be replacing the static configuration file, with the list of
clients, with Qvarn. Eventually, one goal is to make it possible to
allow every person registered in Qvarn to authenticate with Qvisqve.

Eventually, we aim to have Qvisqve certified as a compliant OpenID
Connect implementation.

We also intend to make Qvisqve be flexible, easy, and secure.

# Known problems and things to solve later

The main problem of Qvisqve at this stage is that it doesn't exist. All
other problems can be derived from that.

We don't have a good way of rotating the token signing keys.

# Requirements

For the first development phase of Qvisqve, our acceptance criteria
are:

* setting up a Qvisqve instance is simple: the software should be
  provided as a Debian package installable on Debian 9 (stretch), and
  a corresponding Ansible playbook that configures the instance

* configuring a Qvarn instance to use the Qvisqve instance is simple:
  the Ansible playbook for Qvarn should be updated to work with Qvisqve
  instead of Gluu

* the Qvarn API tests pass

Once we have that working, we will add more requirements.

## Non-requirements

At this stage, we do not care about speed, portability, or other such
qualities. We care about security enough that we want to avoid any
glaringly obvious security issues, but, for example, we don't care
about storing API client secrets in an encrypted fashion.

# Architecture overview

Qvisqve provides an HTTP API interface for authentication. The only
relevant endpoint is `/token` and to use it, the client must
authenticate itself using its "client id" and "client secret" using
HTTP Basic Authentication. A successful response will have the access
token in its JSON body.

A request:

    POST /token HTTP/1.1
    Host: qvisqve.example.com
    Authorization: Basic c2FsYW1pOnBhc3N3b3Jk
    Content-Type: application/x-www-form-urlencoded

    grant_type=client_credentials?scope=version

A successful response:

    HTTP/1.1 200 OK
    Content-Type: application/json

    {
        "access_token": "CAFEF00D",
        "token_type": "bearer",
        "expires_in": 3600,
    }

The client should extract the access token (`CAFEF00D`) and add it to
any requests it makes to the resource server:

    Authorization: Bearer CAFEF00D

The client does not need to understand the token, it merely copies it
into requests it makes.

## Components

Qvisqve consists of several components

@startuml
title Qvisqve components
component [API client] as client
node "Qvisqve" {
    component [Haproxy] as haproxy
    component [backend] as backend
    component [configuration] as config
}

client -> haproxy : 2. https
haproxy -> backend : 3. http
backend <- config : 1. read at startup
haproxy <- backend : 4. access token
client <- haproxy : 5. access token
@enduml

**haproxy** is a load balancer. For Qvisqve we use it to provide TLS
for communication with the client.

The **backend** implements the actual Qvisqve HTTP endpoints and
creates and returns access tokens to the client.

The **configuration** lists the API clients (the id, the secret, and
any scopes the client is allowed to have), as well as the RSA keys
used to sign the access token. The API provider (Qvarn) will be
configured to know the public RSA key so that it can verify that an
access token has been created by Qvisqve.

The client and haproxy use TLS. haproxy and the backend use plain
HTTP, but they will be deployed in an environment where the plain text
communication cannot be overheard, such as via the `localhost`
interface (haproxy and backend would run on the same host).