Skip to content

Instantly share code, notes, and snippets.

@mileszs
Created October 4, 2016 16:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mileszs/adaa26e44d64604e8951e9b3077759ab to your computer and use it in GitHub Desktop.
Save mileszs/adaa26e44d64604e8951e9b3077759ab to your computer and use it in GitHub Desktop.
Plug for authenticating via session or token
defmodule ElixirJobBoard.Plugs.AuthenticateJobPoster do
import Plug.Conn
import Phoenix.Controller, only: [put_flash: 3, redirect: 2]
alias ElixirJobBoard.Repo
alias ElixirJobBoard.User
def init(opts), do: opts
def call(conn, _opts) do
user = get_user_from_session_or_token(conn)
if user do
conn |> assign(:current_user, user)
else
conn
|> put_flash(:info, "You must be logged in.")
|> redirect(to: "/")
|> halt
end
end
defp get_user_from_session_or_token(conn) do
case conn.assigns[:current_user] do
nil -> find_user(conn, user_id_from_session(conn))
user -> user
end
end
defp user_id_from_session(conn) do
get_session(conn, :current_user)
end
defp find_user(conn, nil) do
conn = conn |> fetch_query_params()
find_user_by_token(conn.query_params["token"])
end
defp find_user(conn, id) do
Repo.get(User, id)
end
defp find_user_by_token(nil), do: nil
defp find_user_by_token(token) do
Repo.get_by(User, token: token)
end
end
defmodule ElixirJobBoard.Plugs.AuthenticateJobPosterTest do
use ElixirJobBoard.ConnCase
import ElixirJobBoard.Factory
@session Plug.Session.init([
store: :cookie,
key: "_app",
encryption_salt: "secret",
signing_salt: "secret",
encrypt: false
])
test "user is redirected when current_user is not assigned and token is not present" do
job = insert(:job)
conn = build_conn(:get, "/jobs/#{job.id}/edit", "")
|> setup_session()
|> ElixirJobBoard.Plugs.AuthenticateJobPoster.call(%{})
assert redirected_to(conn) == "/"
end
test "user is redirected when current_user is not assigned and token doesn't match a user" do
job = insert(:job)
token = String.duplicate("abcdefgh", 8)
conn = build_conn(:get, "/jobs/#{job.id}/edit?token=#{token}", "")
|> setup_session()
|> ElixirJobBoard.Plugs.AuthenticateJobPoster.call(%{})
assert redirected_to(conn) == "/"
end
test "user passes through when current_user is assigned" do
user = insert(:user)
job = insert(:job)
conn = build_conn(:get, "/jobs/#{job.id}/edit", "")
|> setup_session()
|> put_session(:current_user, user.id)
|> ElixirJobBoard.Plugs.AuthenticateJobPoster.call(%{})
assert conn.status != 302
end
test "user passes through when token is present and matches a user" do
token = String.duplicate("abcdefgh", 8)
insert(:user, token: token)
job = insert(:job)
conn = build_conn(:get, "/jobs/#{job.id}/edit?token=#{token}", "")
|> setup_session()
|> ElixirJobBoard.Plugs.AuthenticateJobPoster.call(%{})
assert conn.status != 302
end
defp setup_session(conn) do
conn
|> Map.put(:secret_key_base, String.duplicate("abcdefgh", 8))
|> Plug.Session.call(@session)
|> fetch_session()
|> fetch_flash()
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment