Restrict User.update_user to admin; allow :update for email only
- Add ActorIsAdmin policy check (admin permission set only) - User: policy action(:update_user) forbid_unless + authorize_if ActorIsAdmin - User: primary :update action accept [:email] for non-admin profile edit
This commit is contained in:
parent
faee780aab
commit
14fa873640
2 changed files with 31 additions and 0 deletions
|
|
@ -103,6 +103,7 @@ defmodule Mv.Accounts.User do
|
|||
# the specialized :update_user action below.
|
||||
update :update do
|
||||
primary? true
|
||||
accept [:email]
|
||||
|
||||
# Required because custom validation functions (email validation, member relationship validation)
|
||||
# cannot be executed atomically. These validations need to query the database and perform
|
||||
|
|
@ -310,6 +311,14 @@ defmodule Mv.Accounts.User do
|
|||
authorize_if expr(id == ^actor(:id))
|
||||
end
|
||||
|
||||
# update_user allows :member argument (link/unlink). Only admins may use it to prevent
|
||||
# privilege escalation (own_data could otherwise link to any member and get :linked scope).
|
||||
policy action(:update_user) do
|
||||
description "Only admins can update user with member link/unlink"
|
||||
forbid_unless Mv.Authorization.Checks.ActorIsAdmin
|
||||
authorize_if Mv.Authorization.Checks.ActorIsAdmin
|
||||
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"
|
||||
|
|
|
|||
22
lib/mv/authorization/checks/actor_is_admin.ex
Normal file
22
lib/mv/authorization/checks/actor_is_admin.ex
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
defmodule Mv.Authorization.Checks.ActorIsAdmin do
|
||||
@moduledoc """
|
||||
Policy check: true when the actor's role has permission_set_name "admin".
|
||||
|
||||
Used to restrict actions (e.g. User.update_user for member link/unlink) to admins only.
|
||||
"""
|
||||
use Ash.Policy.SimpleCheck
|
||||
|
||||
@impl true
|
||||
def describe(_opts), do: "actor has admin permission set"
|
||||
|
||||
@impl true
|
||||
def match?(nil, _context, _opts), do: false
|
||||
|
||||
def match?(actor, _context, _opts) do
|
||||
ps_name =
|
||||
get_in(actor, [Access.key(:role), Access.key(:permission_set_name)]) ||
|
||||
get_in(actor, [Access.key("role"), Access.key("permission_set_name")])
|
||||
|
||||
ps_name == "admin"
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue