• Stars
    star
    182
  • Rank 211,154 (Top 5 %)
  • Language
    Elixir
  • License
    MIT License
  • Created over 8 years ago
  • Updated almost 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Elixir authorization and resource loading in Plug form for Phoenix

policy_wonk

Build Status Hex.pm Inline docs Hex.pm Hex.pm

PolicyWonk is a lightweight authorization and resource loading library for any Plug or Phoenix application.

Note on v1.0.0

Policy Wonk is almost completely re-written for version 1.0. After living with it for well over a year, I realized there were a set of issues that warranted re-opening the underlying architecture.

  • It wasn't compatible with Phoenix 1.3 umbrella apps. Or rather, you couldn't have separate policies for different apps in an umbrella.
  • It had a whole mess of complexity that simply wasn't needed. I never used most of the "shortcut" options since the more explicit versions (with slightly more typing) were always clearer.
  • Returning errors from Policies was too vague. I want to know errors are being processed!
  • The config file data isn't necessary in a more explicit model.
  • Naming was inconsistent between policies and resources.

Version 1.0 takes these observations (and more), fixes them, and simplifies the configuration dramatically. It has less code and is overall simpler and faster.

There is a little work to upgrade from a older versions, but the overall shape of your code will stay the same, so the work is small and well worth it.

You can read the full documentation here.

Authentication vs. Authorization

Authentication (Auth-N) is the process of proving that a user or other entity is who/what it claims to be. Tools such as comeonin or guardian are mostly about authentication. Any time you are checking hashes or passwords, you are doing Auth-N.

Authorization (Auth-Z) is the process of deciding what a user/entity is allowed to do after they’ve been authenticated.

Authorization ranges from simple (ensuring somebody is logged in), to very rich (make sure the user has specific permissions to see a resource or that one resource is correctly related to the other resources being manipulated).

Setup

Add policy_wonk to the deps section of your application's mix.exs file

defp deps do
  [
    # ...
    {:policy_wonk, "~> 1.0.0"}
    # ...
  ]
end

Don't forget to run mix deps.get

Examples

Load and enforce the current user in a router:

pipeline :browser_session do
  plug MyAppWeb.Resources,  :current_user
  plug MyAppWeb.Policies,   :current_user
end

pipeline :admin do
  plug MyAppWeb.Policies, {:admin_permission, "dashboard"}
end

In a controller:

plug MyAppWeb.Policies, {:admin_permission, "dashboard"}

Policies

With PolicyWonk, you create policies and loaders for your application. They can be used as plugs in your router or controller or called for yes/no decisions in a template or controller.

This lets you enforce things like "a user is signed in" or "the admin has this permission" in the router. Or you could use a policy to determine if you should render a set of UI.

If a policy fails, it halts your plug chain and lets you decide what to do with the error.

Example policy:

defmodule MyAppWeb.Policies do
  use PolicyWonk.Policy         # set up support for policies
  use PolicyWonk.Enforce        # turn this module into an enforcement plug

  def policy( assigns, :current_user ) do
    case assigns[:current_user] do
      %MyApp.Account.User{} ->
        :ok
      _ ->
        {:error, :current_user}
    end
  end

  def policy_error(conn, :current_user) do
    MyAppWeb.ErrorHandlers.unauthenticated(conn, "Must be logged in")
  end
end

See the the PolicyWonk.Policy documentation for details.

Policies outside plugs

In addition to evaluating policies in a plug chain, you will often want to test a policy when rendering UI, processing an action in a controller, or somewhere else.

The use PolicyWonk.Policy call in your policy module adds the enforce!/2 and authorized?/2 functions, which you can use in templates or controllers to decide what UI to show or to raise an error under certain conditions.

In a template:

<%= if MyAppWeb.Policies.authorized?(@conn, {:admin_permission, "dashboard"}) do %>
  <%= link "Admin Dashboard", to: admin_dashboard_path(@conn, :index) %>
<% end %>

In an action in a controller:

def settings(conn, params) do
  ...
  # raise an error if the current user is not the user specified in the url.
  MyAppWeb.Policies.enforce!(conn, :user_is_self)
  ...
end

Resources

Resources are similar to policies in that you define functions that can be used in the plug chain. Instead of making a yes/no enforcement decision, a resource will load a resource and insert it into the conn's assigns map.

defmodule MyAppWeb.Loaders do
  use PolicyWonk.Resource       # set up support for resources
  use PolicyWonk.Load           # turn this module into an load resource plug

  def resource( _conn, :user, %{"id" => user_id} ) do
    case MyApp.Account.get_user(user_id) do
      nil ->  {:error, :user}
      %MyApp.Account.User{} = user -> {:ok, :user, user}
    end
  end

  def resource_error(conn, _resource_id) do
    MyAppWeb.ErrorHandlers.resource_not_found( conn )
  end
end

See the the PolicyWonk.Resource documentation for details.

Documentation

You can read the full documentation here.

More Repositories

1

scenic

Core Scenic library
Elixir
1,751
star
2

phoenix_integration

Lightweight server side integration test tools for Phoenix
Elixir
219
star
3

scenic_new

mix scenic.new task for Scenic apps
Elixir
116
star
4

phoenix_markdown

Phoenix Template Engine for Markdown
Elixir
82
star
5

scenic_driver_glfw

Scenic render and input driver for windowed OSs
C
26
star
6

scenic_driver_nerves_rpi

Scenic render-only driver for the Raspberry Pi under Nerves
C
22
star
7

scenic_driver_nerves_touch

Scenic.Driver.Nerves.Rpi - Scenic driver providing touch input for Nerves devices
Elixir
18
star
8

scenic_math

Math library supporting Scenic
Elixir
15
star
9

scenic_sensor

A combo PubSub and Data cache that sits between sensors and scenes. Can be used outside of Scenic applications
Elixir
14
star
10

adept_modal

LiveView modal dialog component using Tailwind and Alpine js
Elixir
8
star
11

inline_svg

A simple and fast in-line SVG library and renderer for web applications
Elixir
7
star
12

font_metrics

Work with graphical font metrics and strings. Intended for use with, but doesn't require, Scenic
Elixir
5
star
13

scenic_clock

Clock packaged as components up for use in Scenic applications
Elixir
4
star
14

truetype_metrics

Extracts metadata from TrueType fonts and compiles terms for use with font_metrics
Elixir
3
star
15

nerves_scenic_test_app

Work in progress test app for scenic and nerves together. Not intended for production use.
Elixir
2
star
16

presentations

Decks and other information from my various presentations
1
star
17

sinatra-starter

Starter Sinatra site using sprockets, compass, bootstrap-sass, markdown, partials, jquery, more
Ruby
1
star