-
Notifications
You must be signed in to change notification settings - Fork 381
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
plug to ensure load_resource actually worked (#238)
- Loading branch information
1 parent
52b7e1b
commit 824e2a4
Showing
4 changed files
with
196 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
defmodule Guardian.Plug.EnsureResource do | ||
@moduledoc """ | ||
This plug ensures that the current_resource has been set, usually in | ||
Guardian.Plug.LoadResource. | ||
If one is not found, the `no_resource/2` function is invoked with the | ||
`Plug.Conn.t` object and its params. | ||
## Example | ||
# Will call the no_resource/2 function on your handler | ||
plug Guardian.Plug.EnsureAuthenticated, handler: SomeModule | ||
# look in the :secret location. | ||
plug Guardian.Plug.EnsureAuthenticated, handler: SomeModule, key: :secret | ||
If the handler option is not passed, `Guardian.Plug.ErrorHandler` will provide | ||
the default behavior. | ||
""" | ||
require Logger | ||
import Plug.Conn | ||
|
||
@doc false | ||
def init(opts) do | ||
opts = Enum.into(opts, %{}) | ||
handler = build_handler_tuple(opts) | ||
|
||
%{ | ||
handler: handler, | ||
key: Map.get(opts, :key, :default) | ||
} | ||
end | ||
|
||
@doc false | ||
def call(conn, opts) do | ||
key = Map.get(opts, :key, :default) | ||
|
||
case Guardian.Plug.current_resource(conn, key) do | ||
nil -> handle_error(conn, opts) | ||
_ -> conn | ||
end | ||
end | ||
|
||
defp handle_error(%Plug.Conn{params: params} = conn, opts) do | ||
conn = conn |> assign(:guardian_failure, :no_resource) |> halt | ||
params = Map.merge(params, %{reason: :no_resource}) | ||
|
||
{mod, meth} = Map.get(opts, :handler) | ||
|
||
apply(mod, meth, [conn, params]) | ||
end | ||
|
||
defp build_handler_tuple(%{handler: mod}) do | ||
{mod, :no_resource} | ||
end | ||
defp build_handler_tuple(%{on_failure: {mod, fun}}) do | ||
_ = Logger.warn(":on_failure is deprecated. Use the :handler option instead") | ||
{mod, fun} | ||
end | ||
defp build_handler_tuple(_) do | ||
{Guardian.Plug.ErrorHandler, :no_resource} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
defmodule Guardian.Plug.EnsureResourceTest do | ||
@moduledoc false | ||
use ExUnit.Case, async: true | ||
use Plug.Test | ||
import ExUnit.CaptureLog | ||
import Guardian.TestHelper | ||
|
||
alias Guardian.Plug.EnsureResource | ||
|
||
defmodule TestHandler do | ||
@moduledoc false | ||
|
||
def no_resource(conn, _) do | ||
conn | ||
|> Plug.Conn.assign(:guardian_spec, :no_resource) | ||
|> Plug.Conn.send_resp(403, "Unauthorized") | ||
end | ||
end | ||
|
||
setup do | ||
conn = conn(:get, "/foo") | ||
{:ok, %{conn: conn}} | ||
end | ||
|
||
test "init/1 sets the handler option to the module that's passed in" do | ||
%{handler: handler_opts} = EnsureResource.init(handler: TestHandler) | ||
|
||
assert handler_opts == {TestHandler, :no_resource} | ||
end | ||
|
||
test "init/1 sets the handler option to the value of on_failure" do | ||
fun = fn -> | ||
%{handler: handler_opts} = EnsureResource.init( | ||
on_failure: {TestHandler, :custom_failure_method} | ||
) | ||
|
||
assert handler_opts == {TestHandler, :custom_failure_method} | ||
end | ||
|
||
assert capture_log([level: :warn], fun) =~ ":on_failure is deprecated" | ||
end | ||
|
||
test "init/1 defaults the handler option to Guardian.Plug.ErrorHandler" do | ||
%{handler: handler_opts} = EnsureResource.init %{} | ||
|
||
assert handler_opts == {Guardian.Plug.ErrorHandler, :no_resource} | ||
end | ||
|
||
test "init/1 with default options" do | ||
options = EnsureResource.init %{} | ||
|
||
assert options == %{ | ||
handler: {Guardian.Plug.ErrorHandler, :no_resource}, | ||
key: :default | ||
} | ||
end | ||
|
||
test "with a resource already set doesn't call no_resource for default key", %{conn: conn} do | ||
ensured_conn = | ||
conn | ||
|> Guardian.Plug.set_current_resource(:the_resource) | ||
|> run_plug(EnsureResource, handler: TestHandler) | ||
|
||
refute must_have_resource(ensured_conn) | ||
end | ||
|
||
test "with a resource already set doesn't call no_resource for key", %{conn: conn} do | ||
ensured_conn = | ||
conn | ||
|> Guardian.Plug.set_current_resource(:the_resource, :secret) | ||
|> run_plug(EnsureResource, handler: TestHandler, key: :secret) | ||
|
||
refute must_have_resource(ensured_conn) | ||
end | ||
|
||
test "with no resource set calls no_resource for default key", %{conn: conn} do | ||
ensured_conn = run_plug( | ||
conn, | ||
EnsureResource, | ||
handler: TestHandler | ||
) | ||
|
||
assert must_have_resource(ensured_conn) | ||
end | ||
|
||
test "with no resource set calls no_resource for key", %{conn: conn} do | ||
ensured_conn = run_plug( | ||
conn, | ||
EnsureResource, | ||
handler: TestHandler, | ||
key: :secret | ||
) | ||
|
||
assert must_have_resource(ensured_conn) | ||
end | ||
|
||
test "it halts the connection", %{conn: conn} do | ||
ensured_conn = run_plug( | ||
conn, | ||
EnsureResource, | ||
handler: TestHandler, | ||
key: :secret | ||
) | ||
|
||
assert ensured_conn.halted | ||
end | ||
|
||
defp must_have_resource(conn) do | ||
conn.assigns[:guardian_spec] == :no_resource | ||
end | ||
end |