I have read the beta version of the book Ash Framework. It’s something Ash needed! Congratulations @zachdaniel and @sevenseacat , I appreciate it. I’m looking forward to the new chapters!
After reading chapter 6 about Authorization, I have a question.
Imagine a typical domain where we have:
Business (The tenant, everything is related to a business)
has many User. They are managers. Each manager can modify data related to the business.
Posts: Belong to business. The tenant is the business, and any of the managers can be the actor in a field like created_by
Comments: Any user can create comments. The actor is the user that created the comment
What I want to check:
Only business managers can update/delete comments
I see that the check actor_attribute_equals is very handy, but I need to check the actor following relationships on the instance being updated/deleted:
actor in (Comment -> Post -> Business -> managers)
What is the recommended Ash way to create a policy like this one?
Yes, I think that’s what I need! I don’t know how I missed that.
A couple more questions:
Does the check load the relationships, or is it something we have to do before using the check?
If the Users are related to Business using an intermediate M2M table with the field :role. Is it possible to check the role of the user to make sure that only :admin users can pass the check?
I hope neither of you mind, but I have a question so close to this that I thought I’d reply here instead of creating a different thread. In fact, this thread did answer a question I already had that leads up to the following question.
Forgive me but I’m going to change the domain.
a User has many Contacts and
a Contact belongs to a User and has many EmailAddresses
I would like to ensure that when a User creates or modifies an EmailAddress, it belongs to a Contact that in turn belongs to a User (who is the actor). In other words, If I have Zach as a Contact but adrian does not, I don’t want adrian to be able to create an EmailAddress for Zach. Correct me if I’m wrong, but in this thread it appears I can do this in an update action with
However, during a create action, all I have is the contact_id. How can I make sure that the Contact whose id is the provided contact_id actually belongs to the User/actor? Is that done in the action definition? Is that done in the policies?
I don’t know if this is crazy or not, but it works. Is this crazy or crazy like a fox?
defmodule MyApp.Checks.RelatedResourceBelongsToActorCheck do
@moduledoc false
use Ash.Policy.SimpleCheck
def describe(_), do: "Check to make sure that the related resource's user is the actor"
def match?(actor, %{subject: subject}, context) do
get_fn = Keyword.get(context, :get_fn, fn _, _ -> nil end)
case get_fn.(subject.attributes.person_id, actor: actor) do
{:ok, person} ->
person.user_id == actor.id
_ ->
false
end
end
end
policies do
policy action_type(:create) do
authorize_if {MyApp.Checks.RelatedResourceBelongsToActorCheck, get_fn: &MyApp.People.get_person/2}
end
end