68 lines
1.7 KiB
Elixir
68 lines
1.7 KiB
Elixir
defmodule ToweropsWeb.Plugs.AgentAuth do
|
|
@moduledoc """
|
|
Plug for authenticating remote agent API requests.
|
|
|
|
Validates Bearer tokens in the Authorization header and assigns the agent token
|
|
to the connection. Also updates the agent's last_seen_at timestamp asynchronously.
|
|
"""
|
|
|
|
import Phoenix.Controller
|
|
import Plug.Conn
|
|
|
|
alias Ecto.Adapters.SQL.Sandbox
|
|
alias Towerops.Agents
|
|
|
|
@doc """
|
|
Initializes the plug with options.
|
|
"""
|
|
def init(opts), do: opts
|
|
|
|
@doc """
|
|
Validates the agent token from the Authorization header.
|
|
|
|
If valid, assigns :current_agent_token to the connection and updates heartbeat.
|
|
If invalid or missing, returns 401 Unauthorized and halts the connection.
|
|
"""
|
|
def call(conn, _opts) do
|
|
case get_req_header(conn, "authorization") do
|
|
["Bearer " <> token] ->
|
|
case Agents.verify_agent_token(token) do
|
|
{:ok, agent_token} ->
|
|
conn
|
|
|> assign(:current_agent_token, agent_token)
|
|
|> update_heartbeat(agent_token)
|
|
|
|
{:error, _} ->
|
|
unauthorized(conn)
|
|
end
|
|
|
|
_ ->
|
|
unauthorized(conn)
|
|
end
|
|
end
|
|
|
|
defp update_heartbeat(conn, agent_token) do
|
|
ip = to_string(:inet_parse.ntoa(conn.remote_ip))
|
|
|
|
parent = self()
|
|
|
|
Task.start(fn ->
|
|
# Allow this task to use the test database sandbox
|
|
if Application.get_env(:towerops, :sql_sandbox) do
|
|
Sandbox.allow(Towerops.Repo, parent, self())
|
|
end
|
|
|
|
Agents.update_agent_token_heartbeat(agent_token.id, ip)
|
|
end)
|
|
|
|
conn
|
|
end
|
|
|
|
defp unauthorized(conn) do
|
|
conn
|
|
|> put_status(:unauthorized)
|
|
|> put_view(json: ToweropsWeb.ErrorJSON)
|
|
|> render(:"401")
|
|
|> halt()
|
|
end
|
|
end
|