#!/bin/sh # The portal's OAuth2 client and one Kanidm group per desk, mapped into # the `groups` claim under the names the pages use in `qualifies`. # Portal reads that claim at login (portal src/auth.rs). Rerunnable. # # Logs in first (interactive, idm_admin's password from bootstrap.sh), # then writes the client secret into .env and portal.env and restarts # the portal. Needs the kanidm CLI on this machine. set -eu cd "$(dirname "$0")" . ./.env K="kanidm -D idm_admin -H https://$ID_HOST" C=$OAUTH2_CLIENT_ID # Already signed in? Then do not ask again: this script is meant to be # rerunnable, and the session outlives a single run. $K self whoami >/dev/null 2>&1 || $K login has_client() { $K system oauth2 get "$1" 2>/dev/null | grep -q '^name:'; } has_group() { $K group get "$1" 2>/dev/null | grep -q '^name:'; } has_client $C || $K system oauth2 create $C "$SITE_NAME" "https://$PORTAL_HOST" $K system oauth2 add-redirect-url $C "https://$PORTAL_HOST/auth/callback" || true # The desk groups: every group the content gates a directory on. Keep # this list equal to the `qualifies` values under questions/. has_group tomtervel_members || $K group create tomtervel_members for g in kasserer styret komiteer nabohjelp arrangementer elvesti horingsinstans lekeplasser miljogate pendlerforhold trafikk; do has_group tomtervel_$g || $K group create tomtervel_$g $K group add-members tomtervel_members tomtervel_$g done # Portal asks for openid, profile and email; groups arrive as a claim. $K system oauth2 update-scope-map $C tomtervel_members openid profile email for g in kasserer styret komiteer nabohjelp arrangementer elvesti horingsinstans lekeplasser miljogate pendlerforhold trafikk; do $K system oauth2 update-claim-map $C groups tomtervel_$g $g done $K system oauth2 update-claim-map-join $C groups array # What a member sees when they land on the login page. Out of the box # Kanidm says "kanidm" and shows its own mark, which tells a neighbour # nothing about whose site they are signing in to - and a login page # that looks like it belongs to no one is the kind of thing people # rightly hesitate over. # # The logo comes from the content repo, because that is already where # this site's identity lives: the same file site.yaml uses as the # favicon. Branding follows the content, not this repo. $K system domain set-displayname "$SITE_NAME" || true $K system oauth2 set-displayname $C "$SITE_NAME" || true logo=$(mktemp --suffix=.svg) if curl -sfL "$CONTENT_REPO/raw/branch/$CONTENT_BRANCH/images/logo.svg" -o "$logo" && [ -s "$logo" ]; then $K system domain set-image "$logo" svg || echo "note: could not set the instance logo" $K system oauth2 set-image $C "$logo" svg || echo "note: could not set the client logo" else echo "note: no images/logo.svg in the content repo - leaving the default mark" fi rm -f "$logo" secret=$($K system oauth2 show-basic-secret $C 2>/dev/null | tail -1) sed -i "s|^OAUTH2_CLIENT_SECRET=.*|OAUTH2_CLIENT_SECRET=$secret|" .env portal.env # Onboarding from a desk. A committee inviting a neighbour, and any # state whose `grants:` makes someone a member, both go through Kanidm # as this service account - not as a person, and not as an admin. It is # in idm_people_on_boarding, which may create people and issue a first # credential reset and nothing else, so the token cannot touch anyone's # existing credentials. idm_people_pii_read lets an invite find someone # who already has an account by their email, and add them to the group # instead of making a second account for the same person. # # The token is shown once, by Kanidm, at creation. Written straight into # the env files here and never printed. SA=portal-onboarding if ! $K service-account get $SA >/dev/null 2>&1; then $K service-account create $SA "Portal onboarding" idm_admin $K group add-members idm_people_on_boarding $SA $K group add-members idm_people_pii_read $SA || true fi if ! grep -q '^KANIDM_API_TOKEN=.' portal.env 2>/dev/null; then token=$($K service-account api-token generate $SA "portal" --readwrite | tail -1) if [ -n "$token" ]; then grep -q '^KANIDM_API_TOKEN=' portal.env \ && sed -i "s|^KANIDM_API_TOKEN=.*|KANIDM_API_TOKEN=$token|" portal.env \ || printf 'KANIDM_API_TOKEN=%s\n' "$token" >> portal.env echo "onboarding token written to portal.env" else # Loudly, and with whatever the CLI said: the first version of this # passed `--rw` for a flag that is spelled `--readwrite`, swallowed # the error, and reported a bare warning that said nothing about # why. A step that leaves invites broken should not be quiet about # how it failed. echo "warning: could not generate the onboarding token - invites will fail closed until it is set" >&2 echo " retry by hand: $K service-account api-token generate $SA portal --readwrite" >&2 fi fi podman compose restart portal echo "client $C configured; portal restarted with its secret" echo echo "Give people their desk (membership is read at login):" echo " $K group add-members tomtervel_styret " echo "Create a person:" echo " $K person create '' && $K person update --mail " echo " $K person credential create-reset-token "