Add Role resource policies (defense-in-depth)

- PermissionSets: Role read :all for own_data, read_only, normal_user; admin keeps full CRUD
- Role resource: authorizers and policies with HasPermission
- Tests: role_policies_test.exs (read all, create/update/destroy admin only)
- Fix existing tests to pass actor or authorize?: false for Role operations
This commit is contained in:
Moritz 2026-02-04 12:37:48 +01:00
parent 10f37a1246
commit 4d3a64c177
Signed by: moritz
GPG key ID: 1020A035E5DD0824
8 changed files with 304 additions and 51 deletions

View file

@ -78,6 +78,7 @@ defmodule Mv.Authorization.PermissionSets do
defp custom_field_read_all, do: [perm("CustomField", :read, :all)]
defp membership_fee_type_read_all, do: [perm("MembershipFeeType", :read, :all)]
defp membership_fee_cycle_read_all, do: [perm("MembershipFeeCycle", :read, :all)]
defp role_read_all, do: [perm("Role", :read, :all)]
@doc """
Returns the list of all valid permission set names.
@ -129,7 +130,8 @@ defmodule Mv.Authorization.PermissionSets do
group_read_all() ++
[perm("MemberGroup", :read, :linked)] ++
membership_fee_type_read_all() ++
[perm("MembershipFeeCycle", :read, :linked)],
[perm("MembershipFeeCycle", :read, :linked)] ++
role_read_all(),
pages: [
# No "/" - Mitglied must not see member index at root (same content as /members).
# Own profile (sidebar links to /users/:id) and own user edit
@ -156,7 +158,8 @@ defmodule Mv.Authorization.PermissionSets do
group_read_all() ++
[perm("MemberGroup", :read, :all)] ++
membership_fee_type_read_all() ++
membership_fee_cycle_read_all(),
membership_fee_cycle_read_all() ++
role_read_all(),
pages: [
"/",
# Own profile (sidebar links to /users/:id; redirect target must be allowed)
@ -211,7 +214,8 @@ defmodule Mv.Authorization.PermissionSets do
perm("MembershipFeeCycle", :create, :all),
perm("MembershipFeeCycle", :update, :all),
perm("MembershipFeeCycle", :destroy, :all)
],
] ++
role_read_all(),
pages: [
"/",
# Own profile (sidebar links to /users/:id; redirect target must be allowed)

View file

@ -37,7 +37,8 @@ defmodule Mv.Authorization.Role do
"""
use Ash.Resource,
domain: Mv.Authorization,
data_layer: AshPostgres.DataLayer
data_layer: AshPostgres.DataLayer,
authorizers: [Ash.Policy.Authorizer]
postgres do
table "roles"
@ -86,6 +87,13 @@ defmodule Mv.Authorization.Role do
end
end
policies do
policy action_type([:read, :create, :update, :destroy]) do
description "Role access: read for all permission sets, create/update/destroy for admin only (PermissionSets)"
authorize_if Mv.Authorization.Checks.HasPermission
end
end
validations do
validate one_of(
:permission_set_name,