Permissions not halting on unauthorized
Lazarus404 opened this issue · 1 comments
Lazarus404 commented
Okay, so, bearing in mind I'm upgrading from 0.14 to 2.0, so I may be doing something wrong. However, I have a permissions check at the top of each controller (different permissions for different actions). This may look like:
plug(Permissions, [one_of: [%{sys: [:sys]}]] when action in [:create, :update])
Now, in the :create
action, it might look like:
def create(conn, params, _current_user, _claims) do
with {:ok, %Account{id: id}} <- Repo.transaction(fn -> create_account(params) end) do
conn
|> put_status(:created)
|> json(%{status: "success", id: id})
else
e -> do_error(conn, e)
end
end
However, when running my test:
test "POST /api/account DOES NOT create a new account for non-sys user", ctx do
conn =
build_conn()
|> MyApp.Guardian.Plug.sign_in(ctx.admin, %{pem: User.perms(ctx.admin, :manager)})
|> post("/api/account", @valid_params)
assert conn.status == 401
end
I see the unauthorised error printed in the console, but then the action gets run, anyway:
{:unauthorized, :insufficient_permission}
1) test creating accounts POST /api/account DOES NOT create a new account for non-sys user (MyApp.AccountControllerTest)
test/api_web/controllers/account_controller_test.exs:99
** (Plug.Conn.AlreadySentError) the response was already sent
code: |> post("/api/account", @valid_params)
stacktrace:
(plug) lib/plug/conn.ex:372: Plug.Conn.put_status/2
(api) lib/api_web/controllers/account_controller.ex:45: MyAppWeb.AccountController.create/5
What I would expect is for the Permission
check to halt the Plug
stack. Do I have to add anything additional to the Permission
call, perhaps?
Lazarus404 commented
Dagnabbit. I found the answer from my own questioning :)
For those that read this with the same issue, you need to add halt
to your Error Handler. For instance:
defmodule MyApp.AuthErrorHandler do
import Plug.Conn
@behaviour Guardian.Plug.ErrorHandler
@impl Guardian.Plug.ErrorHandler
def auth_error(conn, {type, reason}, _opts) do
body = Poison.encode!(%{message: to_string(type)})
conn
|> put_resp_content_type("application/json")
|> send_resp(401, body)
|> halt()
end
end