Search code examples
elixirphoenix-framework

How test controller authorization


I have a controller similar to this simplified code:

defmodule Web.UserController do
  use Web, :controller

  alias App.User

  action_fallback Web.FallbackController

  def authorize(conn) do
    # in my code I have somo checks here

    conn
      |> send_resp(403, "")
      |> halt()
  end

  def index(conn, _params) do
    authorize(conn)

    users = User.all
    render(conn, "index.json", users: users)
  end
end
  test "lists all users", %{conn: conn} do
    conn = get(conn, Routes.user_path(conn, :index))
    users = User.all

    assert conn.halted
    assert json_response(conn, 403)
  end

When I check it with rest client it return 403 but in the test it returns 200. How I can test it?


Solution

  • The test is good, your code is not.

    your authorize function return a conn, but you never use it on the index function.

    When you request it with a rest client, the connection receives correctly the

    conn
    |> send_resp(403, "")
    

    But in ExUnit, it gets what index returns : render(conn, "index.json", users: users)

    Since you haven't use the conn that authorize(conn) returns

    My suggestion to fix this issue rapidly :

    defmodule Web.UserController do
      use Web, :controller
    
      alias App.User
    
      action_fallback Web.FallbackController
    
      def authorize(conn) do
        # in my code I have somo checks here
    
        :not_authorized
      end
    
      def index(conn, _params) do
        case authorize(conn) do
          :not_authorized -> 
            conn
              |> send_resp(403, "")
              |> halt()      # not necessary since send_resp already does it
          :authorized ->
            users = User.all
            render(conn, "index.json", users: users)
        end
      end
    end
    

    A better solution would be to make a Plug for authorization purpose, add it to a pipeline in your router, it will not reach your controller if the connection is not authorized.