defmodule ABAC.PDP do
require ABAC
require KVS
# PDP
def decision(req0) do
{req, policy} = ABAC.PIP.request(req0)
:lists.any(&policy(req, &1), :lists.flatten(:lists.map(&:kvs.index_match(&1, :object, KVS.kvs(mod: :kvs_mnesia)), policy)))
end
def deny(req0) do
{req, policy} = ABAC.PIP.request(req0)
:lists.any(&!policy(req, &1), :lists.flatten(:lists.map(&:kvs.index_match(&1, :object, KVS.kvs(mod: :kvs_mnesia)), policy)))
end
def get(req0) do
{ABAC.request() = req, policy} = ABAC.PIP.request(req0)
:lists.flatten(:lists.map(fn x ->
:lists.filtermap(fn ABAC.rule(values: []) -> false; ABAC.rule(values: v, object: o) -> {true, :kvs.field(o, v)} end, policy(req, x))
end, :lists.flatten(:lists.map(&:kvs.index_match(&1, :object, KVS.kvs(mod: :kvs_mnesia)), policy))))
end
def parse(r), do: ABAC.PIP.parse(r)
def policy(ABAC.request(type: t) = req, ABAC.policy(rules: r, combining: c)) when t in [:decision, :deny], do:
:erlang.apply(:lists, c, [&rule(req, :erlang.element(2, :kvs.get(:rule, ABAC.rule_ref(&1, :id), KVS.kvs(mod: :kvs_mnesia)))), r])
def policy(ABAC.request(type: :get) = req, ABAC.policy(rules: r, combining: :all)), do:
:erlang.element(2, :lists.foldr(fn _, {false, _} = x -> x
ABAC.rule_ref(id: i), {true, acc} ->
rule = :erlang.element(2, :kvs.get(:rule, i, KVS.kvs(mod: :kvs_mnesia)))
if rule(req, rule), do: {true, [rule | acc]}, else: {false, []}
end, {true, []}, r))
def policy(ABAC.request(type: :get) = req, ABAC.policy(rules: r)), do:
:lists.foldr(fn ABAC.rule_ref(id: i), acc ->
x = :erlang.element(2, :kvs.get(:rule, i, KVS.kvs(mod: :kvs_mnesia)))
case rule(req, x) do true -> [x | acc]; _ -> acc end
end, [], r)
def policy(ABAC.request(type: :decision), _), do: false
def policy(ABAC.request(type: :deny), _), do: true
def policy(ABAC.request(type: :get), _), do: []
def rule(
ABAC.request(endpoint: e, resources: resources) = req,
ABAC.rule(api_endpoint: e, type: t, object_condition: [], object: o, subject_condition: c, resource_match: rm) = r
), do:
(x = :lists.filter(fn ^o -> true; _ -> false end, resources);
result(t, x != [] and :erlang.apply(:lists, rm, [fn _ -> :erlang.apply(:"Elixir.ABAC.Condition", c, [req, r]) end, x])))
def rule(
ABAC.request(endpoint: e, resources: resources) = req,
ABAC.rule(api_endpoint: e, type: t, object_condition: oc, object: o, subject_condition: c, resource_match: rm) = r
), do:
(x = :lists.filter(&(:erlang.is_record(&1, :erlang.element(1, o))), resources);
result(t, x != [] and :erlang.apply(:lists, rm, [fn x -> :erlang.apply(:"Elixir.ABAC.Condition", c, [req, r]) and :erlang.apply(:"Elixir.ABAC.Condition", oc, [x, r]) end, x])))
def rule(_, _), do: false
defp result(:permit, x), do: x
defp result(:deny, x), do: !x
end