Remove NoActor bypass from User and Member policies
This removes the NoActor bypass that was masking authorization bugs in tests. All operations now require an explicit actor for authorization.
This commit is contained in:
parent
b6992f8488
commit
e72b7ab2e8
2 changed files with 6 additions and 17 deletions
|
|
@ -275,12 +275,6 @@ defmodule Mv.Accounts.User do
|
||||||
authorize_if always()
|
authorize_if always()
|
||||||
end
|
end
|
||||||
|
|
||||||
# NoActor bypass (test fixtures only, see no_actor.ex)
|
|
||||||
bypass action_type([:create, :read, :update, :destroy]) do
|
|
||||||
description "Allow system operations without actor (test environment only)"
|
|
||||||
authorize_if Mv.Authorization.Checks.NoActor
|
|
||||||
end
|
|
||||||
|
|
||||||
# READ bypass for list queries (scope :own via expr)
|
# READ bypass for list queries (scope :own via expr)
|
||||||
bypass action_type(:read) do
|
bypass action_type(:read) do
|
||||||
description "Users can always read their own account"
|
description "Users can always read their own account"
|
||||||
|
|
|
||||||
|
|
@ -303,15 +303,6 @@ defmodule Mv.Membership.Member do
|
||||||
# Authorization Policies
|
# Authorization Policies
|
||||||
# Order matters: Most specific policies first, then general permission check
|
# Order matters: Most specific policies first, then general permission check
|
||||||
policies do
|
policies do
|
||||||
# SYSTEM OPERATIONS: Allow CRUD operations without actor (TEST ENVIRONMENT ONLY)
|
|
||||||
# In test: All operations allowed (for test fixtures)
|
|
||||||
# In production/dev: ALL operations denied without actor (fail-closed for security)
|
|
||||||
# NoActor.check uses compile-time environment detection to prevent security issues
|
|
||||||
bypass action_type([:create, :read, :update, :destroy]) do
|
|
||||||
description "Allow system operations without actor (test environment only)"
|
|
||||||
authorize_if Mv.Authorization.Checks.NoActor
|
|
||||||
end
|
|
||||||
|
|
||||||
# SPECIAL CASE: Users can always READ their linked member
|
# SPECIAL CASE: Users can always READ their linked member
|
||||||
# This allows users with ANY permission set to read their own linked member
|
# This allows users with ANY permission set to read their own linked member
|
||||||
# Check using the inverse relationship: User.member_id → Member.id
|
# Check using the inverse relationship: User.member_id → Member.id
|
||||||
|
|
@ -403,8 +394,12 @@ defmodule Mv.Membership.Member do
|
||||||
current_member_id = changeset.data.id
|
current_member_id = changeset.data.id
|
||||||
|
|
||||||
# Get actor from changeset context for authorization
|
# Get actor from changeset context for authorization
|
||||||
# If no actor is present, this will fail in production (fail-closed)
|
# Use system_actor as fallback if no actor is present (for systemic operations)
|
||||||
actor = Map.get(changeset.context || %{}, :actor)
|
actor =
|
||||||
|
case Map.get(changeset.context || %{}, :actor) do
|
||||||
|
nil -> Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
actor -> actor
|
||||||
|
end
|
||||||
|
|
||||||
# Check the current state of the user in the database
|
# Check the current state of the user in the database
|
||||||
# Check if authorization is disabled in the parent operation's context
|
# Check if authorization is disabled in the parent operation's context
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue