Advise on using policies with related resources
I have two resources
Transfer
and Account
. Transfer updates the accounts balance it's related to.
Now I have admin which can create/update/read both resources.
I have an operator that can only create transfers.
The issue is updating the account balance when the operator creates the transfer. Since he does not have access to create/update an acccount.
How should I model my policies to handle this kind of situations?33 Replies
https://hexdocs.pm/ash/Ash.Policy.Check.Builtins.html#accessing_from/2 could maybe work if you use manage_relationship. Otherwise if you use a hook to call the action you can handle auth yourself, or set something in the context you can use to add a policy to your account.
@barnabasj I tried using
accessing_from
on create action it did not work, but it does on reads
So I tried putting some logs in the accessing_from.ex file. I noticed accessing_from
in the query.context
is nil, in the def match?(_actor, %{query: %Ash.Query{} = query}, options) do
function.
Don't know if it's a bug or I'm missing something.
So, what I assume is failing is that the lookup fails. because that one is done without the accessing_from, because at that point there is no relationship yet.
just for testing
not sure if you really want to allow all reads like this
Maybe there's no relationship yet, but the accessing_from could/should be set at this point? I find it strange that it's nil tbh.
The
action(:read)
makes it work. But now it opens all the reads as you mentioned too.there are potential security problems by setting it before the relationship exists
because you should only be able to relate to records that you are allowed to read
One big challenge for me is how to debug where the query for account is built, to check how the context is set there. But I really have no clue how to debug this. Any recommendations?
GitHub
ash/lib/ash/actions/managed_relationships.ex at 43af9c02d73861ef1d5...
A declarative, extensible framework for building Elixir applications. - ash-project/ash
The first time I ran into this, I also just looked for manage_relationship in the code and looked throught the module put some dbg's in.
Not sure if there is a better way
Oh yes this makes sense!
Currenlty to display the accounts on the UI, I use authorize?: false, for the Operator to see the list of accounts, to which he normally does not have access.
I was hoping that
accessing_from(Transfer, :in_account)
would let me at least create my transfer into the DB, because I am accessing the accounts table from the Transfer resource. Maybe I'm not understanding the meaning of accessing_from?GitHub
ash/lib/ash/actions/managed_relationships.ex at 43af9c02d73861ef1d5...
A declarative, extensible framework for building Elixir applications. - ash-project/ash
accessing_from should always be set if something is done through a relationship. it's just that the first read in manage_relationship is not going through the relationship, it's just a read on the resource because at that point the connection between the records does not exist yet.
is the operator not allowed to reads accounts at all?
like if you do authorize?: false at the moment, replacing that with a more sensible policy would maybe also fix the manage_relationship problem
Yes the operator should not read accounts. But they can do operations Transfers/Deposits that operates on Accounts.
Maybe the policy is too strick as you say?
What if I need to hide things like balance of the account and others?
https://hexdocs.pm/ash/policies.html#field-policies to the rescue
Totally agree with you.
But atleast we know we are calling the read from the parent resource at that moment in this case which is Transfer. The policy should pass from that particular context, without causing any security concerns.
I still think it's maybe the right call. I don't know if I could make my point a little clearer.
Thanks this looks interesting too.
you could also turn it around and add create_transfer action on the account that than creates the transfer and only give the operator access to those actions on the account
Yes you are right again. This can be turned in the other direction
@Zach Daniel should'nt tag you, but would like to know if this is a bug to report or close this as it is.
it always runs an action on the target resource, so you can debug by adding preparations/changes on the destination resource.
Its a good question if creating new records for a relationship should be considered
accessing_from
the create sets accessing_from, it's only the read before hand
oh
then yes that is correct
š
We should document this somewhere we can point people at
its by design otherwise you'd be able to "steal" records from other users
yeah, and add a flow diagram for how manage_relationship works
Thanks for volunteering ā¤ļø
š
Let's see what claude can come up with and refine that
Thanks very much for your support.
I'll mark this as solved then
I was just spelunking in the code and saw that there is a
debug?: true
option for manage_relationship, that logs a bunch of stuff
https://hexdocs.pm/ash/Ash.Changeset.html#manage_relationship/4@barnabasj
Actor is nil in
def match?(actor, %{resource: Mc.Banking.Account, action: action} = context, opts)
how are you calling the action?
I'm using Cinder to render the table
My policy is an Ash.Policy.SimpleCheck. Without the field_policy, it my custom policy works for normal policies. Just the fields one causing bugs.
can you reproduce it when calling the action directly in a test? or does it happen only using cinder?
if that's the case, it could be a bug. You should get the same actor you get in the regular policy IIRC
Yup. Bug with Cinder.
A regular call works well
Can I tag Rebecca Here?
We generally discourage tagging people and let them get to it in their own time, best thing would be a issue on GH with the steps to reproduce or even better a test that reproduces the issue
Turns out problem was me!
can you add the problem/solution here, so it can be indexed for the next person please
I did not pass the actor to my Cinder table.