I’m just getting my head around basic AshAuthorization and still struggle with some of the relationship DSL… and I’ve no idea how to tackle this one.
I have two resources, Teams
and Users
(the later being defined by AshAuthentication). They are related via a many_to_many
named :team_members
:
# Team
policies do
bypass actor_attribute_equals(:role, :admin) do
authorize_if always()
end
policy action_type(:update) do
authorize_if actor_attribute_equals(:role, :team_lead) && expr(exists(team_memberships, user_id == ^actor(:id)))
end
end
relationships do
has_many :team_memberships, WasteWalk.Teams.Members
has_many :sprints, WasteWalk.Sprints.Sprint
many_to_many :team_members, WasteWalk.Accounts.User do
join_relationship :team_memberships
source_attribute_on_join_resource :team_id
destination_attribute_on_join_resource :user_id
end
end
As you can see, to update a team, you need to be a team lead for that team.
User
s are just users, as defined by Ash. I’ve added a many_to_many
relationship to the User
resource:
# User
relationships do
has_many :team_memberships, WasteWalk.Teams.Members
many_to_many :teams, WasteWalk.Teams.Team do
join_relationship :team_memberships
source_attribute_on_join_resource :user_id
destination_attribute_on_join_resource :team_id
end
end
Keeping in mind that only someone with a :team_leads
role can actually modify their own Team
, I want to extend that to team membership. In other words, only a :team_lead
can modify (create, destroy) the members of a team.
As it is now (see below) a team lead could modify another team’s membership. (The code API doesn’t really support it, but there’s nothing keeping someone from updating the Members
resource directly).
So I’m struggling with the DSL to prevent team leads from modifying relationships unless they are a :team_lead
(role) for the specific :team_id
they are updating. I’ve no idea how to do that with the policy DSL… (see comment, below – vague idea, but lacking practical knowledge).
# Members
policies do
bypass actor_attribute_equals(:role, :admin) do
authorize_if always()
end
policy action_type(:create) do
authorize_if actor_attribute_equals(:role, :admin)
# TODO restrict to only :team_lead's own teams:
# e.g. kind of like... && expr(exists(team_memberships, user_id == ^actor(:id)))
authorize_if actor_attribute_equals(:role, :team_lead) # &&...??
end
policy action_type(:read) do
authorize_if always()
end
end
actions do
defaults [:read]
create :create do
primary? true
accept [:user_id, :team_id]
end
end
relationships do
belongs_to :user, WasteWalk.Accounts.User, primary_key?: true, allow_nil?: false
belongs_to :team, WasteWalk.Teams.Team, primary_key?: true, allow_nil?: false
actions do
defaults [:read, :destroy, update: :*]
end
end