mirror of
https://github.com/rubenhensen/k8scd.git
synced 2026-11-15 22:29:09 +01:00
Adds Scouts Online 3 (login.scouting.nl) as an OIDC source. Its userinfo has the member's roles within the group; a property mapping puts every member in "MBG leden" and those with an active Kaderlid role also in "MBG kader", on every login. Members become external users. Family members can share an email address and immich needs a unique one, so those get a plus address with their member number. The immich provider now authenticates through a flow whose only stage is an identification stage with this one source and no fields, which sends people straight on to Scouts Online. The source's own flows only run through the source.
279 lines
11 KiB
YAML
279 lines
11 KiB
YAML
# Login for the Scouting MBG photos (immich on foto.scoutingmbg.nl).
|
|
# Mounted as a directory, unlike the other blueprints, so authentik picks up
|
|
# changes without a restart; secrets come from files in /secrets/scouting
|
|
# for the same reason (see apps/templates/authentik-helm.yaml).
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: authentik-blueprint-scouting
|
|
data:
|
|
immich-oidc.yaml: |
|
|
version: 1
|
|
metadata:
|
|
name: immich OIDC
|
|
entries:
|
|
# The source and the login flow below come from scouts-online.yaml.
|
|
- model: authentik_blueprints.metaapplyblueprint
|
|
attrs:
|
|
identifiers:
|
|
path: custom/scouting/scouts-online.yaml
|
|
required: true
|
|
# Filled by the Scouts Online source on every login: every member, and
|
|
# the members with an active Kaderlid role.
|
|
- model: authentik_core.group
|
|
id: mbg-leden
|
|
state: present
|
|
identifiers:
|
|
name: MBG leden
|
|
- model: authentik_core.group
|
|
id: mbg-kader
|
|
state: present
|
|
identifiers:
|
|
name: MBG kader
|
|
# immich syncs both claims on every login. A quota of 0 makes immich
|
|
# refuse uploads, -1 means unlimited.
|
|
- model: authentik_providers_oauth2.scopemapping
|
|
id: immich-scope
|
|
state: present
|
|
identifiers:
|
|
name: "immich: role and quota"
|
|
attrs:
|
|
name: "immich: role and quota"
|
|
scope_name: immich
|
|
description: Upload rights in the Scouting MBG photos
|
|
expression: |
|
|
admin = ak_is_group_member(request.user, name="authentik Admins")
|
|
uploader = admin or ak_is_group_member(request.user, name="MBG kader")
|
|
return {
|
|
"immich_role": "admin" if admin else "user",
|
|
"immich_quota": -1 if uploader else 0,
|
|
}
|
|
- model: authentik_providers_oauth2.oauth2provider
|
|
id: immich-provider
|
|
state: present
|
|
identifiers:
|
|
name: immich
|
|
attrs:
|
|
name: immich
|
|
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
|
|
# Straight on to Scouts Online. Admins with a password log in at
|
|
# authentik first.
|
|
authentication_flow: !Find [authentik_flows.flow, [slug, scouts-online-login]]
|
|
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
|
|
client_type: confidential
|
|
client_id: immich
|
|
client_secret: !File /secrets/scouting/immich-oidc-client-secret
|
|
redirect_uris:
|
|
- matching_mode: strict
|
|
url: https://foto.scoutingmbg.nl/auth/login
|
|
# "Link to OAuth" in immich's account settings
|
|
- matching_mode: strict
|
|
url: https://foto.scoutingmbg.nl/user-settings
|
|
- matching_mode: strict
|
|
url: app.immich:///oauth-callback
|
|
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]]
|
|
property_mappings:
|
|
- !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-openid]]
|
|
- !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-email]]
|
|
- !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-profile]]
|
|
- !KeyOf immich-scope
|
|
- model: authentik_core.application
|
|
id: immich-app
|
|
state: present
|
|
identifiers:
|
|
slug: immich
|
|
attrs:
|
|
name: Scouting MBG foto's
|
|
provider: !KeyOf immich-provider
|
|
meta_launch_url: https://foto.scoutingmbg.nl
|
|
policy_engine_mode: any
|
|
- model: authentik_policies.policybinding
|
|
state: present
|
|
identifiers:
|
|
order: 0
|
|
target: !KeyOf immich-app
|
|
attrs:
|
|
group: !KeyOf mbg-leden
|
|
- model: authentik_policies.policybinding
|
|
state: present
|
|
identifiers:
|
|
order: 1
|
|
target: !KeyOf immich-app
|
|
attrs:
|
|
group: !Find [authentik_core.group, [name, "authentik Admins"]]
|
|
scouts-online.yaml: |
|
|
version: 1
|
|
metadata:
|
|
name: Scouts Online
|
|
entries:
|
|
- model: authentik_sources_oauth.oauthsourcepropertymapping
|
|
id: user-mapping
|
|
state: present
|
|
identifiers:
|
|
name: "Scouts Online: user"
|
|
attrs:
|
|
name: "Scouts Online: user"
|
|
expression: |
|
|
# info is the userinfo of Scouts Online (https://login.scouting.nl/docs/api).
|
|
# It only holds the roles within the organisations of this connection,
|
|
# which is just the group.
|
|
from datetime import date
|
|
|
|
today = date.today().isoformat()
|
|
roles = {role.get("id"): role for role in (info.get("roles") or {}).values()}
|
|
kader = False
|
|
for assignment in info.get("role_assignments") or []:
|
|
start = (assignment.get("start_date") or "")[:10]
|
|
end = (assignment.get("end_date") or "")[:10]
|
|
if (start and start > today) or (end and end < today):
|
|
continue
|
|
role = roles.get(assignment.get("role_id")) or {}
|
|
if "Kaderlid" in (role.get("member_type") or []):
|
|
kader = True
|
|
|
|
member_id = info.get("member_id")
|
|
email = info.get("email") or ""
|
|
# Family members can share an email address; immich needs one per account.
|
|
if email and info.get("multiple_accounts"):
|
|
local, _, domain = email.partition("@")
|
|
email = f"{local}+{member_id}@{domain}"
|
|
|
|
return {
|
|
"username": f"sol-{member_id}",
|
|
"email": email,
|
|
"name": info.get("name") or "",
|
|
"groups": ["MBG leden", "MBG kader"] if kader else ["MBG leden"],
|
|
"attributes": {"sol_member_id": member_id},
|
|
}
|
|
# The source's flows can only be reached through the source.
|
|
- model: authentik_policies_expression.expressionpolicy
|
|
id: sso-only
|
|
state: present
|
|
identifiers:
|
|
name: scouts-online-sso-only
|
|
attrs:
|
|
expression: return ak_is_sso_flow
|
|
# New members become external users: they can use the apps they are
|
|
# let into, not authentik's own interface.
|
|
- model: authentik_stages_user_write.userwritestage
|
|
id: user-write
|
|
state: present
|
|
identifiers:
|
|
name: scouts-online-user-write
|
|
attrs:
|
|
user_creation_mode: always_create
|
|
user_type: external
|
|
- model: authentik_stages_user_login.userloginstage
|
|
id: user-login
|
|
state: present
|
|
identifiers:
|
|
name: scouts-online-user-login
|
|
- model: authentik_flows.flow
|
|
id: enrollment-flow
|
|
state: present
|
|
identifiers:
|
|
slug: scouts-online-enrollment
|
|
attrs:
|
|
name: Scouts Online enrollment
|
|
title: Scouting MBG
|
|
designation: enrollment
|
|
authentication: none
|
|
- model: authentik_flows.flowstagebinding
|
|
state: present
|
|
identifiers:
|
|
order: 0
|
|
target: !KeyOf enrollment-flow
|
|
stage: !KeyOf user-write
|
|
- model: authentik_flows.flowstagebinding
|
|
state: present
|
|
identifiers:
|
|
order: 1
|
|
target: !KeyOf enrollment-flow
|
|
stage: !KeyOf user-login
|
|
- model: authentik_policies.policybinding
|
|
state: present
|
|
identifiers:
|
|
order: 0
|
|
target: !KeyOf enrollment-flow
|
|
policy: !KeyOf sso-only
|
|
- model: authentik_flows.flow
|
|
id: authentication-flow
|
|
state: present
|
|
identifiers:
|
|
slug: scouts-online-authentication
|
|
attrs:
|
|
name: Scouts Online authentication
|
|
title: Scouting MBG
|
|
designation: authentication
|
|
authentication: none
|
|
- model: authentik_flows.flowstagebinding
|
|
state: present
|
|
identifiers:
|
|
order: 0
|
|
target: !KeyOf authentication-flow
|
|
stage: !KeyOf user-login
|
|
- model: authentik_policies.policybinding
|
|
state: present
|
|
identifiers:
|
|
order: 0
|
|
target: !KeyOf authentication-flow
|
|
policy: !KeyOf sso-only
|
|
# SOL only lets in members of the organisations picked in its
|
|
# connection, and only sends roles within them. The callback URL is
|
|
# https://authentik.rubenhensen.nl/source/oauth/callback/scouts-online/
|
|
- model: authentik_sources_oauth.oauthsource
|
|
id: source
|
|
state: present
|
|
identifiers:
|
|
slug: scouts-online
|
|
attrs:
|
|
name: Scouts Online
|
|
slug: scouts-online
|
|
enabled: true
|
|
provider_type: openidconnect
|
|
consumer_key: !File /secrets/scouting/scouts-online-client-id
|
|
consumer_secret: !File /secrets/scouting/scouts-online-client-secret
|
|
authorization_url: https://login.scouting.nl/authorize
|
|
access_token_url: https://login.scouting.nl/token
|
|
profile_url: https://login.scouting.nl/oidc/userinfo
|
|
oidc_well_known_url: https://login.scouting.nl/.well-known/openid-configuration
|
|
oidc_jwks_url: https://login.scouting.nl/.well-known/openid-jwks.json
|
|
additional_scopes: membership roles
|
|
pkce: S256
|
|
authorization_code_auth_method: basic_auth
|
|
user_matching_mode: identifier
|
|
# Links to the groups that immich-oidc.yaml creates
|
|
group_matching_mode: name_link
|
|
user_path_template: goauthentik.io/sources/scouts-online
|
|
enrollment_flow: !KeyOf enrollment-flow
|
|
authentication_flow: !KeyOf authentication-flow
|
|
user_property_mappings:
|
|
- !KeyOf user-mapping
|
|
# Where immich sends people who aren't logged in. An identification
|
|
# stage without fields and with one source goes straight to it.
|
|
- model: authentik_stages_identification.identificationstage
|
|
id: identification
|
|
state: present
|
|
identifiers:
|
|
name: scouts-online-identification
|
|
attrs:
|
|
user_fields: []
|
|
sources:
|
|
- !KeyOf source
|
|
show_source_labels: true
|
|
- model: authentik_flows.flow
|
|
id: login-flow
|
|
state: present
|
|
identifiers:
|
|
slug: scouts-online-login
|
|
attrs:
|
|
name: Scouts Online login
|
|
title: Scouting MBG
|
|
designation: authentication
|
|
- model: authentik_flows.flowstagebinding
|
|
state: present
|
|
identifiers:
|
|
order: 0
|
|
target: !KeyOf login-flow
|
|
stage: !KeyOf identification
|