summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2018-12-22 06:03:06 +0200
committerLars Wirzenius <liw@liw.fi>2018-12-22 06:03:06 +0200
commit4f2e1dea29b84af6b6c4c69e249a2a656151ad2b (patch)
tree44717c7c9322738756f3f55d3fff3271516dd3c8
parent9208e13f1fc514d3f3eb30b8c15ec4b3ae9fa4ed (diff)
downloadeffi-reg-4f2e1dea29b84af6b6c4c69e249a2a656151ad2b.tar.gz
Add: start of arch doc
-rw-r--r--arch/000.yarn171
-rw-r--r--arch/Makefile7
-rw-r--r--arch/arch.css15
-rw-r--r--arch/arch.diag12
-rwxr-xr-xarch/build.sh14
-rwxr-xr-xrun.sh16
6 files changed, 235 insertions, 0 deletions
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 <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.
+
+# 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` &mdash; 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` &mdash; resource id of the subject whose password this
+ is
+* `version` &mdash; version of the password resource (identifies
+ algorithm); must be 1
+* `hash` &mdash; the password, encrypted with the scrypt algorithm
+* `salt` &mdash; a random string to prevent dictionary attacks
+* `key_len` &mdash; parameter for scrypt
+* `N` &mdash; parameter for scrypt
+* `r` &mdash; parameter for scrypt
+* `p` &mdash; parameter for scrypt
+
+Effiapi manages and Qvisqve uses the password resource.
+
+### Member resource (memb)
+
+A membership resource has the following fields:
+
+* `subject-id` &mdash; the resource id of the subject resource for
+ the member
+* `fullname` &mdash; the full name of the member
+* `primary-email` &mdash; the primary email address for the member
+ (and currently the only one)
+* `years-paid` &mdash; 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" \
+ "$@"