diff options
author | Lars Wirzenius <liw@liw.fi> | 2018-12-30 18:40:53 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2018-12-30 18:40:53 +0200 |
commit | dde454d54147d8fba5ea263bdf66d1cc48c44968 (patch) | |
tree | f40f106e4c7ab5b4cf8c5c0ee41ba4a60c395306 | |
download | effireg-website-dde454d54147d8fba5ea263bdf66d1cc48c44968.tar.gz |
Add: initial commit
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | arch.css | 15 | ||||
-rw-r--r-- | arch.diag | 12 | ||||
-rw-r--r-- | arch.html | 145 | ||||
-rw-r--r-- | arch.png | bin | 0 -> 4856 bytes | |||
-rw-r--r-- | architecture.mdwn | 111 | ||||
-rwxr-xr-x | build.sh | 14 | ||||
-rw-r--r-- | ikiwiki.setup | 36 | ||||
-rw-r--r-- | index.mdwn | 12 |
9 files changed, 352 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..14078f5 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +yarns = $(wildcard *.yarn) +images = $(wildcard *.diag) + +all: arch.html + +arch.html: $(yarns) $(images) arch.css + ./build.sh diff --git a/arch.css b/arch.css new file mode 100644 index 0000000..25720b2 --- /dev/null +++ b/arch.css @@ -0,0 +1,15 @@ +html { + font-family: serif; + margin-left: 4em; + margin-right: 4em; +} + +h1, h2, h3 { + font-family: sans-serif; + margin-top: 2em; +} + + +h1 { font-size: 3em; } +h2 { font-size: 2em; } +h3 { font-size: 1em; } diff --git a/arch.diag b/arch.diag new file mode 100644 index 0000000..d1e0f1e --- /dev/null +++ b/arch.diag @@ -0,0 +1,12 @@ +blockdiag { + browser; + qvisqve; + effiweb; + effiapi; + muck; + + browser -> effiweb; + browser -> qvisqve; + effiweb -> effiapi; + effiapi -> muck; +} diff --git a/arch.html b/arch.html new file mode 100644 index 0000000..5e9f8ac --- /dev/null +++ b/arch.html @@ -0,0 +1,145 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang> +<head> + <meta charset="utf-8" /> + <meta name="generator" content="pandoc" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> + <meta name="author" content="Lars Wirzenius" /> + <title>Effireg architecture</title> + <style type="text/css"> + code{white-space: pre-wrap;} + span.smallcaps{font-variant: small-caps;} + span.underline{text-decoration: underline;} + div.column{display: inline-block; vertical-align: top; width: 50%;} + </style> + <style type="text/css">html { +font-family: serif; +margin-left: 4em; +margin-right: 4em; +} +h1, h2, h3 { +font-family: sans-serif; +margin-top: 2em; +} +h1 { font-size: 3em; } +h2 { font-size: 2em; } +h3 { font-size: 1em; } +</style> +</head> +<body> +<header> +<h1 class="title">Effireg architecture</h1> +<p class="author">Lars Wirzenius</p> +<p class="date">Version: trial-1-g4f2e1de-dirty</p> +</header> +<nav id="TOC"> +<ul> +<li><a href="#introduction">Introduction</a></li> +<li><a href="#architecture-overview">Architecture overview</a><ul> +<li><a href="#assumptions">Assumptions</a></li> +<li><a href="#components">Components</a></li> +<li><a href="#authentication">Authentication</a></li> +</ul></li> +<li><a href="#data-model">Data model</a><ul> +<li><a href="#subject-resource">Subject resource</a></li> +<li><a href="#password-resource">Password resource</a></li> +<li><a href="#member-resource-memb">Member resource (memb)</a></li> +</ul></li> +<li><a href="#effiapi">effiapi</a><ul> +<li><a href="#manage-memberships">Manage memberships</a></li> +</ul></li> +<li><a href="#appendix-yarn-scenario-step-implementations">Appendix: Yarn scenario step implementations</a></li> +</ul> +</nav> +<h1 id="introduction">Introduction</h1> +<p>Effireg is a web-based membership register for the Effi non-profit association. See <a href="https://effi.org/" class="uri">https://effi.org/</a> for more information about Effi.</p> +<p>Effireg is written for Effi, but it is free software, released under the Affero GPL v3 license, and may be used by others. No guarantees of quality.</p> +<h1 id="architecture-overview">Architecture overview</h1> +<h2 id="assumptions">Assumptions</h2> +<p>The architecture has been designed under the following assumptions:</p> +<ul> +<li><p>Privacy is important, and should be the default. People should only have access to the information they are authorized to access.</p></li> +<li><p>Members should be able to see their own information, without having to go through the Effi membership register admin.</p></li> +<li><p>It’s not practical to have every member have a password. Authentication can be done by sending the member a unique, single-use link when they want to log in.</p></li> +</ul> +<h2 id="components">Components</h2> +<figure> +<img src="data:image/png;base64,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" alt="Architectural components" /><figcaption>Architectural components</figcaption> +</figure> +<p>Effireg consists of four main components:</p> +<ul> +<li><p><strong>effiapi</strong> provides a RESTful HTTP API for managing the membership data, and for doing things with or to the data. All operations go via the API.</p></li> +<li><p><strong>effiweb</strong> provides the frontend for the web application to use the membership register. It renders HTML to the user, is accesses via a web browser, and generally is the user-visible part of Effireg.</p></li> +<li><p><strong>Qvisqve</strong> provides authentication of end-users (the members, and admins). It lets users log in, and keeps track of what each user is allowed to do.</p></li> +<li><p><strong>Muck-POC</strong> stores the actual membership register data, and controls access to it, based on access tokens from Qvisqve.</p></li> +</ul> +<h2 id="authentication">Authentication</h2> +<p>End-users are authenticated using the <a href="https://openid.net/specs/openid-connect-core-1_0.html">OpenID Connect</a> protocol, specifically the authorization code flow. In this flow, Qvisqve provides cryptographically signed access tokens, which identify the user and specify a list of things the user may do. The signature guarantees the token comes from Qvisqve.</p> +<p>Non-interactive API clients are authenticated using the <a href="https://oauth.net/2/">OAuth2</a> protocol, specifically using client credential grants. This also provides an access token, similar to the one from end-user authentication.</p> +<h1 id="data-model">Data model</h1> +<p>The membership register stores data as “resources” in Muck-POC. Each resource is a JSON object. The following types of objects are supported:</p> +<ul> +<li><strong>subject</strong> represents a person who is allowed to use the register; it it used to identify the user for authentication</li> +<li><strong>password</strong> stores the encrypted password for a subject</li> +<li><strong>memb</strong> represets a subject’s membership in Effi</li> +</ul> +<h3 id="subject-resource">Subject resource</h3> +<p>A subject resource has the following fields:</p> +<ul> +<li><code>username</code> — the username of the subject; this can change, the subject is identified by the resource identifier in the register, not by the username</li> +</ul> +<p>The subject resource does not have any data that isn’t needed for end-user identification. Effiapi manages and Qvisqve uses the subject resource.</p> +<h3 id="password-resource">Password resource</h3> +<p>A password resource has the following fields:</p> +<ul> +<li><code>subject_id</code> — resource id of the subject whose password this is</li> +<li><code>version</code> — version of the password resource (identifies algorithm); must be 1</li> +<li><code>hash</code> — the password, encrypted with the scrypt algorithm</li> +<li><code>salt</code> — a random string to prevent dictionary attacks</li> +<li><code>key_len</code> — parameter for scrypt</li> +<li><code>N</code> — parameter for scrypt</li> +<li><code>r</code> — parameter for scrypt</li> +<li><code>p</code> — parameter for scrypt</li> +</ul> +<p>Effiapi manages and Qvisqve uses the password resource.</p> +<h3 id="member-resource-memb">Member resource (memb)</h3> +<p>A membership resource has the following fields:</p> +<ul> +<li><code>subject-id</code> — the resource id of the subject resource for the member</li> +<li><code>fullname</code> — the full name of the member</li> +<li><code>primary-email</code> — the primary email address for the member (and currently the only one)</li> +<li><code>years-paid</code> — list of integers for the years for which the member has paid their membership</li> +</ul> +<p>Effiapi manages and uses the memb resource. Effiweb renders it for the user.</p> +<h1 id="effiapi">effiapi</h1> +<p>This chapter descibes the effiapi API, as a <a href="https://liw.fi/cmdtest/">yarn</a> automated scenario test. It is meant to be understandable to Effi sysadmins, as well as be an executable test suite for the API.</p> +<p>The API is a simple RESTful HTTP API using JSON. This means that:</p> +<ul> +<li><p>each API call is an HTTP request, with a response</p></li> +<li><p>all data is represented as JSON in the body of the request of response</p></li> +<li><p>metadata about the data is represeneted as HTTP headers</p></li> +<li><p>standard HTTP verbs (POST, PUT, GET, DELETE) are used to indicate the action</p></li> +<li><p>standard HTTP status codes are used to indicate result of the request (200 = OK, 404 = not found, etc)</p></li> +</ul> +<h2 id="manage-memberships">Manage memberships</h2> +<p>This section shows the API calls to manage a memberhip: to create the member, to update and retrieve it, and to search memberships.</p> +<pre><code>SCENARIO Manage memberships + +GIVEN An effiapi instance +WHEN admin requests POST /memb with body { "fullname": "James Bond" } +THEN the member id is ID + +WHEN admin requests GET /memb with header Muck-Id: ${ID} +THEN HTTP status 200 +AND HTTP body matches { "fullname": "James Bond" }</code></pre> +<p>TODO:</p> +<ul> +<li>update</li> +<li>delete</li> +<li>search</li> +<li>members can see their own data, and can’t see each others’</li> +<li>member follows authn link emailed to them</li> +</ul> +<h1 id="appendix-yarn-scenario-step-implementations">Appendix: Yarn scenario step implementations</h1> +</body> +</html> diff --git a/arch.png b/arch.png Binary files differnew file mode 100644 index 0000000..f86d22f --- /dev/null +++ b/arch.png diff --git a/architecture.mdwn b/architecture.mdwn new file mode 100644 index 0000000..fccf309 --- /dev/null +++ b/architecture.mdwn @@ -0,0 +1,111 @@ +[[!meta title="Architecture"]] + +[[!toc ]] + +# Architecture overview + +## Assumptions + +The architecture has been designed under the following assumptions: + +* Privacy is important, and should be the default. People should only + have access to the information they are authorized to access. + +* Members should be able to see their own information, without having + to go through the Effi membership register admin. + +* It's not practical to have every member have a password. + Authentication can be done by sending the member a unique, + single-use link when they want to log in. + +## Components + +[[!img arch.png]] + +Effireg consists of four main components: + +* **effiapi** provides a RESTful HTTP API for managing the membership + data, and for doing things with or to the data. All operations go + via the API. + +* **effiweb** provides the frontend for the web application to use the + membership register. It renders HTML to the user, is accesses via a + web browser, and generally is the user-visible part of Effireg. + +* **Qvisqve** provides authentication of end-users (the members, and + admins). It lets users log in, and keeps track of what each user is + allowed to do. + +* **Muck-POC** stores the actual membership register data, and + controls access to it, based on access tokens from Qvisqve. + +## Authentication + +[OpenID Connect]: https://openid.net/specs/openid-connect-core-1_0.html +[OAuth2]: https://oauth.net/2/ + +End-users are authenticated using the [OpenID Connect][] protocol, +specifically the authorization code flow. In this flow, Qvisqve +provides cryptographically signed access tokens, which identify the +user and specify a list of things the user may do. The signature +guarantees the token comes from Qvisqve. + +Non-interactive API clients are authenticated using the [OAuth2][] +protocol, specifically using client credential grants. This also +provides an access token, similar to the one from end-user +authentication. + +# Data model + +The membership register stores data as "resources" in Muck-POC. Each +resource is a JSON object. The following types of objects are +supported: + +* **subject** represents a person who is allowed to use the register; + it it used to identify the user for authentication +* **password** stores the encrypted password for a subject +* **memb** represets a subject's membership in Effi + +### Subject resource + +A subject resource has the following fields: + +* `username` — the username of the subject; this can change, the + subject is identified by the resource identifier in the register, + not by the username + +The subject resource does not have any data that isn't needed for +end-user identification. Effiapi manages and Qvisqve uses the subject +resource. + +### Password resource + +A password resource has the following fields: + +* `subject_id` — resource id of the subject whose password this + is +* `version` — version of the password resource (identifies + algorithm); must be 1 +* `hash` — the password, encrypted with the scrypt algorithm +* `salt` — a random string to prevent dictionary attacks +* `key_len` — parameter for scrypt +* `N` — parameter for scrypt +* `r` — parameter for scrypt +* `p` — parameter for scrypt + +Effiapi manages and Qvisqve uses the password resource. + +### Member resource (memb) + +A membership resource has the following fields: + +* `subject-id` — the resource id of the subject resource for + the member +* `fullname` — the full name of the member +* `primary-email` — the primary email address for the member + (and currently the only one) +* `years-paid` — list of integers for the years for which the + member has paid their membership + +Effiapi manages and uses the memb resource. Effiweb renders it for the +user. diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..8a04877 --- /dev/null +++ b/build.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -eu + +version="$(git describe --dirty)" +blockdiag3 arch.diag +pandoc \ + -Vdate="Version: $version" \ + --toc \ + --standalone \ + --self-contained \ + --css arch.css \ + -o arch.html \ + *.yarn diff --git a/ikiwiki.setup b/ikiwiki.setup new file mode 100644 index 0000000..43727ba --- /dev/null +++ b/ikiwiki.setup @@ -0,0 +1,36 @@ +# IkiWiki::Setup::Yaml - YAML formatted setup file + +wikiname: Effireg +url: https://icv-biz.liw.fi +srcdir: . +destdir: /home/liw/sites/effireg.liw.fi/html +add_plugins: +- goodstuff +- inline +- attachment +- remove +- rename +- tag +- orphans +- brokenlinks +- trail +- sidebar +- toc +- highlight +- format +- graphviz +disable_plugins: +- smiley +- rawhtml +- html +- tidy +html5: yes +timeformat: '%Y-%m-%d %H:%M' +exclude: 'favicon\.ico' +allowed_attachments: mimetype(image/*) +tagbase: tag +discussion: no +allowrss: yes +allowatom: yes +rss: yes +atom: yes diff --git a/index.mdwn b/index.mdwn new file mode 100644 index 0000000..10925eb --- /dev/null +++ b/index.mdwn @@ -0,0 +1,12 @@ +[[!meta title="Effireg - privacy-aware register of members for associations"]] + +Effireg is a web-based membership register for the Effi non-profit +association. See <https://effi.org/> for more information about Effi. + +Effireg is written for Effi, but it is free software, released under +the Affero GPL v3 license, and may be used by others. No guarantees of +quality. + + +* [[architecture]] + |