Implement token verification and revocation

This commit is contained in:
Nat 2023-06-14 10:02:10 -07:00
parent 9a6b7eb518
commit 9657ab818c
Signed by: nat
GPG Key ID: B53AB05285D710D6
2 changed files with 35 additions and 8 deletions

View File

@ -47,17 +47,33 @@ defmodule HostasWeb.Auth.TokenController do
@doc """ @doc """
Responds with 200 OK if the requester's `Bearing` header Responds with 200 OK if the requester's `Bearing` header
contains a valid, non-expired API token contains a valid, non-expired API token, along with a
payload with an `expires` key detailing when the key
expires.
""" """
def verify(_conn, _params) do def verify(conn, _params) do
:ok conn
|> put_status(200)
|> json(%{"expires" => conn.assigns[:token].expires})
end end
@doc """ @doc """
Deletes the token the requester used in the `Bearing` header Deletes the token the requester used in the `Bearing` header
""" """
def revoke(_conn, _params) do def revoke(conn, %{"id" => id_param}) do
:ok with {:parsed_id, {id, ""}} <- {:parsed_id, Integer.parse(id_param, 10)},
{:ok, token} <- fetch_token(id, conn),
{:can_access, true} <- {:can_access, token.denizen_id == conn.assigns[:denizen].id} do
Repo.delete_all(from t in Token, where: t.id == ^token.id)
conn
|> send_resp(200, "")
else
_ ->
conn
|> put_status(404)
|> json(%{"error" => "Token not found"})
end
end end
@doc """ @doc """
@ -67,4 +83,15 @@ defmodule HostasWeb.Auth.TokenController do
def renew(_conn, _params) do def renew(_conn, _params) do
:ok :ok
end end
defp fetch_token(id, conn) do
if id == conn.assigns[:token].id do
{:ok, conn.assigns[:token]}
else
case Repo.one(from t in Token, where: t.id == ^id) do
nil -> {:error, :token_not_found}
token -> {:ok, token}
end
end
end
end end

View File

@ -32,7 +32,7 @@ defmodule HostasWeb.Auth.TokenControllerTest do
test "fails due to non-existant denizen", %{conn: conn} do test "fails due to non-existant denizen", %{conn: conn} do
conn = post(conn, ~p"/hostapi/auth/token", %{handle: "denizen", password: "password"}) conn = post(conn, ~p"/hostapi/auth/token", %{handle: "denizen", password: "password"})
assert json_response(conn, 404)["error"] == "No user with handle testuser" assert json_response(conn, 404)["error"] == "No user with handle denizen"
end end
test "fails due to missing fields", %{conn: conn} do test "fails due to missing fields", %{conn: conn} do
@ -70,7 +70,7 @@ defmodule HostasWeb.Auth.TokenControllerTest do
|> put_req_header("authorization", "Bearer unknown_credential") |> put_req_header("authorization", "Bearer unknown_credential")
|> get(~p"/hostapi/auth/token") |> get(~p"/hostapi/auth/token")
assert json_response(conn, 200)["error"] == "Token expired" assert json_response(conn, 401)["error"] == "API key not found"
end end
end end
@ -83,7 +83,7 @@ defmodule HostasWeb.Auth.TokenControllerTest do
|> put_req_header("authorization", "Bearer #{struct.token}") |> put_req_header("authorization", "Bearer #{struct.token}")
|> delete(~p"/hostapi/auth/token/#{struct.id}") |> delete(~p"/hostapi/auth/token/#{struct.id}")
assert json_response(conn, 200) assert response(conn, 200)
end end
test "fails because it's someone else's token", %{conn: conn} do test "fails because it's someone else's token", %{conn: conn} do