55 lines
1.4 KiB
Elixir
55 lines
1.4 KiB
Elixir
defmodule BallsPDS.Plug.WACAuthenticationPlug do
|
|
import Plug.Conn
|
|
alias BallsPDS.JWT
|
|
alias BallsPDS.WAC
|
|
|
|
def init(opts), do: opts
|
|
|
|
def call(conn, _opts) do
|
|
with {:subject, nil} <- {:subject, conn.assigns[:subject]},
|
|
{:info, {:ok, subject}} <- {:info, verify_auth_info(conn)} do
|
|
conn
|
|
|> assign(:subject, subject)
|
|
else
|
|
{:subject, _} ->
|
|
# Already set somewhere, ignore
|
|
conn
|
|
end
|
|
end
|
|
|
|
defp verify_auth_info(conn) do
|
|
with {:extract, {:ok, jwt}} when not is_nil(jwt) <- {:extract, extract_jwt(conn)},
|
|
{:jwk, {:ok, jwk}} <- {:jwk, get_jwk(jwt)},
|
|
{:verify, {:ok, %{"sub" => subject}}} <- {:verify, JWT.verify_jwt(jwt, jwk)} do
|
|
{:ok, subject}
|
|
else
|
|
{:extract, {:ok, nil}} ->
|
|
# No auth provided, okay for public stuff.
|
|
{:ok, nil}
|
|
|
|
{:verify, {:error, _} = error} ->
|
|
error
|
|
end
|
|
end
|
|
|
|
defp get_jwk(jwt) do
|
|
with {:peek, {:ok, %{:subject => subject, :id => key_id}}} <-
|
|
{:peek, JWT.extract_key_info(jwt)} do
|
|
if subject == Application.get_env(:balls_pds, :owner_ap_id) do
|
|
{:ok, JWT.generate_my_jwk()}
|
|
else
|
|
WAC.cached_query_public_key(subject, key_id)
|
|
end
|
|
end
|
|
end
|
|
|
|
defp extract_jwt(conn) do
|
|
with ["Bearer " <> jwt] <- get_req_header(conn, "authorization") do
|
|
{:ok, jwt}
|
|
else
|
|
[] -> {:ok, nil}
|
|
unexpected_result -> {:error, unexpected_result}
|
|
end
|
|
end
|
|
end
|