Releases: woylie/let_me
3.0.1
3.0.0
Added
c:LetMe.Policy.fetch_expression/1c:LetMe.Policy.fetch_expression!/1c:LetMe.Policy.get_expression/1
Changed
- The expressions, evaluation logic, and optimization logic introduced in
LetMe 2.0.0 were extracted into a separate library calledSpek. This version
replaces the expression structs and logic with the new library.
How to upgrade
The DSL and callback functions are unchanged compared to version 2.0.0. Only
the representation of expressions under the expression key in the
LetMe.Rule and LetMe.UnauthorizedError structs was changed to use the
Spek structs.
LetMe.AllOf->Spek.AllOfLetMe.AnyOf->Spek.AnyOfLetMe.Check->Spek.CheckLetMe.Literal->Spek.LiteralLetMe.Not->Spek.Not
The structs have mostly the same structure, except for these differences:
- All structs:
passed?->satisfied? Spek.Literal: additionalresultkeySpek.Check:name->fun- additional
modulekey, which contains the name of the check module. arg->args- Because of the way Spek maps the evaluation context to function arguments,
theargskey holds a list in the format
[{:ctx, :subject}, {:ctx, :object}, arg], whereargis the value that
was previously under theargkey.
2.0.0
What's New?
Internal Policy Rule Representation
The internal representation of the policy rules has been changed to a tree-like expression format using AllOf, AnyOf, Check, Literal, and Not structs. An expression might look like this:
%AllOf{
children: [
%Check{name: :role, arg: :admin},
%Check{name: :two_fa}
]
}Or this:
%AllOf{
children: [
%Not{expression: %Check{name: :suspended}},
%Check{name: :two_fa},
%AnyOf{
children: [
%Check{name: :user_type, arg: :admin},
%Check{name: :user_type, arg: :client}
]
}
]
}Or just:
%Literal{passed?: true}These expressions are generated from the policy rules you define with the macro DSL. At compile time, a few basic normalization steps are applied, for example to remove unnecessary nesting or to factorize common checks in AnyOf expressions.
Lazy Evaluation
All expressions are now evaluated lazily when an authorization check is performed.
Checks With Custom Return Values
Previously, all check functions had to return a boolean. Now, the return type is boolean | :ok | :error | {:ok, term} | {:error, term}.
Detailed Authorization Errors
By default, c:LetMe.Policy.authorize/4 still returns {:error, :unauthorized} if an authorization check fails. But there is a new error option you can pass to use LetMe to set a default value and to c:LetMe.Policy.authorize/4 and c:LetMe.Policy.authorize!/4 to override the default. The available values are:
:detailed
If you set the value to :detailed, authorize/4 returns an UnauthorizedError struct with the parts of the expression that were evaluated until a decision was made. You can find the exact return value of the check function in the result field of the Check struct. The UnauthorizedErrorexception raised by authorize!/4 also contains the expression with this option value.
defmodule MyApp.Policy
use LetMe.Policy, error: :detailed
# ...
end
iex> MyApp.Policy.authorize(:article_update, user_2, article)
{
:error,
%LetMe.UnauthorizedError{
expression: %LetMe.AllOf{
children: [
%LetMe.Check{
name: :role,
arg: :admin,
result: true,
passed?: true
},
%LetMe.Check{
name: :aal2,
result: {:error, :aal1},
passed?: false
}
],
passed?: false
},
message: "unauthorized"
}
}:simple
If you set the value to :simple, authorize/4 returns an UnauthorizedError struct without the expression. Likewise, authorize!/4 raises an UnauthorizedError exception without it.
defmodule MyApp.Policy
use LetMe.Policy, error: :simple
# ...
end
iex> MyApp.Policy.authorize(:article_update, user_2, article)
{:error, %LetMe.UnauthorizedError{
message: "unauthorized",
expression: nil
}}any
Any other value will be used directly in the error tuple:
defmodule MyApp.Policy
use LetMe.Policy, error: :forbidden
# ...
end
iex> MyApp.Policy.authorize(:article_update, user_2, article)
{:error, :forbidden}Upgrade from v1
The policy DSL and authorization API remain unchanged. The only breaking changes are:
- The removal of the
allowanddenyfields of theLetMe.Rulestruct in favor of the newexpressionfield. - The removal of the
error_reasonanderror_messageoptions fromuse LetMe.Policyin favor of the newerroroption. - The removal of the
allowanddenyfilter options onLetMe.filter_rules/2and
c:LetMe.Policy.list_rules/1in favor of a singlecheckoption.
For more details, refer to the changelog.
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
Added
- Added an optional
optsargument to the authorize functions, so that additional options can be passed to pre-hooks. - Updated
LetMe.filter_rules/2to allow filtering by meta data.
Changed
- Pre-hook options are now expected to be passed as a keyword list.
Fixed
- Fix deprecation warning about
Logger.warn/2in Elixir 1.15.