diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..a640d13 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,9 @@ +[ + import_deps: [:plug, :phoenix, :phoenix_live_view], + inputs: [ + "lib/**/*.ex", + "config/*.exs", + "test/**/*.exs", + "mix.exs" + ] +] diff --git a/lib/canary/plugs.ex b/lib/canary/plugs.ex index 6faeb3e..d36cd56 100644 --- a/lib/canary/plugs.ex +++ b/lib/canary/plugs.ex @@ -105,10 +105,13 @@ defmodule Canary.Plugs do cond do is_persisted -> fetch_resource(conn, opts) + action == :index -> fetch_all(conn, opts) + action in [:new, :create] -> nil + true -> fetch_resource(conn, opts) end @@ -163,9 +166,12 @@ defmodule Canary.Plugs do defp do_authorize_controller(conn, opts) do controller = conn.assigns[:canary_controller] || conn.private[:phoenix_controller] - current_user_name = opts[:current_user] || - Application.get_env(:canary, :current_user, :current_user) - current_user = Map.fetch! conn.assigns, current_user_name + + current_user_name = + opts[:current_user] || + Application.get_env(:canary, :current_user, :current_user) + + current_user = Map.fetch!(conn.assigns, current_user_name) action = get_action(conn) Plug.Conn.assign(conn, :authorized, can?(current_user, action, controller)) @@ -253,10 +259,13 @@ defmodule Canary.Plugs do end defp do_authorize_resource(conn, opts) do - current_user_name = opts[:current_user] || Application.get_env(:canary, :current_user, :current_user) - current_user = Map.fetch! conn.assigns, current_user_name + current_user_name = + opts[:current_user] || Application.get_env(:canary, :current_user, :current_user) + + current_user = Map.fetch!(conn.assigns, current_user_name) action = get_action(conn) is_persisted = persisted?(opts) + non_id_actions = if opts[:non_id_actions] do Enum.concat([:index, :new, :create], opts[:non_id_actions]) @@ -264,14 +273,17 @@ defmodule Canary.Plugs do [:index, :new, :create] end - resource = cond do - is_persisted -> - fetch_resource(conn, opts) - action in non_id_actions -> - opts[:model] - true -> - fetch_resource(conn, opts) - end + resource = + cond do + is_persisted -> + fetch_resource(conn, opts) + + action in non_id_actions -> + opts[:model] + + true -> + fetch_resource(conn, opts) + end Plug.Conn.assign(conn, :authorized, can?(current_user, action, resource)) end @@ -330,9 +342,11 @@ defmodule Canary.Plugs do defp do_load_and_authorize_resource(conn, opts) do conn - |> Map.put(:skip_canary_handler, true) # skip not_found_handler so auth handler can catch first if needed + # skip not_found_handler so auth handler can catch first if needed + |> Map.put(:skip_canary_handler, true) |> load_resource(opts) - |> Map.delete(:skip_canary_handler) # allow auth handling + # allow auth handling + |> Map.delete(:skip_canary_handler) |> authorize_resource(opts) |> maybe_handle_not_found(opts) |> purge_resource_if_unauthorized(opts) @@ -344,6 +358,7 @@ defmodule Canary.Plugs do defp purge_resource_if_unauthorized(%{assigns: %{authorized: true}} = conn, _opts), do: conn + defp purge_resource_if_unauthorized(%{assigns: %{authorized: false}} = conn, opts), do: Plug.Conn.assign(conn, get_resource_name(conn, opts), nil) @@ -358,12 +373,15 @@ defmodule Canary.Plugs do :error -> repo.get_by(opts[:model], get_map_args) |> preload_if_needed(repo, opts) + {:ok, nil} -> repo.get_by(opts[:model], get_map_args) |> preload_if_needed(repo, opts) + {:ok, resource} -> if resource.__struct__ == opts[:model] do - resource # A resource of the type passed as opts[:model] is already loaded; do not clobber it + # A resource of the type passed as opts[:model] is already loaded; do not clobber it + resource else opts[:model] |> repo.get_by(get_map_args) @@ -377,9 +395,11 @@ defmodule Canary.Plugs do resource_name = get_resource_name(conn, opts) - case Map.fetch(conn.assigns, resource_name) do # check if a resource is already loaded at the key + # check if a resource is already loaded at the key + case Map.fetch(conn.assigns, resource_name) do :error -> from(m in opts[:model]) |> select([m], m) |> repo.all |> preload_if_needed(repo, opts) + {:ok, resources} -> if Enum.at(resources, 0).__struct__ == opts[:model] do resources @@ -393,6 +413,7 @@ defmodule Canary.Plugs do case opts[:id_name] do nil -> conn.params["id"] + id_name -> conn.params[id_name] end @@ -401,7 +422,7 @@ defmodule Canary.Plugs do defp get_action(conn) do case Map.fetch(conn.assigns, :canary_action) do {:ok, action} -> action - _ -> conn.private.phoenix_action + _ -> conn.private.phoenix_action end end @@ -429,10 +450,13 @@ defmodule Canary.Plugs do cond do has_key?(opts, :except) && has_key?(opts, :only) -> false + has_key?(opts, :except) -> !action_exempt?(conn, opts) + has_key?(opts, :only) -> action_included?(conn, opts) + true -> true end @@ -455,7 +479,9 @@ defmodule Canary.Plugs do |> Macro.underscore() |> pluralize_if_needed(conn, opts) |> String.to_atom() - as -> as + + as -> + as end end @@ -475,6 +501,7 @@ defmodule Canary.Plugs do case opts[:preload] do nil -> records + models -> repo.preload(records, models) end @@ -482,6 +509,7 @@ defmodule Canary.Plugs do defp handle_unauthorized(%{assigns: %{authorized: true}} = conn, _opts), do: conn + defp handle_unauthorized(%{assigns: %{authorized: false}} = conn, opts), do: apply_error_handler(conn, :unauthorized_handler, opts) @@ -491,16 +519,18 @@ defmodule Canary.Plugs do defp handle_not_found(conn, opts) do action = get_action(conn) + non_id_actions = if opts[:non_id_actions] do Enum.concat([:index, :new, :create], opts[:non_id_actions]) else [:index, :new, :create] end + is_required = required?(opts) resource_name = Map.get(conn.assigns, get_resource_name(conn, opts)) - if is_nil(resource_name) and (is_required or not(action in non_id_actions)) do + if is_nil(resource_name) and (is_required or action not in non_id_actions) do apply_error_handler(conn, :not_found_handler, opts) else conn @@ -508,12 +538,13 @@ defmodule Canary.Plugs do end defp apply_error_handler(conn, handler_key, opts) do - handler = Keyword.get(opts, handler_key) - || Application.get_env(:canary, handler_key) + handler = + Keyword.get(opts, handler_key) || + Application.get_env(:canary, handler_key) case handler do {mod, fun} -> apply(mod, fun, [conn]) - nil -> conn + nil -> conn end end end diff --git a/test/plug_test.exs b/test/plug_test.exs index 883acff..215fcfc 100644 --- a/test/plug_test.exs +++ b/test/plug_test.exs @@ -6,10 +6,11 @@ defmodule Post do use Ecto.Schema schema "posts" do - belongs_to :user, :integer, define_field: false # :defaults not working so define own field with default value + # :defaults not working so define own field with default value + belongs_to(:user, :integer, define_field: false) - field :user_id, :integer, default: 1 - field :slug, :string + field(:user_id, :integer, default: 1) + field(:slug, :string) end end @@ -25,7 +26,10 @@ defmodule Repo do def preload(%Post{id: 1}, :user), do: %Post{id: 1} def preload(%Post{id: 2, user_id: 2}, :user), do: %Post{id: 2, user_id: 2, user: %User{id: 2}} - def preload([%Post{id: 1}, %Post{id: 2, user_id: 2}], :user), do: [%Post{id: 1}, %Post{id: 2, user_id: 2, user: %User{id: 2}}] + + def preload([%Post{id: 1}, %Post{id: 2, user_id: 2}], :user), + do: [%Post{id: 1}, %Post{id: 2, user_id: 2, user: %User{id: 2}}] + def preload(resources, _), do: resources def get_by(User, %{id: "1"}), do: %User{} @@ -41,27 +45,33 @@ defmodule Repo do end defimpl Canada.Can, for: User do - def can?(%User{}, action, Myproject.PartialAccessController) - when action in [:index, :show], do: true + when action in [:index, :show], + do: true + def can?(%User{}, action, Myproject.PartialAccessController) - when action in [:new, :create, :update, :delete], do: false + when action in [:new, :create, :update, :delete], + do: false def can?(%User{}, :index, Myproject.SampleController), do: true def can?(%User{id: _user_id}, action, Myproject.SampleController) - when action in [:index, :show, :new, :create, :update, :delete], do: true + when action in [:index, :show, :new, :create, :update, :delete], + do: true def can?(%User{id: user_id}, action, %Post{user_id: user_id}) - when action in [:index, :show, :new, :create], do: true + when action in [:index, :show, :new, :create], + do: true def can?(%User{}, :index, Post), do: true def can?(%User{}, action, Post) - when action in [:new, :create, :other_action], do: true + when action in [:new, :create, :other_action], + do: true def can?(%User{id: user_id}, action, %Post{user: %User{id: user_id}}) - when action in [:edit, :update], do: true + when action in [:edit, :update], + do: true def can?(%User{}, _, _), do: false end @@ -76,14 +86,14 @@ defmodule Helpers do conn |> Map.put(:unauthorized_handler_called, true) |> Plug.Conn.resp(403, "I'm sorry Dave. I'm afraid I can't do that.") - |> Plug.Conn.send_resp + |> Plug.Conn.send_resp() end def not_found_handler(conn) do conn |> Map.put(:not_found_handler_called, true) |> Plug.Conn.resp(404, "Resource not found.") - |> Plug.Conn.send_resp + |> Plug.Conn.send_resp() end def non_halting_unauthorized_handler(conn) do @@ -99,9 +109,9 @@ defmodule PlugTest do use ExUnit.Case, async: true - @moduletag timeout: 100000000 + @moduletag timeout: 100_000_000 - Application.put_env :canary, :repo, Repo + Application.put_env(:canary, :repo, Repo) test "it loads the resource correctly" do opts = [model: Post] @@ -116,7 +126,15 @@ defmodule PlugTest do # when a resource of the desired type is already present in conn.assigns # it does not clobber the old resource params = %{"id" => 1} - conn = conn(%Plug.Conn{private: %{phoenix_action: :show}, assigns: %{post: %Post{id: 2}}}, :get, "/posts/1", params) + + conn = + conn( + %Plug.Conn{private: %{phoenix_action: :show}, assigns: %{post: %Post{id: 2}}}, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :post, %Post{id: 2}) assert load_resource(conn, opts) == expected @@ -124,7 +142,15 @@ defmodule PlugTest do # when a resource of the desired type is already present in conn.assigns and the action is :index # it does not clobber the old resource params = %{} - conn = conn(%Plug.Conn{private: %{phoenix_action: :index}, assigns: %{posts: [%Post{id: 2}]}}, :get, "/posts", params) + + conn = + conn( + %Plug.Conn{private: %{phoenix_action: :index}, assigns: %{posts: [%Post{id: 2}]}}, + :get, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :posts, [%Post{id: 2}]) assert load_resource(conn, opts) == expected @@ -132,7 +158,15 @@ defmodule PlugTest do # when a resource of a different type is already present in conn.assigns # it replaces that resource with the desired resource params = %{"id" => 1} - conn = conn(%Plug.Conn{private: %{phoenix_action: :show}, assigns: %{post: %User{id: 2}}}, :get, "/posts/1", params) + + conn = + conn( + %Plug.Conn{private: %{phoenix_action: :show}, assigns: %{post: %User{id: 2}}}, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :post, %Post{id: 1}) assert load_resource(conn, opts) == expected @@ -140,7 +174,15 @@ defmodule PlugTest do # when a resource of a different type is already present in conn.assigns and the action is :index # it replaces that resource with the desired resource params = %{} - conn = conn(%Plug.Conn{private: %{phoenix_action: :index}, assigns: %{posts: [%User{id: 2}]}}, :get, "/posts", params) + + conn = + conn( + %Plug.Conn{private: %{phoenix_action: :index}, assigns: %{posts: [%User{id: 2}]}}, + :get, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :posts, [%Post{id: 1}, %Post{id: 2, user_id: 2}]) assert load_resource(conn, opts) == expected @@ -152,7 +194,6 @@ defmodule PlugTest do assert load_resource(conn, opts) == expected - # when the action is "index" params = %{} conn = conn(%Plug.Conn{private: %{phoenix_action: :index}}, :get, "/posts", params) @@ -160,7 +201,6 @@ defmodule PlugTest do assert load_resource(conn, opts) == expected - # when the action is "new" params = %{} conn = conn(%Plug.Conn{private: %{phoenix_action: :new}}, :get, "/posts/new", params) @@ -168,7 +208,6 @@ defmodule PlugTest do assert load_resource(conn, opts) == expected - # when the action is "create" params = %{} conn = conn(%Plug.Conn{private: %{phoenix_action: :create}}, :post, "/posts/create", params) @@ -233,7 +272,14 @@ defmodule PlugTest do opts = [model: Post, not_found_handler: {Helpers, :not_found_handler}, required: true] params = %{"id" => 3} - conn = conn(%Plug.Conn{assigns: %{post: nil}, private: %{phoenix_action: :new}}, :get, "/posts/3/new", params) + + conn = + conn( + %Plug.Conn{assigns: %{post: nil}, private: %{phoenix_action: :new}}, + :get, + "/posts/3/new", + params + ) expected = Helpers.not_found_handler(conn) @@ -244,7 +290,14 @@ defmodule PlugTest do opts = [model: Post, not_found_handler: {Helpers, :not_found_handler}, required: true] params = %{"id" => 3} - conn = conn(%Plug.Conn{assigns: %{post: nil}, private: %{phoenix_action: :index}}, :post, "/posts/3/new", params) + + conn = + conn( + %Plug.Conn{assigns: %{post: nil}, private: %{phoenix_action: :index}}, + :post, + "/posts/3/new", + params + ) expected = Helpers.not_found_handler(conn) @@ -255,7 +308,14 @@ defmodule PlugTest do opts = [model: Post, not_found_handler: {Helpers, :not_found_handler}, required: true] params = %{"id" => 3} - conn = conn(%Plug.Conn{assigns: %{post: nil}, private: %{phoenix_action: :index}}, :get, "/posts/3", params) + + conn = + conn( + %Plug.Conn{assigns: %{post: nil}, private: %{phoenix_action: :index}}, + :get, + "/posts/3", + params + ) expected = Helpers.not_found_handler(conn) @@ -267,113 +327,128 @@ defmodule PlugTest do # when the action is "new" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :new}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/new", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :new}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/new", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the action is "create" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :create}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/create", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :create}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/create", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the action is "index" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :index}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :index}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the action is a phoenix action params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the current user can access the given resource # and the action is specified in conn.assigns.canary_action params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show} + }, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when both conn.assigns.canary_action and conn.private.phoenix_action are defined # it uses conn.assigns.canary_action for authorization params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}, canary_action: :unauthorized} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}, canary_action: :unauthorized} + }, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_resource(conn, opts) == expected - # when the current user cannot access the given resource params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show} - }, - :get, - "/posts/2", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show} + }, + :get, + "/posts/2", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_resource(conn, opts) == expected @@ -381,15 +456,18 @@ defmodule PlugTest do # when the resource of the desired type already exists in conn.assigns, # it authorizes for that resource params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %Post{user_id: 1}} - }, - :get, - "/posts/2", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %Post{user_id: 1}} + }, + :get, + "/posts/2", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected @@ -397,30 +475,36 @@ defmodule PlugTest do # when the resource of a different type already exists in conn.assigns, # it authorizes for the desired resource params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %User{}} - }, - :get, - "/posts/2", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %User{}} + }, + :get, + "/posts/2", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_resource(conn, opts) == expected # when current_user is nil params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: nil, canary_action: :create} - }, - :post, - "/posts", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: nil, canary_action: :create} + }, + :post, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_resource(conn, opts) == expected @@ -431,113 +515,128 @@ defmodule PlugTest do # when the action is "new" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :new}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/new", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :new}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/new", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the action is "create" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :create}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/create", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :create}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/create", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the action is "index" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :index}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :index}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the action is a phoenix action params = %{"slug" => "slug1"} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/slug1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/slug1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the current user can access the given resource # and the action is specified in conn.assigns.canary_action params = %{"slug" => "slug1"} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show} - }, - :get, - "/posts/slug1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show} + }, + :get, + "/posts/slug1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when both conn.assigns.canary_action and conn.private.phoenix_action are defined # it uses conn.assigns.canary_action for authorization params = %{"slug" => "slug1"} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}, canary_action: :unauthorized} - }, - :get, - "/posts/slug1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}, canary_action: :unauthorized} + }, + :get, + "/posts/slug1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_resource(conn, opts) == expected - # when the current user cannot access the given resource params = %{"slug" => "slug2"} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show} - }, - :get, - "/posts/slug2", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show} + }, + :get, + "/posts/slug2", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_resource(conn, opts) == expected @@ -545,15 +644,18 @@ defmodule PlugTest do # when the resource of the desired type already exists in conn.assigns, # it authorizes for that resource params = %{"slug" => "slug2"} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %Post{user_id: 1}} - }, - :get, - "/posts/slug2", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %Post{user_id: 1}} + }, + :get, + "/posts/slug2", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected @@ -561,30 +663,36 @@ defmodule PlugTest do # when the resource of a different type already exists in conn.assigns, # it authorizes for the desired resource params = %{"slug" => "slug2"} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %User{}} - }, - :get, - "/posts/slug2", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %User{}} + }, + :get, + "/posts/slug2", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_resource(conn, opts) == expected # when current_user is nil params = %{"slug" => "slug1"} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: nil, canary_action: :create} - }, - :post, - "/posts", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: nil, canary_action: :create} + }, + :post, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_resource(conn, opts) == expected @@ -594,15 +702,18 @@ defmodule PlugTest do opts = [model: Post, id_name: "post_id", persisted: true] params = %{"post_id" => 2} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :index}, - assigns: %{current_user: %User{id: 2}} - }, - :get, - "/posts/post_id/comments", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :index}, + assigns: %{current_user: %User{id: 2}} + }, + :get, + "/posts/post_id/comments", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected @@ -612,15 +723,18 @@ defmodule PlugTest do opts = [model: Post, id_name: "post_id", persisted: true] params = %{"post_id" => 2} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :new}, - assigns: %{current_user: %User{id: 2}} - }, - :get, - "/posts/post_id/comments/new", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :new}, + assigns: %{current_user: %User{id: 2}} + }, + :get, + "/posts/post_id/comments/new", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected @@ -630,15 +744,18 @@ defmodule PlugTest do opts = [model: Post, id_name: "post_id", persisted: true] params = %{"post_id" => "2"} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :create}, - assigns: %{current_user: %User{id: 2}} - }, - :post, - "/posts/post_id/comments", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :create}, + assigns: %{current_user: %User{id: 2}} + }, + :post, + "/posts/post_id/comments", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected @@ -650,90 +767,108 @@ defmodule PlugTest do # when the current user can access the given resource # and the resource can be loaded params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 1, user_id: 1}) - assert load_and_authorize_resource(conn, opts) == expected + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 1, user_id: 1}) + assert load_and_authorize_resource(conn, opts) == expected # when the current user cannot access the given resource params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show} - }, - :get, - "/posts/2", - params - ) - - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Plug.Conn.assign(:post, nil) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show} + }, + :get, + "/posts/2", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Plug.Conn.assign(:post, nil) assert load_and_authorize_resource(conn, opts) == expected # when a resource of the desired type is already present in conn.assigns # it does not load a new resource params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %Post{user_id: 1}} - }, - :get, - "/posts/2", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{user_id: 1}) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %Post{user_id: 1}} + }, + :get, + "/posts/2", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{user_id: 1}) assert load_and_authorize_resource(conn, opts) == expected # when a resource of the a different type is already present in conn.assigns # it loads and authorizes for the desired resource params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %User{id: 1}} - }, - :get, - "/posts/2", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Plug.Conn.assign(:post, nil) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %User{id: 1}} + }, + :get, + "/posts/2", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Plug.Conn.assign(:post, nil) assert load_and_authorize_resource(conn, opts) == expected # when the given resource cannot be loaded params = %{"id" => 3} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show} - }, - :get, - "/posts/1", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Plug.Conn.assign(:post, nil) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show} + }, + :get, + "/posts/1", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Plug.Conn.assign(:post, nil) assert load_and_authorize_resource(conn, opts) == expected end @@ -744,89 +879,108 @@ defmodule PlugTest do # when the current user can access the given resource # and the resource can be loaded params = %{"slug" => "slug1"} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/slug1", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 1, slug: "slug1", user_id: 1}) - assert load_and_authorize_resource(conn, opts) == expected + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/slug1", + params + ) + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 1, slug: "slug1", user_id: 1}) + + assert load_and_authorize_resource(conn, opts) == expected # when the current user cannot access the given resource params = %{"slug" => "slug2"} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show} - }, - :get, - "/posts/slug2", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Plug.Conn.assign(:post, nil) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show} + }, + :get, + "/posts/slug2", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Plug.Conn.assign(:post, nil) assert load_and_authorize_resource(conn, opts) == expected # when a resource of the desired type is already present in conn.assigns # it does not load a new resource params = %{"slug" => "slug2"} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %Post{user_id: 1}} - }, - :get, - "/posts/slug2", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{user_id: 1}) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %Post{user_id: 1}} + }, + :get, + "/posts/slug2", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{user_id: 1}) assert load_and_authorize_resource(conn, opts) == expected # when a resource of the a different type is already present in conn.assigns # it loads and authorizes for the desired resource params = %{"slug" => "slug2"} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %User{id: 1}} - }, - :get, - "/posts/slug2", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Plug.Conn.assign(:post, nil) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show, post: %User{id: 1}} + }, + :get, + "/posts/slug2", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Plug.Conn.assign(:post, nil) assert load_and_authorize_resource(conn, opts) == expected # when the given resource cannot be loaded params = %{"slug" => "slug3"} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show} - }, - :get, - "/posts/slug3", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Plug.Conn.assign(:post, nil) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{current_user: %User{id: 1}, canary_action: :show} + }, + :get, + "/posts/slug3", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Plug.Conn.assign(:post, nil) assert load_and_authorize_resource(conn, opts) == expected end @@ -835,18 +989,22 @@ defmodule PlugTest do opts = [model: Post, id_name: "post_id", persisted: true] params = %{"post_id" => 2} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :index}, - assigns: %{current_user: %User{id: 2}} - }, - :get, - "/posts/2/comments", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2}) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :index}, + assigns: %{current_user: %User{id: 2}} + }, + :get, + "/posts/2/comments", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2}) assert load_and_authorize_resource(conn, opts) == expected end @@ -855,18 +1013,22 @@ defmodule PlugTest do opts = [model: Post, id_name: "post_id", persisted: true] params = %{"post_id" => 2} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :new}, - assigns: %{current_user: %User{id: 2}} - }, - :get, - "/posts/2/comments/new", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2}) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :new}, + assigns: %{current_user: %User{id: 2}} + }, + :get, + "/posts/2/comments/new", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2}) assert load_and_authorize_resource(conn, opts) == expected end @@ -875,18 +1037,22 @@ defmodule PlugTest do opts = [model: Post, id_name: "post_id", persisted: true] params = %{"post_id" => "2"} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :create}, - assigns: %{current_user: %User{id: 2}} - }, - :create, - "/posts/2/comments", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2}) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :create}, + assigns: %{current_user: %User{id: 2}} + }, + :create, + "/posts/2/comments", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2}) assert load_and_authorize_resource(conn, opts) == expected end @@ -895,32 +1061,37 @@ defmodule PlugTest do # when the action is in opts[:only] opts = [model: Post, only: :show] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :post, %Post{id: 1}) assert load_resource(conn, opts) == expected - # when the action is not opts[:only] opts = [model: Post, only: :other] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert load_resource(conn, opts) == expected @@ -930,122 +1101,138 @@ defmodule PlugTest do # when the action is in opts[:only] opts = [model: Post, only: :show] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the action is not opts[:only] opts = [model: Post, only: :other] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert authorize_resource(conn, opts) == expected end - test "it only loads and authorizes the resource for actions in opts[:only]" do # when the action is in opts[:only] opts = [model: Post, only: :show] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 1, user_id: 1}) - assert load_and_authorize_resource(conn, opts) == expected + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 1, user_id: 1}) + assert load_and_authorize_resource(conn, opts) == expected # when the action is not opts[:only] opts = [model: Post, only: :other] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert load_and_authorize_resource(conn, opts) == expected end - test "it skips the plug when both opts[:only] and opts[:except] are specified" do # when the plug is load_resource opts = [model: Post, only: :show, except: :index] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert load_resource(conn, opts) == expected - # when the plug is authorize_resource opts = [model: Post, only: :show, except: :index] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert authorize_resource(conn, opts) == expected - # when the plug is load_and_authorize_resource opts = [model: Post, only: :show, except: :index] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert load_and_authorize_resource(conn, opts) == expected @@ -1055,20 +1242,22 @@ defmodule PlugTest do # when the action is exempt opts = [model: Post, except: :show] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert authorize_resource(conn, opts) == expected - # when the action is not exempt opts = [model: Post] expected = Plug.Conn.assign(conn, :authorized, true) @@ -1076,58 +1265,61 @@ defmodule PlugTest do assert authorize_resource(conn, opts) == expected end - test "it correctly skips loading resources for exempt actions" do # when the action is exempt opts = [model: Post, except: :show] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert load_resource(conn, opts) == expected - # when the action is not exempt opts = [model: Post] expected = Plug.Conn.assign(conn, :post, %Post{id: 1, user_id: 1}) assert load_resource(conn, opts) == expected end - test "it correctly skips load_and_authorize_resource for exempt actions" do # when the action is exempt opts = [model: Post, except: :show] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert load_and_authorize_resource(conn, opts) == expected - # when the action is not exempt opts = [model: Post] - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 1, user_id: 1}) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 1, user_id: 1}) assert load_and_authorize_resource(conn, opts) == expected end - test "it loads the resource into a key specified by the :as option" do opts = [model: Post, as: :some_key] @@ -1139,51 +1331,55 @@ defmodule PlugTest do assert load_resource(conn, opts) == expected end - test "it authorizes the resource correctly when the :as key is specified" do opts = [model: Post, as: :some_key] # when the action is "new" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :new}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/new", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :new}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/new", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected # need to check that it works for authorization as well, and for load_and_authorize_resource end - test "it loads and authorizes the resource correctly when the :as key is specified" do opts = [model: Post, as: :some_key] # when the current user can access the given resource # and the resource can be loaded params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:some_key, %Post{id: 1, user_id: 1}) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:some_key, %Post{id: 1, user_id: 1}) assert load_and_authorize_resource(conn, opts) == expected end - test "when the :as key is not specified, it loads the resource into a key inferred from the model name" do opts = [model: Post] @@ -1199,11 +1395,19 @@ defmodule PlugTest do opts = [model: Post, unauthorized_handler: {Helpers, :unauthorized_handler}] params = %{"id" => 1} - conn = conn(%Plug.Conn{assigns: %{current_user: %User{id: 2}}, - private: %{phoenix_action: :show}}, :get, "/posts/1", params) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Helpers.unauthorized_handler + + conn = + conn( + %Plug.Conn{assigns: %{current_user: %User{id: 2}}, private: %{phoenix_action: :show}}, + :get, + "/posts/1", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Helpers.unauthorized_handler() assert authorize_resource(conn, opts) == expected end @@ -1212,7 +1416,14 @@ defmodule PlugTest do opts = [model: Post, not_found_handler: {Helpers, :not_found_handler}] params = %{"id" => 3} - conn = conn(%Plug.Conn{assigns: %{post: nil}, private: %{phoenix_action: :show}}, :get, "/posts/3", params) + + conn = + conn( + %Plug.Conn{assigns: %{post: nil}, private: %{phoenix_action: :show}}, + :get, + "/posts/3", + params + ) expected = Helpers.not_found_handler(conn) @@ -1220,34 +1431,54 @@ defmodule PlugTest do end test "when unauthorized and resource not found, it calls the specified authorization handler first" do - opts = [model: Post, not_found_handler: {Helpers, :not_found_handler}, - unauthorized_handler: {Helpers, :unauthorized_handler}] + opts = [ + model: Post, + not_found_handler: {Helpers, :not_found_handler}, + unauthorized_handler: {Helpers, :unauthorized_handler} + ] params = %{"id" => 3} - conn = conn(%Plug.Conn{assigns: %{current_user: %User{id: 2}}, - private: %{phoenix_action: :show}}, :get, "/posts/3", params) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Plug.Conn.assign(:post, nil) - |> Helpers.unauthorized_handler + conn = + conn( + %Plug.Conn{assigns: %{current_user: %User{id: 2}}, private: %{phoenix_action: :show}}, + :get, + "/posts/3", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Plug.Conn.assign(:post, nil) + |> Helpers.unauthorized_handler() assert load_and_authorize_resource(conn, opts) == expected end test "when the authorization handler does not halt the request, it calls the not found handler if specified" do - opts = [model: Post, not_found_handler: {Helpers, :not_found_handler}, - unauthorized_handler: {Helpers, :non_halting_unauthorized_handler}] + opts = [ + model: Post, + not_found_handler: {Helpers, :not_found_handler}, + unauthorized_handler: {Helpers, :non_halting_unauthorized_handler} + ] params = %{"id" => 3} - conn = conn(%Plug.Conn{assigns: %{current_user: %User{id: 2}}, - private: %{phoenix_action: :show}}, :get, "/posts/3", params) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Plug.Conn.assign(:post, nil) - |> Helpers.non_halting_unauthorized_handler - |> Helpers.not_found_handler + conn = + conn( + %Plug.Conn{assigns: %{current_user: %User{id: 2}}, private: %{phoenix_action: :show}}, + :get, + "/posts/3", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Plug.Conn.assign(:post, nil) + |> Helpers.non_halting_unauthorized_handler() + |> Helpers.not_found_handler() assert load_and_authorize_resource(conn, opts) == expected end @@ -1260,12 +1491,19 @@ defmodule PlugTest do opts = [model: Post] params = %{"id" => 1} - conn = conn(%Plug.Conn{assigns: %{current_user: %User{id: 2}}, - private: %{phoenix_action: :show}}, :get, "/posts/1", params) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Helpers.unauthorized_handler + conn = + conn( + %Plug.Conn{assigns: %{current_user: %User{id: 2}}, private: %{phoenix_action: :show}}, + :get, + "/posts/1", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Helpers.unauthorized_handler() assert authorize_resource(conn, opts) == expected end @@ -1275,13 +1513,20 @@ defmodule PlugTest do opts = [model: Post] params = %{"id" => 3} - conn = conn(%Plug.Conn{assigns: %{current_user: %User{id: 2}}, - private: %{phoenix_action: :show}}, :get, "/posts/3", params) - expected = conn - |> Plug.Conn.assign(:authorized, false) - |> Plug.Conn.assign(:post, nil) - |> Helpers.unauthorized_handler + conn = + conn( + %Plug.Conn{assigns: %{current_user: %User{id: 2}}, private: %{phoenix_action: :show}}, + :get, + "/posts/3", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, false) + |> Plug.Conn.assign(:post, nil) + |> Helpers.unauthorized_handler() assert load_and_authorize_resource(conn, opts) == expected end @@ -1291,15 +1536,24 @@ defmodule PlugTest do use ExUnit.Case, async: false test "when unauthorized, it calls the opt-specified action rather than the configured action" do - Application.put_env(:canary, :unauthorized_handler, {Helpers, :does_not_exist}) # should not be called + # should not be called + Application.put_env(:canary, :unauthorized_handler, {Helpers, :does_not_exist}) opts = [model: Post, unauthorized_handler: {Helpers, :unauthorized_handler}] params = %{"id" => 1} - conn = conn(%Plug.Conn{assigns: %{current_user: %User{id: 2}}, - private: %{phoenix_action: :show}}, :get, "/posts/1", params) - expected = conn - |> Helpers.unauthorized_handler - |> Plug.Conn.assign(:authorized, false) + + conn = + conn( + %Plug.Conn{assigns: %{current_user: %User{id: 2}}, private: %{phoenix_action: :show}}, + :get, + "/posts/1", + params + ) + + expected = + conn + |> Helpers.unauthorized_handler() + |> Plug.Conn.assign(:authorized, false) assert authorize_resource(conn, opts) == expected end @@ -1314,9 +1568,11 @@ defmodule PlugTest do params = %{"id" => 4} conn = conn(%Plug.Conn{private: %{phoenix_action: :show}}, :get, "/posts/4", params) - expected = conn - |> Helpers.not_found_handler - |> Plug.Conn.assign(:post, nil) + + expected = + conn + |> Helpers.not_found_handler() + |> Plug.Conn.assign(:post, nil) assert load_resource(conn, opts) == expected end @@ -1326,14 +1582,17 @@ defmodule PlugTest do use ExUnit.Case, async: false test "when not_found, it calls the opt-specified action rather than the configured action" do - Application.put_env(:canary, :not_found_handler, {Helpers, :does_not_exist}) # should not be called + # should not be called + Application.put_env(:canary, :not_found_handler, {Helpers, :does_not_exist}) opts = [model: Post, not_found_handler: {Helpers, :not_found_handler}] params = %{"id" => 4} conn = conn(%Plug.Conn{private: %{phoenix_action: :show}}, :get, "/posts/4", params) - expected = conn - |> Helpers.not_found_handler - |> Plug.Conn.assign(:post, nil) + + expected = + conn + |> Helpers.not_found_handler() + |> Plug.Conn.assign(:post, nil) assert load_resource(conn, opts) == expected end @@ -1346,21 +1605,23 @@ defmodule PlugTest do use ExUnit.Case, async: false import Mock - test_with_mock "it uses the current_user name configured", Application, [:passthrough], [ - get_env: fn(_,_,_)-> :current_admin end - ] do + test_with_mock "it uses the current_user name configured", Application, [:passthrough], + get_env: fn _, _, _ -> :current_admin end do # when the user configured with opts opts = [model: Post, except: :show] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_admin: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_admin: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = conn assert authorize_resource(conn, opts) == expected @@ -1371,15 +1632,18 @@ defmodule PlugTest do # when the user configured with opts opts = [model: Post, current_user: :user] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{user: %User{id: 1}, authorized: true} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{user: %User{id: 1}, authorized: true} + }, + :get, + "/posts/1", + params + ) + expected = conn assert authorize_resource(conn, opts) == expected @@ -1389,17 +1653,19 @@ defmodule PlugTest do # when the user configured with opts opts = [model: Post, current_user: :configured_current_user] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{user: %User{id: 1}, authorized: true} - }, - :get, - "/posts/1", - params - ) - assert_raise KeyError, ~r/^key :configured_current_user not found in: %{/, fn-> + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{user: %User{id: 1}, authorized: true} + }, + :get, + "/posts/1", + params + ) + + assert_raise KeyError, ~r/^key :configured_current_user not found in: %{/, fn -> authorize_resource(conn, opts) end end @@ -1418,7 +1684,6 @@ defmodule PlugTest do assert load_resource(conn, opts) == expected - # when the resource with the id can be fetched and the association does not exist params = %{"id" => 1} conn = conn(%Plug.Conn{private: %{phoenix_action: :show}}, :get, "/posts/1", params) @@ -1426,7 +1691,6 @@ defmodule PlugTest do assert load_resource(conn, opts) == expected - # when the resource with the id cannot be fetched params = %{"id" => 3} conn = conn(%Plug.Conn{private: %{phoenix_action: :show}}, :get, "/posts/3", params) @@ -1434,14 +1698,17 @@ defmodule PlugTest do assert load_resource(conn, opts) == expected - # when the action is "index" params = %{} conn = conn(%Plug.Conn{private: %{phoenix_action: :index}}, :get, "/posts", params) - expected = Plug.Conn.assign(conn, :posts, [%Post{id: 1}, %Post{id: 2, user_id: 2, user: %User{id: 2}}]) - assert load_resource(conn, opts) == expected + expected = + Plug.Conn.assign(conn, :posts, [ + %Post{id: 1}, + %Post{id: 2, user_id: 2, user: %User{id: 2}} + ]) + assert load_resource(conn, opts) == expected # when the action is "new" params = %{} @@ -1456,31 +1723,36 @@ defmodule PlugTest do # when the action is "edit" params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :edit}, - assigns: %{current_user: %User{id: 2}} - }, - :get, - "/posts/edit/2", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :edit}, + assigns: %{current_user: %User{id: 2}} + }, + :get, + "/posts/edit/2", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected - # when the action is "index" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :index}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :index}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected @@ -1492,54 +1764,65 @@ defmodule PlugTest do # when the current user can access the given resource # and the resource can be loaded and the association exists params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 2}} - }, - :get, - "/posts/2", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2, user: %User{id: 2}}) - assert load_and_authorize_resource(conn, opts) == expected + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 2}} + }, + :get, + "/posts/2", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2, user: %User{id: 2}}) + assert load_and_authorize_resource(conn, opts) == expected # when the current user can access the given resource # and the resource can be loaded and the association does not exist params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 1, user_id: 1}) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 1, user_id: 1}) assert load_and_authorize_resource(conn, opts) == expected # when the action is "edit" params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :edit}, - assigns: %{current_user: %User{id: 2}} - }, - :get, - "/posts/edit/2", - params - ) - expected = conn - |> Plug.Conn.assign(:authorized, true) - |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2, user: %User{id: 2}}) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :edit}, + assigns: %{current_user: %User{id: 2}} + }, + :get, + "/posts/edit/2", + params + ) + + expected = + conn + |> Plug.Conn.assign(:authorized, true) + |> Plug.Conn.assign(:post, %Post{id: 2, user_id: 2, user: %User{id: 2}}) assert load_and_authorize_resource(conn, opts) == expected end @@ -1552,17 +1835,19 @@ defmodule PlugTest do # when opts[:non_id_actions] is set but not as a list opts = [model: Post, non_id_actions: :other_action] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :other_action}, - assigns: %{current_user: %User{id: 1}, authorized: true} - }, - :get, - "/posts/other-action", - params - ) - assert_raise Protocol.UndefinedError, ~r/protocol Enumerable not implemented for /, fn-> + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :other_action}, + assigns: %{current_user: %User{id: 1}, authorized: true} + }, + :get, + "/posts/other-action", + params + ) + + assert_raise Protocol.UndefinedError, ~r/protocol Enumerable not implemented for /, fn -> authorize_resource(conn, opts) end end @@ -1572,15 +1857,18 @@ defmodule PlugTest do opts = [model: Post, non_id_actions: [:other_action]] params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :other_action}, - assigns: %{current_user: %User{id: 1}, authorized: true} - }, - :get, - "/posts/other-action", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :other_action}, + assigns: %{current_user: %User{id: 1}, authorized: true} + }, + :get, + "/posts/other-action", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_resource(conn, opts) == expected @@ -1592,60 +1880,72 @@ defmodule PlugTest do # when the action is "new" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :new, phoenix_controller: Myproject.SampleController}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/new", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :new, phoenix_controller: Myproject.SampleController}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/new", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_controller(conn, opts) == expected # when the action is "create" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :create, phoenix_controller: Myproject.SampleController}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/create", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :create, phoenix_controller: Myproject.SampleController}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/create", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_controller(conn, opts) == expected # when the action is "index" params = %{} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :index, phoenix_controller: Myproject.SampleController}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :index, phoenix_controller: Myproject.SampleController}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_controller(conn, opts) == expected # when the action is a phoenix action params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show, phoenix_controller: Myproject.SampleController}, - assigns: %{current_user: %User{id: 1}} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show, phoenix_controller: Myproject.SampleController}, + assigns: %{current_user: %User{id: 1}} + }, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_controller(conn, opts) == expected @@ -1653,15 +1953,22 @@ defmodule PlugTest do # when the current user can access the given resource # and the action and controller are specified in conn.assigns.canary_action params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{}, - assigns: %{current_user: %User{id: 1}, canary_action: :show, canary_controller: Myproject.SampleController} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{}, + assigns: %{ + current_user: %User{id: 1}, + canary_action: :show, + canary_controller: Myproject.SampleController + } + }, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_controller(conn, opts) == expected @@ -1669,76 +1976,90 @@ defmodule PlugTest do # when both conn.assigns.canary_action and conn.private.phoenix_action are defined # it uses conn.assigns.canary_action for authorization params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_action: :show, phoenix_controller: Myproject.SampleController}, - assigns: %{current_user: %User{id: 1}, canary_action: :unauthorized} - }, - :get, - "/posts/1", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_action: :show, phoenix_controller: Myproject.SampleController}, + assigns: %{current_user: %User{id: 1}, canary_action: :unauthorized} + }, + :get, + "/posts/1", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_controller(conn, opts) == expected - # when the current user cannot access the given action params = %{"id" => 2} - conn = conn( - %Plug.Conn{ - private: %{phoenix_controller: Myproject.SampleController}, - assigns: %{current_user: %User{id: 1}, canary_action: :someaction} - }, - :get, - "/posts/2", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_controller: Myproject.SampleController}, + assigns: %{current_user: %User{id: 1}, canary_action: :someaction} + }, + :get, + "/posts/2", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_controller(conn, opts) == expected # when current_user is nil params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_controller: Myproject.SampleController}, - assigns: %{current_user: nil, canary_action: :create} - }, - :post, - "/posts", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_controller: Myproject.SampleController}, + assigns: %{current_user: nil, canary_action: :create} + }, + :post, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_controller(conn, opts) == expected # when an action is restricted on a controller params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_controller: Myproject.PartialAccessController}, - assigns: %{current_user: %User{id: 1}, canary_action: :new} - }, - :post, - "/posts", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_controller: Myproject.PartialAccessController}, + assigns: %{current_user: %User{id: 1}, canary_action: :new} + }, + :post, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :authorized, false) assert authorize_controller(conn, opts) == expected # when an action is authorized on a controller params = %{"id" => 1} - conn = conn( - %Plug.Conn{ - private: %{phoenix_controller: Myproject.PartialAccessController}, - assigns: %{current_user: %User{id: 1}, canary_action: :show} - }, - :post, - "/posts", - params - ) + + conn = + conn( + %Plug.Conn{ + private: %{phoenix_controller: Myproject.PartialAccessController}, + assigns: %{current_user: %User{id: 1}, canary_action: :show} + }, + :post, + "/posts", + params + ) + expected = Plug.Conn.assign(conn, :authorized, true) assert authorize_controller(conn, opts) == expected