An example of a resource with authorization rules declared.
defmodule Author do
use Ash.Resource, name: "authors", type: "author"
use Ash.DataLayer.Ets, private?: true
actions do
read :default, authorization_steps: [authorize_if: always()]
create :default,
authorization_steps: [
authorize_if: user_attribute(:admin, true),
authorize_if: user_attribute(:manager, true)
]
end
attributes do
attribute :name, :string, authorization_steps: false
attribute :state, :string,
authorization_steps: [
authorize_if: user_attribute(:admin, true),
forbid_if: setting(to: "closed"),
authorize_if: always()
]
attribute :bio_locked, :boolean,
default: {:constant, false},
authorization_steps: false
attribute :self_manager, :boolean, authorization_steps: false
attribute :fired, :boolean, authorization_steps: false
end
relationships do
many_to_many :posts, Ash.Test.Authorization.CreateAuthorizationTest.Post,
through: Ash.Test.Authorization.CreateAuthorizationTest.AuthorPost
has_one :bio, Ash.Test.Authorization.CreateAuthorizationTest.Bio,
authorization_steps: [
forbid_if: attribute_equals(:bio_locked, true),
authorize_if: always()
]
end
end
An example of error output that is generated from a system like the above.
17:04:39.736 [info] forbidden:
Facts Gathered
Global facts:
✓ setting state to "closed" ⭑
✓ always true ⭑
✗ user.admin == true ⭑
✗ user.admin == true ⭑
✓ user.manager == true ⭑
Authorization run with `strict_access?: true`. This is the only safe way to authorize requests for lists of filtered data.
Some checks may still fetch data from the database, like filters on related data when their primary key was given.
Authorization Steps:
create - `default`:
↓ | authorize_if: user.admin == true ✗
✓ | authorize_if: user.manager == true ✓
------
change on `state`:
↓ | authorize_if: user.admin == true ✗
✗ | forbid_if: setting state to "closed" ✓
✓ | authorize_if: always true ✓
Scenarios:
No scenarios found. Under construction.
Eventually, scenarios will explain what data you could change to make the request possible.