Skip to content

Releases: woylie/let_me

3.0.1

05 Jun 09:46
Immutable release. Only release title and notes can be modified.
b86415b

Choose a tag to compare

Changed

  • Require spek ~> 0.3.0.

3.0.0

27 May 05:31
Immutable release. Only release title and notes can be modified.
d142e45

Choose a tag to compare

Added

  • c:LetMe.Policy.fetch_expression/1
  • c:LetMe.Policy.fetch_expression!/1
  • c: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 called Spek. 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.AllOf
  • LetMe.AnyOf -> Spek.AnyOf
  • LetMe.Check -> Spek.Check
  • LetMe.Literal -> Spek.Literal
  • LetMe.Not -> Spek.Not

The structs have mostly the same structure, except for these differences:

  • All structs: passed? -> satisfied?
  • Spek.Literal: additional result key
  • Spek.Check:
    • name -> fun
    • additional module key, which contains the name of the check module.
    • arg -> args
    • Because of the way Spek maps the evaluation context to function arguments,
      the args key holds a list in the format
      [{:ctx, :subject}, {:ctx, :object}, arg], where arg is the value that
      was previously under the arg key.

2.0.0

31 Mar 10:15
Immutable release. Only release title and notes can be modified.
594e644

Choose a tag to compare

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 allow and deny fields of the LetMe.Rule struct in favor of the new expression field.
  • The removal of the error_reason and error_message options from use LetMe.Policy in favor of the new error option.
  • The removal of the allow and deny filter options on LetMe.filter_rules/2 and
    c:LetMe.Policy.list_rules/1 in favor of a single check option.

For more details, refer to the changelog.

1.2.5

26 Mar 07:51
94ab1b6

Choose a tag to compare

Changed

  • Improve documentation.

1.2.4

22 Apr 22:28
f5b8ac6

Choose a tag to compare

Fixed

  • Nested lists within structs resulted in a CaseClauseError during redaction.

1.2.3

11 Nov 05:40
a94332e

Choose a tag to compare

Changed

  • Updated documentation.

1.2.2

28 Jun 08:50
46f0f4c

Choose a tag to compare

Changed

  • You can now override the exception message used by
    c:LetMe.Policy.authorize!/4 (e.g.
    use LetMe.Policy, error_message: "Not today, chap.").

1.2.1

27 Jun 16:23
ccfa210

Choose a tag to compare

Changed

  • Define action type when you use LetMe.Policy.
  • Add type specifications for generated authorize functions.

1.2.0

19 Jun 14:03
946a9df

Choose a tag to compare

Added

  • Added an optional opts argument to the authorize functions, so that additional options can be passed to pre-hooks.
  • Updated LetMe.filter_rules/2 to 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/2 in Elixir 1.15.

1.1.0

07 May 21:29
0693a08

Choose a tag to compare

Added

  • Added a metadata macro to add metadata to actions. The metadata can be read from the LetMe.Rule struct.