Packages

ash

2.9.7
3.29.3 3.29.2 3.29.1 3.29.0 3.28.0 3.27.8 3.27.7 3.27.6 3.27.5 3.27.4 3.27.3 3.27.2 3.27.1 3.27.0 3.26.0 3.25.2 3.25.1 3.25.0 retired 3.24.7 3.24.6 3.24.5 3.24.4 3.24.3 3.24.2 3.24.1 3.24.0 3.23.1 3.23.0 3.22.2 3.22.1 3.22.0 3.21.3 3.21.2 3.21.1 3.21.0 3.20.0 3.19.3 3.19.2 3.19.1 3.19.0 3.18.0 3.17.1 3.17.0 3.16.0 3.15.0 3.14.1 3.14.0 retired 3.13.2 3.13.1 3.13.0 3.12.0 3.11.3 3.11.2 3.11.1 3.11.0 3.10.1 3.10.0 3.9.0 3.8.0 3.7.6 3.7.5 3.7.4 3.7.3 3.7.2 3.7.1 3.7.0 retired 3.6.3 retired 3.6.2 3.6.1 3.6.0 3.5.43 3.5.42 3.5.41 3.5.40 3.5.39 3.5.38 3.5.37 3.5.36 3.5.35 3.5.34 3.5.33 3.5.32 3.5.31 3.5.30 3.5.29 3.5.28 3.5.27 3.5.26 3.5.25 3.5.24 3.5.23 3.5.22 3.5.21 3.5.20 3.5.19 3.5.18 3.5.17 3.5.16 3.5.15 3.5.14 3.5.13 3.5.12 3.5.11 3.5.10 3.5.9 3.5.8 3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.4.74 retired 3.4.73 3.4.72 3.4.71 3.4.70 3.4.69 3.4.68 3.4.67 3.4.66 3.4.65 3.4.64 3.4.63 3.4.62 3.4.61 3.4.60 3.4.59 3.4.58 3.4.57 3.4.56 3.4.55 3.4.54 3.4.53 3.4.52 3.4.51 3.4.50 3.4.49 3.4.48 3.4.47 3.4.46 3.4.45 3.4.44 3.4.43 3.4.42 3.4.41 3.4.40 3.4.39 3.4.38 3.4.37 3.4.36 3.4.35 3.4.34 3.4.33 3.4.32 3.4.31 3.4.30 3.4.29 3.4.28 3.4.27 3.4.26 3.4.25 3.4.24 3.4.23 3.4.22 3.4.21 3.4.20 3.4.19 3.4.18 3.4.17 3.4.16 3.4.15 3.4.14 3.4.13 3.4.12 3.4.11 3.4.10 3.4.9 3.4.8 3.4.7 3.4.6 3.4.5 3.4.4 3.4.3 3.4.2 3.4.1 3.4.0 3.3.3 3.3.2 3.3.1 3.3.0 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 3.2.0 3.1.8 3.1.7 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.16 3.0.15 3.0.14 3.0.13 3.0.12 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.4 3.0.3 3.0.2 3.0.1 3.0.0 3.0.0-rc.46 3.0.0-rc.45 3.0.0-rc.44 3.0.0-rc.43 3.0.0-rc.42 3.0.0-rc.41 3.0.0-rc.40 3.0.0-rc.39 3.0.0-rc.38 3.0.0-rc.37 3.0.0-rc.36 3.0.0-rc.35 3.0.0-rc.34 3.0.0-rc.33 3.0.0-rc.32 3.0.0-rc.31 3.0.0-rc.29 3.0.0-rc.28 3.0.0-rc.27 3.0.0-rc.26 3.0.0-rc.25 3.0.0-rc.24 3.0.0-rc.23 3.0.0-rc.22 3.0.0-rc.21 3.0.0-rc.20 3.0.0-rc.19 3.0.0-rc.18 3.0.0-rc.17 3.0.0-rc.16 3.0.0-rc.15 3.0.0-rc.14 3.0.0-rc.13 3.0.0-rc.12 3.0.0-rc.11 3.0.0-rc.10 3.0.0-rc.9 3.0.0-rc.8 3.0.0-rc.7 3.0.0-rc.6 3.0.0-rc.5 3.0.0-rc.4 3.0.0-rc.3 3.0.0-rc.1 3.0.0-rc.0 2.21.15 2.21.14 2.21.13 2.21.12 2.21.11 2.21.10 2.21.9 2.21.8 2.21.7 2.21.6 2.21.5 2.21.4 2.21.3 2.21.2 2.21.1 2.21.0 2.20.3 2.20.2 2.20.1 2.20.0 2.19.14 2.19.13 2.19.12 2.19.11 2.19.10 2.19.9 2.19.8 2.19.7 2.19.6 2.19.5 2.19.4 2.19.3 retired 2.19.2 retired 2.19.1 retired 2.19.0 retired 2.18.2 2.18.1 2.18.0 2.17.24 2.17.23 2.17.22 2.17.21 2.17.20 2.17.19 2.17.18 2.17.17 2.17.16 2.17.15 2.17.14 2.17.13 2.17.12 2.17.11 2.17.10 2.17.9 2.17.8 2.17.7 2.17.6 2.17.5 2.17.4 2.17.3 2.17.2 2.17.1 2.17.0 2.16.1 2.16.0 2.15.20 2.15.19 2.15.18 2.15.17 2.15.16 2.15.15 2.15.14 2.15.13 2.15.12 2.15.11 2.15.10 2.15.9 2.15.8 2.15.7 2.15.6 2.15.5 2.15.4 2.15.2 2.15.1 2.15.0 2.14.21 2.14.20 2.14.19 2.14.18 2.14.17 2.14.16 2.14.15 2.14.14 2.14.13 2.14.12 2.14.11 2.14.10 2.14.9 2.14.8 2.14.7 2.14.6 2.14.5 2.14.4 2.14.3 2.14.2 2.14.1 2.14.0 2.13.4 retired 2.13.3 2.13.2 2.13.1 2.13.0 2.12.1 2.12.0 2.11.11 2.11.10 2.11.9 2.11.8 2.11.7 2.11.6 2.11.5 2.11.4 2.11.3 2.11.2 2.11.1 2.11.0 2.11.0-rc.3 2.11.0-rc.2 2.11.0-rc.1 2.11.0-rc.0 2.10.2 2.10.1 2.10.0 2.9.29 2.9.28 2.9.27 2.9.26 2.9.25 2.9.24 2.9.23 2.9.22 2.9.21 2.9.20 2.9.19 2.9.18 2.9.17 2.9.16 2.9.15 2.9.14 2.9.13 2.9.12 2.9.11 2.9.10 2.9.9 2.9.8 2.9.7 2.9.6 2.9.5 2.9.4 2.9.3 2.9.2 2.9.1 2.9.0 2.8.1 2.8.0 2.7.1 2.7.0 2.6.31 2.6.30 2.6.29 2.6.28 2.6.27 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.6.2 2.6.1 2.6.0 2.5.16 2.5.15 2.5.14 2.5.13 2.5.12 2.5.11 2.5.10 2.5.9 2.5.8 2.5.7 2.5.6 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5.0 2.5.0-rc.6 2.5.0-rc.5 2.5.0-rc.4 2.5.0-rc.3 2.5.0-rc.2 2.5.0-rc.1 2.5.0-rc.0 2.4.30 2.4.29 2.4.28 2.4.27 2.4.26 2.4.25 2.4.24 2.4.23 2.4.22 2.4.21 2.4.20 2.4.19 2.4.18 2.4.17 2.4.16 2.4.15 2.4.14 2.4.13 2.4.12 2.4.11 2.4.10 2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 2.3.0 2.2.0 2.1.0 2.0.0 2.0.0-rc.15 2.0.0-rc.14 2.0.0-rc.13 2.0.0-rc.12 2.0.0-rc.11 2.0.0-rc.10 2.0.0-rc.9 2.0.0-rc.8 2.0.0-rc.7 2.0.0-rc.6 2.0.0-rc.5 2.0.0-rc.4 2.0.0-rc.3 2.0.0-rc.2 2.0.0-rc.1 2.0.0-rc.0 2.0.0-pre.8 2.0.0-pre.7 2.0.0-pre.6 2.0.0-pre.5 2.0.0-pre.4 2.0.0-pre.3 2.0.0-pre.2 2.0.0-pre.1 2.0.0-pre.0 1.53.3 1.53.2 1.53.0 1.52.0-rc.22 1.52.0-rc.21 1.52.0-rc.20 1.52.0-rc.19 1.52.0-rc.18 1.52.0-rc.17 1.52.0-rc.16 1.52.0-rc.15 1.52.0-rc.14 1.52.0-rc.13 1.52.0-rc.12 1.52.0-rc.11 1.52.0-rc.10 1.52.0-rc.9 1.52.0-rc.8 1.52.0-rc.7 1.52.0-rc.6 1.52.0-rc.5 1.52.0-rc.4 1.52.0-rc.3 1.52.0-rc.2 1.52.0-rc.1 1.52.0-rc.0 1.51.2 1.51.1 retired 1.51.0 1.50.21 1.50.20 1.50.19 1.50.18 1.50.17 1.50.16 1.50.15 1.50.14 1.50.13 1.50.12 1.50.11 1.50.10 1.50.9 1.50.8 1.50.7 1.50.6 1.50.5 1.50.4 1.50.3 1.50.2 1.50.1 1.50.0 1.49.0 1.48.0-rc.30 1.48.0-rc.29 1.48.0-rc.28 1.48.0-rc.27 1.48.0-rc.26 1.48.0-rc.25 1.48.0-rc.24 1.48.0-rc.23 1.48.0-rc.22 1.48.0-rc.21 1.48.0-rc.20 1.48.0-rc.19 1.48.0-rc.18 1.48.0-rc.17 1.48.0-rc.16 1.48.0-rc.15 1.48.0-rc.14 1.48.0-rc.13 1.48.0-rc.12 1.48.0-rc.11 1.48.0-rc.10 1.48.0-rc.9 1.48.0-rc.8 1.48.0-rc.7 1.48.0-rc.6 1.48.0-rc.5 1.48.0-rc.4 1.48.0-rc.3 1.48.0-rc.2 1.48.0-rc.1 1.48.0-rc.0 1.47.12 1.47.11 1.47.10 1.47.9 1.47.8 1.47.7 1.47.6 1.47.5 1.47.4 1.47.3 1.47.2 1.47.1 1.47.0 1.46.13 1.46.12 1.46.11 1.46.10 1.46.9 1.46.8 1.46.7 1.46.6 1.46.5 1.46.4 1.46.3 1.46.2 1.46.1 1.46.0 1.45.0-rc9 1.45.0-rc8 1.45.0-rc7 1.45.0-rc6 1.45.0-rc5 1.45.0-rc4 1.45.0-rc3 1.45.0-rc20 1.45.0-rc2 1.45.0-rc19 1.45.0-rc18 1.45.0-rc17 1.45.0-rc16 1.45.0-rc15 1.45.0-rc14 1.45.0-rc13 1.45.0-rc12 1.45.0-rc11 1.45.0-rc10 1.45.0-rc1 1.45.0-rc0 1.44.13 1.44.12 1.44.11 1.44.10 1.44.9 1.44.8 1.44.7 1.44.6 1.44.5 1.44.4 1.44.3 1.44.2 1.44.1 1.44.0 1.43.12 1.43.11 1.43.10 1.43.9 1.43.8 1.43.7 1.43.6 1.43.5 1.43.4 1.43.3 1.43.2 1.43.1 1.43.0 1.42.0 1.41.12 1.41.11 1.41.10 1.41.9 1.41.8 1.41.7 1.41.6 1.41.5 1.41.4 1.41.3 1.41.2 1.41.1 1.41.0 1.40.0 1.39.7 1.39.6 1.39.5 1.39.4 1.39.3 1.39.2 1.39.1 1.39.0 1.38.0 1.37.2 1.37.1 1.37.0 1.36.22 1.36.21 1.36.19 1.36.18 1.36.17 1.36.16 1.36.15 1.36.14 1.36.13 1.36.12 1.36.11 1.36.10 1.36.9 1.36.8 1.36.7 1.36.6 1.36.5 1.36.4 1.36.3 1.36.2 1.36.0 1.35.1 1.35.0 1.34.9 1.34.8 1.34.7 1.34.6 1.34.5 1.34.4 1.34.3 1.34.2 1.34.1 1.34.0 1.33.0 1.32.2 1.32.1 1.32.0 1.31.1 1.31.0 1.30.2 1.30.1 1.29.0-rc1 1.29.0-rc0 1.28.1 1.28.0 1.27.1 1.27.0 1.26.13 1.26.12 1.26.11 1.26.10 1.26.9 1.26.8 1.26.7 1.26.6 1.26.5 1.26.4 1.26.2 1.26.1 1.26.0 1.25.8 1.25.7 1.25.6 1.25.5 1.25.4 1.25.3 1.25.2 1.25.1 1.25.0 1.24.2 1.24.1 1.24.0 1.23.3 1.23.2 1.23.1 1.23.0 1.22.1 1.22.0 1.20.1 1.20.0 1.19.1 1.19.0 1.18.1 1.18.0 1.17.1 1.17.0 1.16.2 1.15.1 1.15.0 1.14.0 1.13.4 1.13.3 1.13.2 1.13.1 1.13.0 1.12.0 1.11.1 1.11.0 1.10.0 1.9.0 1.8.0 1.7.0 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.1 1.5.0 1.4.1 1.4.0 1.3.1 1.3.0 1.2.1 1.2.0 1.1.3 1.1.2 1.1.0 1.0.3 1.0.2 1.0.1 1.0.0 0.13.1 0.13.0 0.12.0 0.10.0 0.9.1 0.9.0 0.8.0 0.7.0 0.6.5 0.6.4 0.6.3 0.6.2 0.6.1 0.6.0 0.5.2 0.5.1 0.5.0 0.4.0 0.3.0 0.2.0 0.1.9 0.1.8 0.1.3 0.1.1 0.1.0

A declarative, extensible framework for building Elixir applications.

Security advisory: This version has known vulnerabilities. View advisories

Current section

Files

Jump to
ash lib ash policy policy.ex
Raw

lib/ash/policy/policy.ex

defmodule Ash.Policy.Policy do
@moduledoc false
# For now we just write to `checks` and move them to `policies`
# on build, when we support nested policies we can change that.
defstruct [
:condition,
:policies,
:bypass?,
:checks,
:description,
:access_type
]
@type t :: %__MODULE__{}
@static_checks [
{Ash.Policy.Check.Static, [result: true]},
{Ash.Policy.Check.Static, [result: false]},
true,
false
]
def solve(authorizer) do
authorizer.policies
|> build_requirements_expression(authorizer)
|> case do
{true, authorizer} ->
{:ok, true, authorizer}
{false, authorizer} ->
{:ok, false, authorizer}
{expression, authorizer} ->
Ash.Policy.SatSolver.solve(expression, fn scenario, bindings ->
scenario
|> Ash.SatSolver.solutions_to_predicate_values(bindings)
|> Map.drop(@static_checks)
end)
|> case do
{:ok, scenarios} ->
{:ok, scenarios, authorizer}
{:error, error} ->
{:error, authorizer, error}
end
end
end
defp build_requirements_expression(policies, authorizer) do
{at_least_one_policy_expression, authorizer} =
at_least_one_policy_expression(policies, authorizer)
if at_least_one_policy_expression == false do
{false, authorizer}
else
{policy_expression, authorizer} =
if at_least_one_policy_expression == true do
compile_policy_expression(policies, authorizer)
else
{policy_expression, authorizer} = compile_policy_expression(policies, authorizer)
case {:and, at_least_one_policy_expression, policy_expression} do
{:and, false, _} ->
{false, authorizer}
{:and, _, false} ->
{false, authorizer}
{:and, true, true} ->
{true, authorizer}
{:and, left, true} ->
{left, authorizer}
{:and, true, right} ->
{right, authorizer}
other ->
{other, authorizer}
end
end
facts_expression =
authorizer.facts
|> Map.drop([true, false])
|> Ash.Policy.SatSolver.facts_to_statement()
if facts_expression do
{{:and, facts_expression, policy_expression}, authorizer}
else
{policy_expression, authorizer}
end
end
end
def at_least_one_policy_expression(policies, authorizer) do
policies
|> Enum.reduce({[], authorizer}, fn
policy, {condition_exprs, authorizer} when is_list(condition_exprs) ->
case condition_expression(policy.condition, authorizer) do
{nil, authorizer} ->
{condition_exprs, authorizer}
{true, authorizer} ->
{true, authorizer}
{condition_expr, authorizer} ->
{[condition_expr | condition_exprs], authorizer}
end
_, {true, authorizer} ->
{true, authorizer}
end)
|> then(fn
{true, authorizer} ->
{true, authorizer}
{condition_exprs, authorizer} ->
{condition_exprs
|> Enum.reduce(false, fn
_, true ->
true
true, _ ->
true
false, acc ->
acc
condition, acc ->
{:or, condition, acc}
end), authorizer}
end)
end
def fetch_or_strict_check_fact(authorizer, %{check_module: mod, check_opts: opts}) do
fetch_or_strict_check_fact(authorizer, {mod, opts})
end
def fetch_or_strict_check_fact(authorizer, {check_module, opts}) do
Enum.find_value(authorizer.facts, fn
{{fact_mod, fact_opts}, result} ->
if check_module == fact_mod &&
Keyword.delete(fact_opts, :access_type) ==
Keyword.delete(opts, :access_type) do
{:ok, result}
end
_ ->
nil
end)
|> case do
nil ->
case check_module.strict_check(authorizer.actor, authorizer, opts) do
{:ok, value} when is_boolean(value) or value == :unknown ->
authorizer = %{
authorizer
| facts: Map.put(authorizer.facts, {check_module, opts}, value)
}
if value == :unknown do
{:error, authorizer}
else
{:ok, value, authorizer}
end
{:error, error} ->
raise "Error produced by #{check_module}'s strict_checking logic: #{inspect(error)}"
end
{:ok, :unknown} ->
{:error, authorizer}
{:ok, value} ->
{:ok, value, authorizer}
end
end
def fetch_fact(facts, %{check_module: mod, check_opts: opts}) do
fetch_fact(facts, {mod, opts})
end
def fetch_fact(facts, {mod, opts}) do
# TODO: this is slow, and we should figure out a better way to access facts indiscriminate of access type,
# which my necessity must be stored with the fact (as facts create scenarios)
# Eventually we may just want to track two separate maps of facts, one with access type and one without
Enum.find_value(facts, fn
{{fact_mod, fact_opts}, result} ->
if mod == fact_mod &&
Keyword.delete(fact_opts, :access_type) ==
Keyword.delete(opts, :access_type) do
{:ok, result}
end
_ ->
nil
end)
|> case do
nil ->
:error
:unknown ->
:error
value ->
value
end
end
defp condition_expression(condition, authorizer) do
condition
|> List.wrap()
|> Enum.reduce({nil, authorizer}, fn
condition, {nil, authorizer} ->
case fetch_or_strict_check_fact(authorizer, condition) do
{:ok, true, authorizer} ->
{true, authorizer}
{:ok, false, authorizer} ->
{false, authorizer}
_ ->
{condition, authorizer}
end
_condition, {false, authorizer} ->
{false, authorizer}
condition, {expression, authorizer} ->
case fetch_or_strict_check_fact(authorizer, condition) do
{:ok, true, authorizer} ->
{expression, authorizer}
{:ok, false, authorizer} ->
{false, authorizer}
_ ->
{{:and, condition, expression}, authorizer}
end
end)
end
defp compile_policy_expression([], authorizer) do
{false, authorizer}
end
defp compile_policy_expression(
[%__MODULE__{condition: condition, policies: policies}],
authorizer
) do
{condition_expression, authorizer} = condition_expression(condition, authorizer)
case condition_expression do
true ->
compile_policy_expression(policies, authorizer)
false ->
{true, authorizer}
nil ->
compile_policy_expression(policies, authorizer)
condition_expression ->
case compile_policy_expression(policies, authorizer) do
{true, authorizer} ->
{condition_expression, authorizer}
{false, authorizer} ->
{{:not, condition_expression}, authorizer}
{compiled_policies, authorizer} ->
{{:and, condition_expression, compiled_policies}, authorizer}
end
end
end
defp compile_policy_expression(
[
%__MODULE__{condition: condition, policies: policies, bypass?: bypass?} | rest
],
authorizer
) do
{condition_expression, authorizer} = condition_expression(condition, authorizer)
case condition_expression do
true ->
if bypass? do
case compile_policy_expression(policies, authorizer) do
{true, authorizer} ->
{true, authorizer}
{false, authorizer} ->
{at_least_one_policy_expression, authorizer} =
at_least_one_policy_expression(Enum.take_while(rest, &(!&1.bypass?)), authorizer)
{rest, authorizer} = compile_policy_expression(rest, authorizer)
{{:and, rest, at_least_one_policy_expression}, authorizer}
{policy_expression, authorizer} ->
{at_least_one_policy_expression, authorizer} =
at_least_one_policy_expression(Enum.take_while(rest, &(!&1.bypass?)), authorizer)
{rest, authorizer} = compile_policy_expression(rest, authorizer)
{{:or, policy_expression, {:and, rest, at_least_one_policy_expression}}, authorizer}
end
else
case compile_policy_expression(policies, authorizer) do
{false, authorizer} ->
{false, authorizer}
{true, authorizer} ->
compile_policy_expression(rest, authorizer)
{policy_expression, authorizer} ->
case compile_policy_expression(rest, authorizer) do
{false, authorizer} ->
{false, authorizer}
{true, authorizer} ->
{policy_expression, authorizer}
{rest, authorizer} ->
{{:and, policy_expression, rest}, authorizer}
end
end
end
false ->
compile_policy_expression(rest, authorizer)
nil ->
if bypass? do
case compile_policy_expression(policies, authorizer) do
{true, authorizer} ->
{true, authorizer}
{false, authorizer} ->
{at_least_one_policy_expression, authorizer} =
at_least_one_policy_expression(Enum.take_while(rest, &(!&1.bypass?)), authorizer)
rest = compile_policy_expression(rest, authorizer)
{:and, rest, at_least_one_policy_expression}
{policy_expression, authorizer} ->
{at_least_one_policy_expression, authorizer} =
at_least_one_policy_expression(Enum.take_while(rest, &(!&1.bypass?)), authorizer)
case compile_policy_expression(rest, authorizer) do
{false, authorizer} ->
{policy_expression, authorizer}
{true, authorizer} ->
{{:or, policy_expression, at_least_one_policy_expression}, authorizer}
{rest, authorizer} ->
{{:or, policy_expression, {:and, rest, at_least_one_policy_expression}},
authorizer}
end
end
else
case compile_policy_expression(policies, authorizer) do
{true, authorizer} ->
compile_policy_expression(rest, authorizer)
{false, authorizer} ->
{false, authorizer}
{policy_expression, authorizer} ->
case compile_policy_expression(rest, authorizer) do
{true, authorizer} ->
{policy_expression, authorizer}
{false, authorizer} ->
{false, authorizer}
{rest, authorizer} ->
{{:and, policy_expression, rest}, authorizer}
end
end
end
condition_expression ->
if bypass? do
{at_least_one_policy_expression, authorizer} =
at_least_one_policy_expression(Enum.take_while(rest, &(!&1.bypass?)), authorizer)
{condition_and_policy_expression, authorizer} =
case compile_policy_expression(policies, authorizer) do
{true, authorizer} ->
{condition_expression, authorizer}
{false, authorizer} ->
{false, authorizer}
{other, authorizer} ->
{{:and, condition_expression, other}, authorizer}
end
case condition_and_policy_expression do
true ->
{true, authorizer}
false ->
case compile_policy_expression(rest, authorizer) do
{true, authorizer} ->
{at_least_one_policy_expression, authorizer}
{false, authorizer} ->
{false, authorizer}
{rest, authorizer} ->
{{:and, rest, at_least_one_policy_expression}, authorizer}
end
condition_and_policy_expression ->
case compile_policy_expression(rest, authorizer) do
{true, authorizer} ->
{at_least_one_policy_expression, authorizer}
{false, authorizer} ->
{condition_and_policy_expression, authorizer}
{rest, authorizer} ->
{{:or, condition_and_policy_expression,
{:and, rest, at_least_one_policy_expression}}, authorizer}
end
end
else
{condition_and_policy_expression, authorizer} =
case compile_policy_expression(policies, authorizer) do
{true, authorizer} ->
{condition, authorizer}
{false, authorizer} ->
{false, authorizer}
{policy_expression, authorizer} ->
{{:and, condition, policy_expression}, authorizer}
end
case condition_and_policy_expression do
false ->
compile_policy_expression(rest, authorizer)
true ->
{true, authorizer}
condition_and_policy_expression ->
case compile_policy_expression(rest, authorizer) do
{true, authorizer} ->
{true, authorizer}
{false, authorizer} ->
{condition_and_policy_expression, authorizer}
{rest, authorizer} ->
{{:or, condition_and_policy_expression, rest}, authorizer}
end
end
end
end
end
defp compile_policy_expression(
[%{type: :authorize_if} = clause],
authorizer
) do
case fetch_or_strict_check_fact(authorizer, clause) do
{:ok, true, authorizer} ->
{true, authorizer}
{:ok, false, authorizer} ->
{false, authorizer}
{:error, authorizer} ->
{{clause.check_module, clause.check_opts}, authorizer}
end
end
defp compile_policy_expression(
[%{type: :authorize_if} = clause | rest],
authorizer
) do
case fetch_or_strict_check_fact(authorizer, clause) do
{:ok, true, authorizer} ->
{true, authorizer}
{:ok, false, authorizer} ->
compile_policy_expression(rest, authorizer)
{:error, authorizer} ->
{rest, authorizer} = compile_policy_expression(rest, authorizer)
{{:or, {clause.check_module, clause.check_opts}, rest}, authorizer}
end
end
defp compile_policy_expression(
[%{type: :authorize_unless} = clause],
authorizer
) do
case fetch_or_strict_check_fact(authorizer, clause) do
{:ok, true, authorizer} ->
{false, authorizer}
{:ok, false, authorizer} ->
{true, authorizer}
{:error, authorizer} ->
{{clause.check_module, clause.check_opts}, authorizer}
end
end
defp compile_policy_expression(
[%{type: :authorize_unless} = clause | rest],
authorizer
) do
case fetch_or_strict_check_fact(authorizer, clause) do
{:ok, true, authorizer} ->
compile_policy_expression(rest, authorizer)
{:ok, false, authorizer} ->
{true, authorizer}
{:error, authorizer} ->
{rest, authorizer} = compile_policy_expression(rest, authorizer)
{{:or, {:not, {clause.check_module, clause.check_opts}}, rest}, authorizer}
end
end
defp compile_policy_expression([%{type: :forbid_if}], authorizer) do
{false, authorizer}
end
defp compile_policy_expression(
[%{type: :forbid_if} = clause | rest],
authorizer
) do
case fetch_or_strict_check_fact(authorizer, clause) do
{:ok, true, authorizer} ->
{false, authorizer}
{:ok, false, authorizer} ->
compile_policy_expression(rest, authorizer)
{:error, authorizer} ->
{rest, authorizer} = compile_policy_expression(rest, authorizer)
case rest do
true ->
{{:not, {clause.check_module, clause.check_opts}}, authorizer}
false ->
{false, authorizer}
rest ->
{{:and, {:not, {clause.check_module, clause.check_opts}}, rest}, authorizer}
end
end
end
defp compile_policy_expression([%{type: :forbid_unless}], authorizer) do
{false, authorizer}
end
defp compile_policy_expression(
[%{type: :forbid_unless} = clause | rest],
authorizer
) do
case fetch_or_strict_check_fact(authorizer, clause) do
{:ok, true, authorizer} ->
compile_policy_expression(rest, authorizer)
{:ok, false, authorizer} ->
{false, authorizer}
{:error, authorizer} ->
{rest, authorizer} = compile_policy_expression(rest, authorizer)
case rest do
false ->
{false, authorizer}
true ->
{{clause.check_module, clause.check_opts}, authorizer}
rest ->
{{:and, {clause.check_module, clause.check_opts}, rest}, authorizer}
end
end
end
end