Add CustomFieldValueCreateScope check for create actions
Ash cannot apply filters to create; this check enforces :linked/:all scope via strict_check only (no filter).
This commit is contained in:
parent
b93b419246
commit
80efa5b3bd
1 changed files with 64 additions and 0 deletions
|
|
@ -0,0 +1,64 @@
|
||||||
|
defmodule Mv.Authorization.Checks.CustomFieldValueCreateScope do
|
||||||
|
@moduledoc """
|
||||||
|
Policy check for CustomFieldValue create actions only.
|
||||||
|
|
||||||
|
Use this for create instead of HasPermission because Ash cannot apply
|
||||||
|
filters to create actions ("Cannot use a filter to authorize a create").
|
||||||
|
This check performs the same scope logic as HasPermission for create
|
||||||
|
(PermissionSets + :linked/:all) but only implements strict_check, so it
|
||||||
|
never adds a filter.
|
||||||
|
|
||||||
|
Used in CustomFieldValue policies:
|
||||||
|
policy action_type(:create) do
|
||||||
|
authorize_if Mv.Authorization.Checks.CustomFieldValueCreateScope
|
||||||
|
end
|
||||||
|
"""
|
||||||
|
use Ash.Policy.Check
|
||||||
|
alias Mv.Authorization.PermissionSets
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe(_opts),
|
||||||
|
do: "CustomFieldValue create allowed by permission set scope (:linked or :all)"
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def strict_check(actor, authorizer, _opts) do
|
||||||
|
actor = ensure_role_loaded(actor)
|
||||||
|
|
||||||
|
with %{role: %{permission_set_name: ps_name}} when not is_nil(ps_name) <- actor,
|
||||||
|
{:ok, ps_atom} <- PermissionSets.permission_set_name_to_atom(ps_name),
|
||||||
|
permissions <- PermissionSets.get_permissions(ps_atom),
|
||||||
|
perm <- find_custom_field_value_create(permissions.resources) do
|
||||||
|
case perm do
|
||||||
|
nil -> {:ok, false}
|
||||||
|
%{scope: :all} -> {:ok, true}
|
||||||
|
%{scope: :linked} -> {:ok, member_id_matches?(authorizer, actor)}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
_ -> {:ok, false}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp find_custom_field_value_create(resources) do
|
||||||
|
Enum.find(resources, fn p ->
|
||||||
|
p.resource == "CustomFieldValue" and p.action == :create and p.granted
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp member_id_matches?(authorizer, actor) do
|
||||||
|
member_id = get_create_member_id(authorizer)
|
||||||
|
!is_nil(member_id) and member_id == actor.member_id
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_create_member_id(authorizer) do
|
||||||
|
changeset = authorizer.changeset || authorizer.subject
|
||||||
|
|
||||||
|
if changeset && function_exported?(Ash.Changeset, :get_attribute, 2) do
|
||||||
|
Ash.Changeset.get_attribute(changeset, :member_id)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp ensure_role_loaded(actor), do: Mv.Authorization.Actor.ensure_loaded(actor)
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue