From 4f2e1dea29b84af6b6c4c69e249a2a656151ad2b Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 22 Dec 2018 06:03:06 +0200 Subject: Add: start of arch doc --- arch/000.yarn | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ arch/Makefile | 7 +++ arch/arch.css | 15 +++++ arch/arch.diag | 12 ++++ arch/build.sh | 14 +++++ run.sh | 16 ++++++ 6 files changed, 235 insertions(+) create mode 100644 arch/000.yarn create mode 100644 arch/Makefile create mode 100644 arch/arch.css create mode 100644 arch/arch.diag create mode 100755 arch/build.sh create mode 100755 run.sh diff --git a/arch/000.yarn b/arch/000.yarn new file mode 100644 index 0000000..5db67f3 --- /dev/null +++ b/arch/000.yarn @@ -0,0 +1,171 @@ +--- +title: Effireg architecture +author: Lars Wirzenius +... + +# Introduction + +Effireg is a web-based membership register for the EFfi non-profit +association. See 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. + +# 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 + +![Architectural components](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. + +# effiapi + +[yarn]: https://liw.fi/cmdtest/ + +This chapter descibes the effiapi API, as a [yarn][] automated +scenario test. It is meant to be understandable to Effi sysadmins, as +well as be an executable test suite for the API. + +The API is a simple RESTful HTTP API using JSON. This means that: + +* each API call is an HTTP request, with a response + +* all data is represented as JSON in the body of the request of + response + +* metadata about the data is represeneted as HTTP headers + +* standard HTTP verbs (POST, PUT, GET, DELETE) are used to indicate + the action + +* standard HTTP status codes are used to indicate result of the + request (200 = OK, 404 = not found, etc) + +## Manage memberships + +This section shows the API calls to manage a memberhip: to create the +member, to update and retrieve it, and to search memberships. + +~~~ +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" } +~~~ + +TODO: + +* update +* delete +* search +* members can see their own data, and can't see each others' +* member follows authn link emailed to them + +# Appendix: Yarn scenario step implementations + diff --git a/arch/Makefile b/arch/Makefile new file mode 100644 index 0000000..14078f5 --- /dev/null +++ b/arch/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/arch.css b/arch/arch.css new file mode 100644 index 0000000..25720b2 --- /dev/null +++ b/arch/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/arch.diag b/arch/arch.diag new file mode 100644 index 0000000..d1e0f1e --- /dev/null +++ b/arch/arch.diag @@ -0,0 +1,12 @@ +blockdiag { + browser; + qvisqve; + effiweb; + effiapi; + muck; + + browser -> effiweb; + browser -> qvisqve; + effiweb -> effiapi; + effiapi -> muck; +} diff --git a/arch/build.sh b/arch/build.sh new file mode 100755 index 0000000..794b299 --- /dev/null +++ b/arch/build.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -eu + +version="$(git describe --dirty)" +blockdiag3 arch.diag +pandoc \ + -Vdate="$version" \ + --toc \ + --standalone \ + --self-contained \ + --css arch.css \ + -o arch.html \ + *.yarn diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..592cf7f --- /dev/null +++ b/run.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -eu + +tokenurl=https://effi-reg.vm.liw.fi +apiurl=https://effi-reg.vm.liw.fi + +#tokenurl="https://muck-muck.vm.liw.fi" +#apiurl="http://localhost:8080" + +./effitool \ + --log effitool.log \ + -i admin -s hunter2 \ + -u "$apiurl" \ + -t "$tokenurl" \ + "$@" -- cgit v1.2.1