aegis v0.2.0 Aegis.Controller View Source

Wraps controllers with Aegis authorization functionality.

Link to this section Summary

Functions

Allows another module to inherit Aegis.Controller methods

Returns the set of accessible resources, for a user, for a given action

Authorizes a resource, for a user, for a given action, and marks the connection as having had aegis authorization perfomed via the assignment of a boolean value to aegis_auth_performed on the connection

Calls controller action and performs a check on the connection in order to determine whether or not Aegis authorization has been performed

Link to this section Functions

Link to this macro __using__(opts \\ []) View Source (macro)

Allows another module to inherit Aegis.Controller methods.

Options

  • except - list of actions to exclude from aegis authorization; defaults to an empty list

Examples:

For Phoenix applications:

defmodule MyApp.PuppyController do
  use MyApp, :controller
  use Aegis.Controller

  def current_user(conn) do
    conn.assigns[:user]
  end
end

if you want to allow some actions to skip authorization, just use the except option:

defmodule MyApp.Controller do
  use MyApp, :controller
  use Aegis.Controller, except: [:custom_action]

  def current_user(conn) do
    conn.assigns[:user]
  end
end
Link to this function auth_scope(user, scope, action, policy \\ nil) View Source
auth_scope(term(), term(), atom(), module() | nil) :: list()

Returns the set of accessible resources, for a user, for a given action.

Examples

Suppose your library defines the following resource and resource policy:

defmodule Puppy do
  defstruct [id: nil, user_id: nil, hungry: false]
end

defmodule Puppy.Policy do
  @behaviour Aegis.Policy

  ...

  # users should only be able to see puppies that belong to them..
  def auth_scope(%User{id: user_id}, {:index, scope}) do
    Enum.filter(scope, &(&1.user_id == user_id))
  end

end

We can use auth_scope/4 to appropriately limit access to puppies for a given user

iex> user = %User{id: 1}
iex> puppy_1 = %Puppy{id: 1, user_id: 1}
iex> puppy_2 = %Puppy{id: 2, user_id: 2}
iex> all_puppies = [puppy_1, puppy_2]
iex> Aegis.Controller.auth_scope(user, all_puppies, :index)
[%Puppy{id: 1, user_id: 1, hungry: false}]
iex> Aegis.Controller.auth_scope(user, all_puppies, :index, Puppy.Policy)
[%Puppy{id: 1, user_id: 1, hungry: false}]

In the above example, Puppy.Policy.auth_scope is written such that it takes in and filters an enumerable. A more common use case—if you’re integrating Aegis with database-backed data—is to filter data via building a query that limits what data is returned.

For example, assuming our app uses Ecto as a database wrapper, Puppy.Policy.auth_scope/2 can be rewritten as follows, so that data is filtered as part of the querying process:

defmodule Puppy.Policy do
  @behaviour Aegis.Policy

  ...

  def auth_scope(%User{id: user_id}, {:index, scope}) do
    import Ecto.Query

    scope |> where([p], p.user_id == ^user_id)
  end

end
Link to this function authorized?(conn, user, resource, opts) View Source
authorized?(Plug.Conn.t(), term(), term(), Keyword.t()) ::
  {:ok, Plug.Conn.t()} | {:error, Plug.Conn.t()}

Authorizes a resource, for a user, for a given action, and marks the connection as having had aegis authorization perfomed via the assignment of a boolean value to aegis_auth_performed on the connection.

Returns a two-element tuple: if authorization check passes, then {:ok, conn} is returned; otherwise, {:error, conn} is returned.

Examples

defmodule Puppy do
  defstruct [id: nil, user_id: nil, hungry: false]
end

defmodule Puppy.Policy do
  @behaviour Aegis.Policy

  def authorized?(_user, {:index, _puppy}), do: true
  def authorized?(%User{id: id}, {:show, %Puppy{user_id: id}}), do: true
  def authorized?(_user, {:show, _puppy}), do: false

end

iex> conn = %Plug.Conn{}
iex> user = :user
iex> resource = Puppy
iex> action = :index
iex> {:ok, conn} = Aegis.Controller.authorized?(conn, user, resource, action: action)
iex> conn.private[:aegis_auth_performed]
true

iex> conn = %Plug.Conn{}
iex> user = :user
iex> resource = Puppy
iex> action = :show
iex> {:error, conn} = Aegis.Controller.authorized?(conn, user, resource, action: action)
iex> conn.private[:aegis_auth_performed]
true
Link to this function call_action_and_verify_authorized(mod, actn, conn, user) View Source
call_action_and_verify_authorized(module(), atom(), Plug.Conn.t(), term()) ::
  Plug.t()

Calls controller action and performs a check on the connection in order to determine whether or not Aegis authorization has been performed.

Examples

TODO..