mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 13:33:20 +12:00
dc73c3a3d5
Policy groups allow you to group policies by shared conditions. This can help simplify the mental overhead of large sets of policies. For example: ```elixir policies do policy_group actor_attribute_equals(:role, :owner) do policy action_type(:read) do authorize_if expr(owner_id == ^actor(:id)) end policy action_type([:create, :update, :destroy]) do forbid_if authorize_if expr(owner_id == ^actor(:id)) end end end ```
1290 lines
32 KiB
Markdown
1290 lines
32 KiB
Markdown
<!--
|
|
This file was generated by Spark. Do not edit it by hand.
|
|
-->
|
|
# DSL: Ash.Policy.Authorizer
|
|
|
|
An authorization extension for ash resources.
|
|
|
|
To add this extension to a resource, add it to the list of `authorizers` like so:
|
|
|
|
```elixir
|
|
use Ash.Resource,
|
|
...,
|
|
authorizers: [
|
|
Ash.Policy.Authorizer
|
|
]
|
|
```
|
|
|
|
A resource can be given a set of policies, which are enforced on each call to a resource action.
|
|
|
|
For reads, policies can be configured to filter out data that the actor shouldn't see, as opposed to
|
|
resulting in a forbidden error.
|
|
|
|
See the [policies guide](/documentation/topics/security/policies.md) for practical examples.
|
|
|
|
Policies are solved/managed via a boolean satisfiability solver. To read more about boolean satisfiability,
|
|
see this page: https://en.wikipedia.org/wiki/Boolean_satisfiability_problem. At the end of
|
|
the day, however, it is not necessary to understand exactly how Ash takes your
|
|
authorization requirements and determines if a request is allowed. The
|
|
important thing to understand is that Ash may or may not run any/all of your
|
|
authorization rules as they may be deemed unnecessary. As such, authorization
|
|
checks should have no side effects. Ideally, the checks built-in to ash should
|
|
cover the bulk of your needs.
|
|
|
|
|
|
## policies
|
|
A section for declaring authorization policies.
|
|
|
|
Each policy that applies must pass independently in order for the
|
|
request to be authorized.
|
|
|
|
See the [policies guide](/documentation/topics/security/policies.md) for more.
|
|
|
|
|
|
### Nested DSLs
|
|
* [policy](#policies-policy)
|
|
* authorize_if
|
|
* forbid_if
|
|
* authorize_unless
|
|
* forbid_unless
|
|
* [policy_group](#policies-policy_group)
|
|
* policy
|
|
* authorize_if
|
|
* forbid_if
|
|
* authorize_unless
|
|
* forbid_unless
|
|
* [bypass](#policies-bypass)
|
|
* authorize_if
|
|
* forbid_if
|
|
* authorize_unless
|
|
* forbid_unless
|
|
|
|
|
|
### Examples
|
|
```
|
|
policies do
|
|
# Anything you can use in a condition, you can use in a check, and vice-versa
|
|
# This policy applies if the actor is a super_user
|
|
# Additionally, this policy is declared as a `bypass`. That means that this check is allowed to fail without
|
|
# failing the whole request, and that if this check *passes*, the entire request passes.
|
|
bypass actor_attribute_equals(:super_user, true) do
|
|
authorize_if always()
|
|
end
|
|
|
|
# This will likely be a common occurrence. Specifically, policies that apply to all read actions
|
|
policy action_type(:read) do
|
|
# unless the actor is an active user, forbid their request
|
|
forbid_unless actor_attribute_equals(:active, true)
|
|
# if the record is marked as public, authorize the request
|
|
authorize_if attribute(:public, true)
|
|
# if the actor is related to the data via that data's `owner` relationship, authorize the request
|
|
authorize_if relates_to_actor_via(:owner)
|
|
end
|
|
end
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`default_access_type`](#policies-default_access_type){: #policies-default_access_type } | `:strict \| :filter \| :runtime` | `:filter` | The default access type of policies for this resource. |
|
|
|
|
|
|
|
|
## policies.policy
|
|
```elixir
|
|
policy condition \\ nil
|
|
```
|
|
|
|
|
|
A policy has a name, a condition, and a list of checks.
|
|
|
|
Checks apply logically in the order they are specified, from top to bottom.
|
|
If no check explicitly authorizes the request, then the request is forbidden.
|
|
This means that, if you want to "blacklist" instead of "whitelist", you likely
|
|
want to add an `authorize_if always()` at the bottom of your policy, like so:
|
|
|
|
```elixir
|
|
policy action_type(:read) do
|
|
forbid_if not_logged_in()
|
|
forbid_if user_is_denylisted()
|
|
forbid_if user_is_in_denylisted_group()
|
|
|
|
authorize_if always()
|
|
end
|
|
```
|
|
|
|
If the policy should always run, use the `always()` check, like so:
|
|
|
|
```elixir
|
|
policy always() do
|
|
...
|
|
end
|
|
```
|
|
|
|
See the [policies guide](/documentation/topics/security/policies.md) for more.
|
|
|
|
|
|
### Nested DSLs
|
|
* [authorize_if](#policies-policy-authorize_if)
|
|
* [forbid_if](#policies-policy-forbid_if)
|
|
* [authorize_unless](#policies-policy-authorize_unless)
|
|
* [forbid_unless](#policies-policy-forbid_unless)
|
|
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`condition`](#policies-policy-condition){: #policies-policy-condition } | `any` | | A check or list of checks that must be true in order for this policy to apply. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`description`](#policies-policy-description){: #policies-policy-description } | `String.t` | | A description for the policy, used when explaining authorization results |
|
|
| [`access_type`](#policies-policy-access_type){: #policies-policy-access_type } | `:strict \| :filter \| :runtime` | | Determines how the policy is applied. See the guide for more. |
|
|
|
|
|
|
## policies.policy.authorize_if
|
|
```elixir
|
|
authorize_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_if logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_if actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-policy-authorize_if-check){: #policies-policy-authorize_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-policy-authorize_if-name){: #policies-policy-authorize_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## policies.policy.forbid_if
|
|
```elixir
|
|
forbid_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_if not_logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_if actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-policy-forbid_if-check){: #policies-policy-forbid_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-policy-forbid_if-name){: #policies-policy-forbid_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## policies.policy.authorize_unless
|
|
```elixir
|
|
authorize_unless check
|
|
```
|
|
|
|
|
|
If the check is false, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_unless not_logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_unless actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-policy-authorize_unless-check){: #policies-policy-authorize_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-policy-authorize_unless-name){: #policies-policy-authorize_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## policies.policy.forbid_unless
|
|
```elixir
|
|
forbid_unless check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_unless logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_unless actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-policy-forbid_unless-check){: #policies-policy-forbid_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-policy-forbid_unless-name){: #policies-policy-forbid_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Policy`
|
|
|
|
## policies.policy_group
|
|
```elixir
|
|
policy_group condition
|
|
```
|
|
|
|
|
|
Groups a set of policies together by some condition.
|
|
|
|
If the condition on the policy group does not apply, then none of the policies within it apply.
|
|
|
|
This is primarily syntactic sugar. At compile time, the conditions from the policy group are
|
|
added to each policy it contains, and the list is flattened out. This exists primarily to make it
|
|
easier to reason about and write policies.
|
|
|
|
The following are equivalent:
|
|
|
|
```elixir
|
|
policy_group condition1 do
|
|
policy condition2 do
|
|
...
|
|
end
|
|
|
|
policy condition3 do
|
|
...
|
|
end
|
|
end
|
|
```
|
|
|
|
and
|
|
|
|
```elixir
|
|
policy [condition1, condition2] do
|
|
...
|
|
end
|
|
|
|
policy [condition1, condition3] do
|
|
...
|
|
end
|
|
```
|
|
|
|
|
|
### Nested DSLs
|
|
* [policy](#policies-policy_group-policy)
|
|
* authorize_if
|
|
* forbid_if
|
|
* authorize_unless
|
|
* forbid_unless
|
|
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`condition`](#policies-policy_group-condition){: #policies-policy_group-condition } | `any` | | A check or list of checks that must be true in order for this policy to apply. |
|
|
|
|
|
|
|
|
## policies.policy_group.policy
|
|
```elixir
|
|
policy condition \\ nil
|
|
```
|
|
|
|
|
|
A policy has a name, a condition, and a list of checks.
|
|
|
|
Checks apply logically in the order they are specified, from top to bottom.
|
|
If no check explicitly authorizes the request, then the request is forbidden.
|
|
This means that, if you want to "blacklist" instead of "whitelist", you likely
|
|
want to add an `authorize_if always()` at the bottom of your policy, like so:
|
|
|
|
```elixir
|
|
policy action_type(:read) do
|
|
forbid_if not_logged_in()
|
|
forbid_if user_is_denylisted()
|
|
forbid_if user_is_in_denylisted_group()
|
|
|
|
authorize_if always()
|
|
end
|
|
```
|
|
|
|
If the policy should always run, use the `always()` check, like so:
|
|
|
|
```elixir
|
|
policy always() do
|
|
...
|
|
end
|
|
```
|
|
|
|
See the [policies guide](/documentation/topics/security/policies.md) for more.
|
|
|
|
|
|
### Nested DSLs
|
|
* [authorize_if](#policies-policy_group-policy-authorize_if)
|
|
* [forbid_if](#policies-policy_group-policy-forbid_if)
|
|
* [authorize_unless](#policies-policy_group-policy-authorize_unless)
|
|
* [forbid_unless](#policies-policy_group-policy-forbid_unless)
|
|
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`condition`](#policies-policy_group-policy-condition){: #policies-policy_group-policy-condition } | `any` | | A check or list of checks that must be true in order for this policy to apply. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`description`](#policies-policy_group-policy-description){: #policies-policy_group-policy-description } | `String.t` | | A description for the policy, used when explaining authorization results |
|
|
| [`access_type`](#policies-policy_group-policy-access_type){: #policies-policy_group-policy-access_type } | `:strict \| :filter \| :runtime` | | Determines how the policy is applied. See the guide for more. |
|
|
|
|
|
|
## policies.policy_group.policy.authorize_if
|
|
```elixir
|
|
authorize_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_if logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_if actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-policy_group-policy-authorize_if-check){: #policies-policy_group-policy-authorize_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-policy_group-policy-authorize_if-name){: #policies-policy_group-policy-authorize_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## policies.policy_group.policy.forbid_if
|
|
```elixir
|
|
forbid_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_if not_logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_if actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-policy_group-policy-forbid_if-check){: #policies-policy_group-policy-forbid_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-policy_group-policy-forbid_if-name){: #policies-policy_group-policy-forbid_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## policies.policy_group.policy.authorize_unless
|
|
```elixir
|
|
authorize_unless check
|
|
```
|
|
|
|
|
|
If the check is false, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_unless not_logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_unless actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-policy_group-policy-authorize_unless-check){: #policies-policy_group-policy-authorize_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-policy_group-policy-authorize_unless-name){: #policies-policy_group-policy-authorize_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## policies.policy_group.policy.forbid_unless
|
|
```elixir
|
|
forbid_unless check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_unless logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_unless actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-policy_group-policy-forbid_unless-check){: #policies-policy_group-policy-forbid_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-policy_group-policy-forbid_unless-name){: #policies-policy_group-policy-forbid_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Policy`
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.PolicyGroup`
|
|
|
|
## policies.bypass
|
|
```elixir
|
|
bypass condition \\ nil
|
|
```
|
|
|
|
|
|
A policy that, if passed, will skip all following policies. If failed, authorization moves on to the next policy
|
|
|
|
### Nested DSLs
|
|
* [authorize_if](#policies-bypass-authorize_if)
|
|
* [forbid_if](#policies-bypass-forbid_if)
|
|
* [authorize_unless](#policies-bypass-authorize_unless)
|
|
* [forbid_unless](#policies-bypass-forbid_unless)
|
|
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`condition`](#policies-bypass-condition){: #policies-bypass-condition } | `any` | | A check or list of checks that must be true in order for this policy to apply. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`description`](#policies-bypass-description){: #policies-bypass-description } | `String.t` | | A description for the policy, used when explaining authorization results |
|
|
| [`access_type`](#policies-bypass-access_type){: #policies-bypass-access_type } | `:strict \| :filter \| :runtime` | | Determines how the policy is applied. See the guide for more. |
|
|
|
|
|
|
## policies.bypass.authorize_if
|
|
```elixir
|
|
authorize_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_if logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_if actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-bypass-authorize_if-check){: #policies-bypass-authorize_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-bypass-authorize_if-name){: #policies-bypass-authorize_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## policies.bypass.forbid_if
|
|
```elixir
|
|
forbid_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_if not_logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_if actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-bypass-forbid_if-check){: #policies-bypass-forbid_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-bypass-forbid_if-name){: #policies-bypass-forbid_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## policies.bypass.authorize_unless
|
|
```elixir
|
|
authorize_unless check
|
|
```
|
|
|
|
|
|
If the check is false, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_unless not_logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_unless actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-bypass-authorize_unless-check){: #policies-bypass-authorize_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-bypass-authorize_unless-name){: #policies-bypass-authorize_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## policies.bypass.forbid_unless
|
|
```elixir
|
|
forbid_unless check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_unless logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_unless actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#policies-bypass-forbid_unless-check){: #policies-bypass-forbid_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#policies-bypass-forbid_unless-name){: #policies-bypass-forbid_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Policy`
|
|
|
|
|
|
|
|
|
|
## field_policies
|
|
Authorize access to specific fields via policies scoped to fields.
|
|
|
|
If *any* field policies exist then *all* fields must be authorized by a field policy.
|
|
If you want a "deny-list" style, then you can add policies for specific fields
|
|
and add a catch-all policy using the special field name `:*`. All policies that apply
|
|
to a field must be authorized.
|
|
|
|
The only exception to the above behavior is primary keys, which can always be read by everyone.
|
|
|
|
Additionally, keep in mind that adding `Ash.Policy.Authorizer` will require that all actions
|
|
pass policies. If you want to just add field policies, you will need to add a policy that allows
|
|
all access explicitly, i.e
|
|
|
|
```elixir
|
|
policies do
|
|
policy always() do
|
|
authorize_if always()
|
|
end
|
|
end
|
|
```
|
|
|
|
Using expressions: unlike in regular policies, expressions in field policies cannot refer
|
|
to related entities currently. Instead, you will need to create aggregates or expression calculations
|
|
that return the results you want to reference.
|
|
|
|
In results, forbidden fields will be replaced with a special value: `%Ash.ForbiddenField{}`.
|
|
|
|
When these fields are referred to in filters, they will be replaced with an expression that evaluates
|
|
to `nil`. To support this behavior, only expression/filter checks are allowed in field policies.
|
|
|
|
|
|
### Nested DSLs
|
|
* [field_policy_bypass](#field_policies-field_policy_bypass)
|
|
* authorize_if
|
|
* forbid_if
|
|
* authorize_unless
|
|
* forbid_unless
|
|
* [field_policy](#field_policies-field_policy)
|
|
* authorize_if
|
|
* forbid_if
|
|
* authorize_unless
|
|
* forbid_unless
|
|
|
|
|
|
### Examples
|
|
```
|
|
field_policies do
|
|
field_policy :admin_only_field do
|
|
authorize_if actor_attribute_equals(:admin, true)
|
|
end
|
|
end
|
|
|
|
```
|
|
|
|
```
|
|
# Example of denylist style
|
|
field_policies do
|
|
field_policy [:sensitive, :fields] do
|
|
authorize_if actor_attribute_equals(:admin, true)
|
|
end
|
|
|
|
field_policy :* do
|
|
authorize_if always()
|
|
end
|
|
end
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`private_fields`](#field_policies-private_fields){: #field_policies-private_fields } | `:show \| :hide \| :include` | `:show` | How private fields should be handeled by field policies in internal functions. See the [Policies guide](documentation/topics/security/policies.md#field-policies) for more. |
|
|
|
|
|
|
|
|
## field_policies.field_policy_bypass
|
|
```elixir
|
|
field_policy_bypass fields, condition \\ nil
|
|
```
|
|
|
|
|
|
A field policy that, if passed, will skip all following field policies for that field or fields. If failed, field authorization moves on to the next policy
|
|
|
|
### Nested DSLs
|
|
* [authorize_if](#field_policies-field_policy_bypass-authorize_if)
|
|
* [forbid_if](#field_policies-field_policy_bypass-forbid_if)
|
|
* [authorize_unless](#field_policies-field_policy_bypass-authorize_unless)
|
|
* [forbid_unless](#field_policies-field_policy_bypass-forbid_unless)
|
|
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`fields`](#field_policies-field_policy_bypass-fields){: #field_policies-field_policy_bypass-fields } | `atom \| list(atom)` | | The field or fields that the policy applies to. |
|
|
| [`condition`](#field_policies-field_policy_bypass-condition){: #field_policies-field_policy_bypass-condition } | `any` | | A check or list of checks that must be true in order for this field policy to apply. If not specified, it always applies. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`description`](#field_policies-field_policy_bypass-description){: #field_policies-field_policy_bypass-description } | `String.t` | | A description for the policy, used when explaining authorization results |
|
|
|
|
|
|
## field_policies.field_policy_bypass.authorize_if
|
|
```elixir
|
|
authorize_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_if logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_if actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#field_policies-field_policy_bypass-authorize_if-check){: #field_policies-field_policy_bypass-authorize_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#field_policies-field_policy_bypass-authorize_if-name){: #field_policies-field_policy_bypass-authorize_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## field_policies.field_policy_bypass.forbid_if
|
|
```elixir
|
|
forbid_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_if not_logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_if actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#field_policies-field_policy_bypass-forbid_if-check){: #field_policies-field_policy_bypass-forbid_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#field_policies-field_policy_bypass-forbid_if-name){: #field_policies-field_policy_bypass-forbid_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## field_policies.field_policy_bypass.authorize_unless
|
|
```elixir
|
|
authorize_unless check
|
|
```
|
|
|
|
|
|
If the check is false, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_unless not_logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_unless actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#field_policies-field_policy_bypass-authorize_unless-check){: #field_policies-field_policy_bypass-authorize_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#field_policies-field_policy_bypass-authorize_unless-name){: #field_policies-field_policy_bypass-authorize_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## field_policies.field_policy_bypass.forbid_unless
|
|
```elixir
|
|
forbid_unless check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_unless logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_unless actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#field_policies-field_policy_bypass-forbid_unless-check){: #field_policies-field_policy_bypass-forbid_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#field_policies-field_policy_bypass-forbid_unless-name){: #field_policies-field_policy_bypass-forbid_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.FieldPolicy`
|
|
|
|
## field_policies.field_policy
|
|
```elixir
|
|
field_policy fields, condition \\ nil
|
|
```
|
|
|
|
|
|
Field policies behave similarly to policies. See `d:Ash.Policy.Authorizer.field_policies`
|
|
for more.
|
|
|
|
|
|
### Nested DSLs
|
|
* [authorize_if](#field_policies-field_policy-authorize_if)
|
|
* [forbid_if](#field_policies-field_policy-forbid_if)
|
|
* [authorize_unless](#field_policies-field_policy-authorize_unless)
|
|
* [forbid_unless](#field_policies-field_policy-forbid_unless)
|
|
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`fields`](#field_policies-field_policy-fields){: #field_policies-field_policy-fields } | `atom \| list(atom)` | | The field or fields that the policy applies to. |
|
|
| [`condition`](#field_policies-field_policy-condition){: #field_policies-field_policy-condition } | `any` | | A check or list of checks that must be true in order for this field policy to apply. If not specified, it always applies. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`description`](#field_policies-field_policy-description){: #field_policies-field_policy-description } | `String.t` | | A description for the policy, used when explaining authorization results |
|
|
|
|
|
|
## field_policies.field_policy.authorize_if
|
|
```elixir
|
|
authorize_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_if logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_if actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#field_policies-field_policy-authorize_if-check){: #field_policies-field_policy-authorize_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#field_policies-field_policy-authorize_if-name){: #field_policies-field_policy-authorize_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## field_policies.field_policy.forbid_if
|
|
```elixir
|
|
forbid_if check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_if not_logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_if actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#field_policies-field_policy-forbid_if-check){: #field_policies-field_policy-forbid_if-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#field_policies-field_policy-forbid_if-name){: #field_policies-field_policy-forbid_if-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## field_policies.field_policy.authorize_unless
|
|
```elixir
|
|
authorize_unless check
|
|
```
|
|
|
|
|
|
If the check is false, the request is authorized, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
authorize_unless not_logged_in()
|
|
```
|
|
|
|
```
|
|
authorize_unless actor_attribute_matches_record(:group, :blacklisted_groups)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#field_policies-field_policy-authorize_unless-check){: #field_policies-field_policy-authorize_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#field_policies-field_policy-authorize_unless-name){: #field_policies-field_policy-authorize_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
## field_policies.field_policy.forbid_unless
|
|
```elixir
|
|
forbid_unless check
|
|
```
|
|
|
|
|
|
If the check is true, the request is forbidden, otherwise run remaining checks.
|
|
|
|
|
|
|
|
### Examples
|
|
```
|
|
forbid_unless logged_in()
|
|
```
|
|
|
|
```
|
|
forbid_unless actor_attribute_matches_record(:group, :group)
|
|
```
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`check`](#field_policies-field_policy-forbid_unless-check){: #field_policies-field_policy-forbid_unless-check .spark-required} | `module \| any` | | The check to run. See `Ash.Policy.Check` for more. |
|
|
### Options
|
|
|
|
| Name | Type | Default | Docs |
|
|
|------|------|---------|------|
|
|
| [`name`](#field_policies-field_policy-forbid_unless-name){: #field_policies-field_policy-forbid_unless-name } | `String.t` | | A short name or description for the check, used when explaining authorization results |
|
|
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.Check`
|
|
|
|
|
|
|
|
|
|
### Introspection
|
|
|
|
Target: `Ash.Policy.FieldPolicy`
|
|
|
|
|
|
|
|
|
|
|
|
<style type="text/css">.spark-required::after { content: "*"; color: red !important; }</style>
|