towerops/lib/towerops_web/router.ex
Graham McIntire 853d548f82
Add superuser system with user impersonation for admin support
Implement comprehensive admin interface allowing designated superusers to view all users and organizations, impersonate users for debugging, and perform administrative operations. All superuser actions are tracked in audit logs for compliance.

Features:
- Superuser authentication with dedicated admin routes at /admin
- User impersonation with session state preservation
- Admin dashboard with system statistics
- User and organization management interfaces
- Comprehensive audit logging with IP tracking
- Visual impersonation banner with exit capability
- Security controls preventing self-impersonation and superuser-to-superuser impersonation

Database:
- Add is_superuser boolean field to users table
- Create audit_logs table for tracking sensitive operations
- Set graham@mcintire.me as initial superuser
2026-01-06 12:50:10 -06:00

141 lines
4.1 KiB
Elixir

defmodule ToweropsWeb.Router do
use ToweropsWeb, :router
import Phoenix.LiveDashboard.Router
import ToweropsWeb.UserAuth
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {ToweropsWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :fetch_current_scope_for_user
end
pipeline :api do
plug :accepts, ["json"]
end
# Health check endpoint for Kubernetes probes (no authentication required)
scope "/", ToweropsWeb do
get "/health", HealthController, :index
end
scope "/", ToweropsWeb do
pipe_through :browser
get "/", PageController, :home
end
# Other scopes may use custom stacks.
# scope "/api", ToweropsWeb do
# pipe_through :api
# end
# Enable LiveDashboard in production with authentication
scope "/dashboard" do
pipe_through [:browser, :require_authenticated_user]
live_dashboard "/", metrics: ToweropsWeb.Telemetry, ecto_repos: [Towerops.Repo]
end
# Enable Swoosh mailbox preview in development
if Application.compile_env(:towerops, :dev_routes) do
scope "/dev" do
pipe_through :browser
forward "/mailbox", Plug.Swoosh.MailboxPreview
end
end
## Authentication routes
scope "/", ToweropsWeb do
pipe_through [:browser, :redirect_if_user_is_authenticated]
get "/users/register", UserRegistrationController, :new
post "/users/register", UserRegistrationController, :create
end
scope "/", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user]
get "/users/settings", UserSettingsController, :edit
put "/users/settings", UserSettingsController, :update
get "/users/settings/confirm-email/:token", UserSettingsController, :confirm_email
end
scope "/", ToweropsWeb do
pipe_through [:browser]
get "/users/log-in", UserSessionController, :new
get "/users/log-in/:token", UserSessionController, :confirm
post "/users/log-in", UserSessionController, :create
delete "/users/log-out", UserSessionController, :delete
end
## Admin routes (superuser only)
scope "/", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user, :require_superuser]
post "/admin/impersonate/:user_id", AdminController, :start_impersonate
delete "/admin/impersonate", AdminController, :stop_impersonate
end
live_session :require_superuser,
on_mount: [
{ToweropsWeb.UserAuth, :require_authenticated_user},
{ToweropsWeb.UserAuth, :require_superuser}
] do
scope "/admin", ToweropsWeb.Admin do
pipe_through [:browser, :require_authenticated_user, :require_superuser]
live "/", DashboardLive, :index
live "/users", UserLive.Index, :index
live "/organizations", OrgLive.Index, :index
end
end
## Organization routes
live_session :require_authenticated_user,
on_mount: [{ToweropsWeb.UserAuth, :require_authenticated_user}] do
scope "/", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user]
live "/orgs", OrgLive.Index, :index
live "/orgs/new", OrgLive.New, :new
end
end
live_session :require_authenticated_user_and_organization,
on_mount: [
{ToweropsWeb.UserAuth, :require_authenticated_user},
{ToweropsWeb.UserAuth, :load_current_organization}
] do
scope "/orgs/:org_slug", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user, :load_current_organization]
live "/", DashboardLive, :index
# Site routes
live "/sites", SiteLive.Index, :index
live "/sites/new", SiteLive.Form, :new
live "/sites/:id", SiteLive.Show, :show
live "/sites/:id/edit", SiteLive.Form, :edit
# Equipment routes
live "/equipment", EquipmentLive.Index, :index
live "/equipment/new", EquipmentLive.Form, :new
live "/equipment/:id", EquipmentLive.Show, :show
live "/equipment/:id/edit", EquipmentLive.Form, :edit
live "/equipment/:id/graph/:sensor_type", GraphLive.Show, :show
# Alert routes
live "/alerts", AlertLive.Index, :index
end
end
end