File size: 4,008 Bytes
936b397 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | defmodule PlausibleWeb.SSOController do
use PlausibleWeb, :controller
require Logger
alias Plausible.Auth
alias Plausible.Auth.SSO
alias PlausibleWeb.LoginPreference
alias PlausibleWeb.Router.Helpers, as: Routes
plug Plausible.Plugs.AuthorizeTeamAccess,
[:owner] when action in [:sso_settings]
plug Plausible.Plugs.AuthorizeTeamAccess,
[:owner, :admin] when action in [:team_sessions, :delete_session]
def login_form(conn, params) do
login_preference = LoginPreference.get(conn)
error = Phoenix.Flash.get(conn.assigns.flash, :login_error)
case {login_preference, params["prefer"], error} do
{nil, nil, nil} ->
redirect(conn, to: Routes.auth_path(conn, :login_form, return_to: params["return_to"]))
_ ->
render_auth_page(conn, "login_form.html",
autosubmit: params["autosubmit"] != nil,
heading: "Sign in with SSO"
)
end
end
def login(conn, %{"email" => email} = params) do
with :ok <- Auth.rate_limit(:login_ip, conn),
{:ok, %{sso_integration: integration}} <- SSO.Domains.lookup(email) do
redirect(conn,
to:
Routes.sso_path(
conn,
:saml_signin,
integration.identifier,
email: email,
return_to: params["return_to"]
)
)
else
{:error, :not_found} ->
conn
|> put_flash(
:login_error,
"We couldn't find a Single Sign-On account for that email."
)
|> redirect(to: Routes.sso_path(conn, :login_form))
{:error, {:rate_limit, _}} ->
Auth.log_failed_login_attempt("too many login attempts for #{email}")
render_error(
conn,
429,
"Too many login attempts. Wait a minute before trying again."
)
end
end
def provision_notice(conn, _params) do
render_auth_page(conn, "provision_notice.html", heading: "Single Sign-On required")
end
def provision_issue(conn, params) do
issue =
case params["issue"] do
"not_a_member" -> :not_a_member
"multiple_memberships" -> :multiple_memberships
"multiple_memberships_noforce" -> :multiple_memberships_noforce
"active_personal_team" -> :active_personal_team
"active_personal_team_noforce" -> :active_personal_team_noforce
_ -> :unknown
end
render_auth_page(conn, "provision_issue.html",
heading: "Single Sign-On required",
issue: issue
)
end
def saml_signin(conn, params) do
saml_adapter().signin(conn, params)
end
def saml_consume(conn, params) do
saml_adapter().consume(conn, params)
end
def csp_report(conn, _params) do
{:ok, body, conn} = Plug.Conn.read_body(conn)
Logger.error(body)
conn |> send_resp(200, "OK")
end
def cta(conn, _params) do
render(conn, :cta, layout: {PlausibleWeb.LayoutView, :settings})
end
def sso_settings(conn, _params) do
if Plausible.Teams.setup?(conn.assigns.current_team) and
Plausible.Billing.Feature.SSO.check_availability(conn.assigns.current_team) == :ok do
render(conn, :sso_settings,
layout: {PlausibleWeb.LayoutView, :settings},
connect_live_socket: true
)
else
conn
|> redirect(to: Routes.site_path(conn, :index))
end
end
def team_sessions(conn, _params) do
sso_sessions = Auth.UserSessions.list_sso_for_team(conn.assigns.current_team)
render(conn, :team_sessions,
layout: {PlausibleWeb.LayoutView, :settings},
sso_sessions: sso_sessions
)
end
def delete_session(conn, %{"session_id" => session_id}) do
current_team = conn.assigns.current_team
Auth.UserSessions.revoke_sso_by_id(current_team, session_id)
conn
|> put_flash(:success, "Session logged out successfully")
|> redirect(to: Routes.sso_path(conn, :team_sessions))
end
defp saml_adapter() do
Application.fetch_env!(:plausible, :sso_saml_adapter)
end
end
|