Add OidcRoleSync: apply Admin/Mitglied from OIDC groups
Register and sign-in call apply_admin_role_from_user_info; users in configured admin group get Admin role, others get Mitglied. Internal User action + bypass policy.
This commit is contained in:
parent
a6e35da0f7
commit
99722dee26
4 changed files with 302 additions and 1 deletions
|
|
@ -187,6 +187,13 @@ defmodule Mv.Accounts.User do
|
|||
require_atomic? false
|
||||
end
|
||||
|
||||
# Internal: set role from OIDC group sync (Mv.OidcRoleSync). Bypass policy when context.private.oidc_role_sync.
|
||||
# Same "at least one admin" validation as update_user (see validations where action_is).
|
||||
update :set_role_from_oidc_sync do
|
||||
accept [:role_id]
|
||||
require_atomic? false
|
||||
end
|
||||
|
||||
# Admin action for direct password changes in admin panel
|
||||
# Uses the official Ash Authentication HashPasswordChange with correct context
|
||||
update :admin_set_password do
|
||||
|
|
@ -260,6 +267,17 @@ defmodule Mv.Accounts.User do
|
|||
# linked their account via OIDC. Password-only users (oidc_id = nil)
|
||||
# cannot be accessed via OIDC login without password verification.
|
||||
filter expr(oidc_id == get_path(^arg(:user_info), [:sub]))
|
||||
|
||||
# Sync role from OIDC groups after sign-in (e.g. admin group → Admin role)
|
||||
prepare Ash.Resource.Preparation.Builtins.after_action(fn query, records, _context ->
|
||||
user_info = Ash.Query.get_argument(query, :user_info) || %{}
|
||||
|
||||
Enum.each(records, fn user ->
|
||||
Mv.OidcRoleSync.apply_admin_role_from_user_info(user, user_info)
|
||||
end)
|
||||
|
||||
{:ok, records}
|
||||
end)
|
||||
end
|
||||
|
||||
create :register_with_rauthy do
|
||||
|
|
@ -297,6 +315,16 @@ defmodule Mv.Accounts.User do
|
|||
|
||||
# Sync user email to member when linking (User → Member)
|
||||
change Mv.EmailSync.Changes.SyncUserEmailToMember
|
||||
|
||||
# Sync role from OIDC groups (e.g. admin group → Admin role) after user is created/updated
|
||||
change fn changeset, _ctx ->
|
||||
user_info = Ash.Changeset.get_argument(changeset, :user_info)
|
||||
|
||||
Ash.Changeset.after_action(changeset, fn _cs, record ->
|
||||
Mv.OidcRoleSync.apply_admin_role_from_user_info(record, user_info)
|
||||
{:ok, Ash.get!(__MODULE__, record.id, authorize?: false, domain: Mv.Accounts)}
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -323,6 +351,13 @@ defmodule Mv.Accounts.User do
|
|||
authorize_if Mv.Authorization.Checks.ActorIsAdmin
|
||||
end
|
||||
|
||||
# set_role_from_oidc_sync: internal only (called from Mv.OidcRoleSync on registration/sign-in).
|
||||
# Not exposed in code_interface; must never be callable by clients.
|
||||
bypass action(:set_role_from_oidc_sync) do
|
||||
description "Internal: OIDC role sync (server-side only)"
|
||||
authorize_if always()
|
||||
end
|
||||
|
||||
# UPDATE/DESTROY via HasPermission (evaluates PermissionSets scope)
|
||||
policy action_type([:read, :create, :update, :destroy]) do
|
||||
description "Check permissions from user's role and permission set"
|
||||
|
|
@ -446,7 +481,7 @@ defmodule Mv.Accounts.User do
|
|||
end
|
||||
end,
|
||||
on: [:update],
|
||||
where: [action_is(:update_user)]
|
||||
where: [action_is([:update_user, :set_role_from_oidc_sync])]
|
||||
|
||||
# Prevent modification of the system actor user (required for internal operations).
|
||||
# Block update/destroy on UI-exposed actions only; :update_internal is used by bootstrap/tests.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue