Identify the bot's web callers by Discord id, and isolate the bot's network
authentik/vanguard-profile-scope-mapping.py (new, and the first time that mapping is version-controlled rather than pasted from the docs) emits the Discord snowflake from the account's source connection alongside the inherited groups, so the bot never has to match a name. docker-compose.yml: discord-bot moves to its own network. It trusts the identity headers Caddy injects, and it shared the default bridge with jellyfin, copyparty, syncthing, gitea, act_runner and cadvisor, any of which could reach :8000 directly and forge them. It needs no sibling container: Caddy uses the published loopback port and MariaDB is reached through host.docker.internal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
38
authentik/vanguard-profile-scope-mapping.py
Normal file
38
authentik/vanguard-profile-scope-mapping.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# Authentik SCOPE MAPPING (not a policy): adds two things the apps behind the proxy need and the built-in
|
||||
# mappings do not provide.
|
||||
#
|
||||
# Paste into: Customization -> Property Mappings -> Create -> Scope Mapping
|
||||
# Name: Vanguard profile (nested groups + discord id)
|
||||
# Scope name: profile
|
||||
# Then tick it, NEXT TO the managed "authentik default OAuth Mapping: OpenID 'profile'", on every provider the
|
||||
# community uses: the "Vanguard sites" proxy provider, Jellyfin and Gitea (Advanced protocol settings -> Scopes).
|
||||
# Claims from several mappings are merged, so both run and neither needs removing. Proxy providers re-add the
|
||||
# managed one on every save, which is why this adds to it rather than replacing it.
|
||||
#
|
||||
# 1. groups: the managed mapping emits ak_groups, i.e. DIRECT memberships only, so a group inherited through a
|
||||
# parent never reaches the apps. This emits only the inherited ones; merged with the managed mapping's direct
|
||||
# ones the apps see the full set, with no duplicates.
|
||||
#
|
||||
# 2. discord_id: the Discord snowflake, taken from the source connection Authentik already stores when it links
|
||||
# an account. It reaches the apps in X-Authentik-Jwt. The Discord bot uses it to identify the caller exactly,
|
||||
# instead of matching an Authentik username against Discord names — names are mutable, reusable, and server
|
||||
# nicknames are not unique, so name matching can both lock the right person out and let the wrong one in.
|
||||
#
|
||||
# Takes effect on the next login.
|
||||
|
||||
DISCORD_SOURCE_SLUG = "discord"
|
||||
|
||||
direct = set(request.user.ak_groups.all())
|
||||
inherited = sorted(group.name for group in request.user.all_groups() if group not in direct)
|
||||
|
||||
discord_id = None
|
||||
for attribute in ("usersourceconnection_set", "source_connections"): # the related name differs by version
|
||||
related = getattr(request.user, attribute, None)
|
||||
if related is None:
|
||||
continue
|
||||
connection = (related.filter(source__slug=DISCORD_SOURCE_SLUG).first() or related.first())
|
||||
if connection is not None:
|
||||
discord_id = getattr(connection, "identifier", None) or None
|
||||
break
|
||||
|
||||
return {"groups": inherited, "discord_id": discord_id}
|
||||
Reference in New Issue
Block a user