Persist login type preference (SSO/standard) (#5520)
* First pass: store login preference * Only set login preference if SSO is used * Change mock DNS to use port 5354 and `domain_id` for parameter * Make login forms use flash message for error passing --------- Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
This commit is contained in:
parent
a2ed1e04b1
commit
e56baeb272
8
Makefile
8
Makefile
|
|
@ -94,12 +94,12 @@ sso-stop:
|
||||||
docker remove idp
|
docker remove idp
|
||||||
|
|
||||||
generate-corefile:
|
generate-corefile:
|
||||||
$(call require, integration_id)
|
$(call require, domain_id)
|
||||||
integration_id=$(integration_id) envsubst < $(PWD)/extra/fixture/Corefile.template > $(PWD)/extra/fixture/Corefile.gen.$(integration_id)
|
domain_id=$(domain_id) envsubst < $(PWD)/extra/fixture/Corefile.template > $(PWD)/extra/fixture/Corefile.gen.$(domain_id)
|
||||||
|
|
||||||
mock-dns: generate-corefile
|
mock-dns: generate-corefile
|
||||||
$(call require, integration_id)
|
$(call require, domain_id)
|
||||||
docker run --rm -p 5353:53/udp -v $(PWD)/extra/fixture/Corefile.gen.$(integration_id):/Corefile coredns/coredns:latest -conf Corefile
|
docker run --rm -p 5354:53/udp -v $(PWD)/extra/fixture/Corefile.gen.$(domain_id):/Corefile coredns/coredns:latest -conf Corefile
|
||||||
|
|
||||||
loadtest-server:
|
loadtest-server:
|
||||||
@echo "Ensure your OTP installation is built with --enable-lock-counter"
|
@echo "Ensure your OTP installation is built with --enable-lock-counter"
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ SHOW_CITIES=true
|
||||||
PADDLE_VENDOR_AUTH_CODE=895e20d4efaec0575bb857f44b183217b332d9592e76e69b8a
|
PADDLE_VENDOR_AUTH_CODE=895e20d4efaec0575bb857f44b183217b332d9592e76e69b8a
|
||||||
PADDLE_VENDOR_ID=3942
|
PADDLE_VENDOR_ID=3942
|
||||||
SSO_ENABLED=true
|
SSO_ENABLED=true
|
||||||
SSO_VERIFICATION_NAMESERVERS=0.0.0.0:5353
|
SSO_VERIFICATION_NAMESERVERS=0.0.0.0:5354
|
||||||
|
|
||||||
GOOGLE_CLIENT_ID=875387135161-l8tp53dpt7fdhdg9m1pc3vl42si95rh0.apps.googleusercontent.com
|
GOOGLE_CLIENT_ID=875387135161-l8tp53dpt7fdhdg9m1pc3vl42si95rh0.apps.googleusercontent.com
|
||||||
GOOGLE_CLIENT_SECRET=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
|
GOOGLE_CLIENT_SECRET=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
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
. {
|
. {
|
||||||
bind 0.0.0.0
|
bind 0.0.0.0
|
||||||
template IN TXT plausible.test {
|
template IN TXT plausible.test {
|
||||||
answer "{{ .Name }} 60 IN TXT \"plausible-sso-verification=${integration_id}\""
|
answer "{{ .Name }} 60 IN TXT \"plausible-sso-verification=${domain_id}\""
|
||||||
fallthrough
|
fallthrough
|
||||||
}
|
}
|
||||||
log
|
log
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ defmodule PlausibleWeb.SSOController do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
alias Plausible.Auth.SSO
|
alias Plausible.Auth.SSO
|
||||||
|
alias PlausibleWeb.LoginPreference
|
||||||
|
|
||||||
alias PlausibleWeb.Router.Helpers, as: Routes
|
alias PlausibleWeb.Router.Helpers, as: Routes
|
||||||
|
|
||||||
|
|
@ -11,7 +12,16 @@ defmodule PlausibleWeb.SSOController do
|
||||||
[:owner] when action in [:sso_settings]
|
[:owner] when action in [:sso_settings]
|
||||||
|
|
||||||
def login_form(conn, params) do
|
def login_form(conn, params) do
|
||||||
render(conn, "login_form.html", error: params["error"])
|
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(conn, "login_form.html")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def login(conn, %{"email" => email} = params) do
|
def login(conn, %{"email" => email} = params) do
|
||||||
|
|
@ -29,7 +39,9 @@ defmodule PlausibleWeb.SSOController do
|
||||||
)
|
)
|
||||||
|
|
||||||
{:error, :not_found} ->
|
{:error, :not_found} ->
|
||||||
render(conn, "login_form.html", error: "Wrong email.")
|
conn
|
||||||
|
|> put_flash(:login_error, "Wrong email.")
|
||||||
|
|> redirect(to: Routes.sso_path(conn, :login_form))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,12 +48,10 @@ defmodule PlausibleWeb.SSO.FakeSAMLAdapter do
|
||||||
PlausibleWeb.UserAuth.log_in_user(conn, identity, params["return_to"])
|
PlausibleWeb.UserAuth.log_in_user(conn, identity, params["return_to"])
|
||||||
|
|
||||||
{:error, :not_found} ->
|
{:error, :not_found} ->
|
||||||
Phoenix.Controller.redirect(conn,
|
conn
|
||||||
to:
|
|> Phoenix.Controller.put_flash(:login_error, "Wrong email.")
|
||||||
Routes.sso_path(conn, :login_form,
|
|> Phoenix.Controller.redirect(
|
||||||
error: "Wrong email.",
|
to: Routes.sso_path(conn, :login_form, return_to: params["return_to"])
|
||||||
return_to: params["return_to"]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -50,12 +50,10 @@ defmodule PlausibleWeb.SSO.RealSAMLAdapter do
|
||||||
|> Phoenix.Controller.redirect(external: url)
|
|> Phoenix.Controller.redirect(external: url)
|
||||||
|
|
||||||
{:error, :not_found} ->
|
{:error, :not_found} ->
|
||||||
Phoenix.Controller.redirect(conn,
|
conn
|
||||||
to:
|
|> Phoenix.Controller.put_flash(:login_error, "Wrong email.")
|
||||||
Routes.sso_path(conn, :login_form,
|
|> Phoenix.Controller.redirect(
|
||||||
error: "Wrong email.",
|
to: Routes.sso_path(conn, :login_form, return_to: return_to)
|
||||||
return_to: return_to
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -72,9 +70,9 @@ defmodule PlausibleWeb.SSO.RealSAMLAdapter do
|
||||||
|> consume(integration_id, cookie, saml_response, relay_state)
|
|> consume(integration_id, cookie, saml_response, relay_state)
|
||||||
|
|
||||||
{:error, :session_expired} ->
|
{:error, :session_expired} ->
|
||||||
Phoenix.Controller.redirect(conn,
|
conn
|
||||||
to: Routes.sso_path(conn, :login_form, error: "Session expired.")
|
|> Phoenix.Controller.put_flash(:login_error, "Session expired.")
|
||||||
)
|
|> Phoenix.Controller.redirect(to: Routes.sso_path(conn, :login_form))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -105,12 +103,10 @@ defmodule PlausibleWeb.SSO.RealSAMLAdapter do
|
||||||
PlausibleWeb.UserAuth.log_in_user(conn, identity, cookie.return_to)
|
PlausibleWeb.UserAuth.log_in_user(conn, identity, cookie.return_to)
|
||||||
else
|
else
|
||||||
{:error, reason} ->
|
{:error, reason} ->
|
||||||
Phoenix.Controller.redirect(conn,
|
conn
|
||||||
to:
|
|> Phoenix.Controller.put_flash(:login_error, error_by_reason(reason))
|
||||||
Routes.sso_path(conn, :login_form,
|
|> Phoenix.Controller.redirect(
|
||||||
error: error_by_reason(reason),
|
to: Routes.sso_path(conn, :login_form, return_to: cookie.return_to)
|
||||||
return_to: cookie.return_to
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= if @conn.assigns[:error] do %>
|
<%= if login_error = Phoenix.Flash.get(@flash, :login_error) do %>
|
||||||
<div class="text-red-500 mt-4">{@conn.assigns[:error]}</div>
|
<div class="text-red-500 mt-4">{login_error}</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<.input type="hidden" field={f[:return_to]} />
|
<.input type="hidden" field={f[:return_to]} />
|
||||||
|
|
@ -33,7 +33,10 @@
|
||||||
<:item>
|
<:item>
|
||||||
Have a standard account?
|
Have a standard account?
|
||||||
<.styled_link href={
|
<.styled_link href={
|
||||||
Routes.auth_path(@conn, :login_form, return_to: @conn.params["return_to"])
|
Routes.auth_path(@conn, :login_form,
|
||||||
|
return_to: @conn.params["return_to"],
|
||||||
|
prefer: "manual"
|
||||||
|
)
|
||||||
}>
|
}>
|
||||||
Log in here
|
Log in here
|
||||||
</.styled_link>
|
</.styled_link>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
defmodule PlausibleWeb.AuthController do
|
defmodule PlausibleWeb.AuthController do
|
||||||
use PlausibleWeb, :controller
|
use PlausibleWeb, :controller
|
||||||
use Plausible.Repo
|
use Plausible.Repo
|
||||||
|
use Plausible
|
||||||
|
|
||||||
alias Plausible.Auth
|
alias Plausible.Auth
|
||||||
alias Plausible.Teams
|
alias Plausible.Teams
|
||||||
alias PlausibleWeb.TwoFactor
|
alias PlausibleWeb.TwoFactor
|
||||||
alias PlausibleWeb.UserAuth
|
alias PlausibleWeb.UserAuth
|
||||||
|
alias PlausibleWeb.LoginPreference
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
@ -227,9 +229,28 @@ defmodule PlausibleWeb.AuthController do
|
||||||
|> redirect(to: Routes.auth_path(conn, :login_form))
|
|> redirect(to: Routes.auth_path(conn, :login_form))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
on_ee do
|
||||||
|
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
|
||||||
|
{"sso", nil, nil} ->
|
||||||
|
if Plausible.sso_enabled?() do
|
||||||
|
redirect(conn, to: Routes.sso_path(conn, :login_form, return_to: params["return_to"]))
|
||||||
|
else
|
||||||
|
render(conn, "login_form.html")
|
||||||
|
end
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
render(conn, "login_form.html")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
def login_form(conn, _params) do
|
def login_form(conn, _params) do
|
||||||
render(conn, "login_form.html")
|
render(conn, "login_form.html")
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def login(conn, %{"user" => params}) do
|
def login(conn, %{"user" => params}) do
|
||||||
login(conn, params)
|
login(conn, params)
|
||||||
|
|
@ -268,18 +289,24 @@ defmodule PlausibleWeb.AuthController do
|
||||||
params["return_to"]
|
params["return_to"]
|
||||||
end
|
end
|
||||||
|
|
||||||
UserAuth.log_in_user(conn, user, redirect_path)
|
conn
|
||||||
|
|> LoginPreference.clear()
|
||||||
|
|> UserAuth.log_in_user(user, redirect_path)
|
||||||
else
|
else
|
||||||
{:error, :wrong_password} ->
|
{:error, :wrong_password} ->
|
||||||
maybe_log_failed_login_attempts("wrong password for #{email}")
|
maybe_log_failed_login_attempts("wrong password for #{email}")
|
||||||
|
|
||||||
render(conn, "login_form.html", error: "Wrong email or password. Please try again.")
|
conn
|
||||||
|
|> put_flash(:login_error, "Wrong email or password. Please try again.")
|
||||||
|
|> render("login_form.html")
|
||||||
|
|
||||||
{:error, :user_not_found} ->
|
{:error, :user_not_found} ->
|
||||||
maybe_log_failed_login_attempts("user not found for #{email}")
|
maybe_log_failed_login_attempts("user not found for #{email}")
|
||||||
Plausible.Auth.Password.dummy_calculation()
|
Plausible.Auth.Password.dummy_calculation()
|
||||||
|
|
||||||
render(conn, "login_form.html", error: "Wrong email or password. Please try again.")
|
conn
|
||||||
|
|> put_flash(:login_error, "Wrong email or password. Please try again.")
|
||||||
|
|> render("login_form.html")
|
||||||
|
|
||||||
{:error, {:rate_limit, _}} ->
|
{:error, {:rate_limit, _}} ->
|
||||||
maybe_log_failed_login_attempts("too many login attempts for #{email}")
|
maybe_log_failed_login_attempts("too many login attempts for #{email}")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
defmodule PlausibleWeb.LoginPreference do
|
||||||
|
@moduledoc """
|
||||||
|
Functions for managing user login preference cookies.
|
||||||
|
|
||||||
|
This module handles storing and retrieving the user's preferred login method
|
||||||
|
(standard or SSO) to provide a better user experience by showing their
|
||||||
|
preferred option first.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@cookie_name "login_preference"
|
||||||
|
@cookie_max_age 60 * 60 * 24 * 365
|
||||||
|
|
||||||
|
@spec set_sso(Plug.Conn.t()) :: Plug.Conn.t()
|
||||||
|
def set_sso(conn) do
|
||||||
|
secure_cookie = PlausibleWeb.Endpoint.secure_cookie?()
|
||||||
|
|
||||||
|
Plug.Conn.put_resp_cookie(conn, @cookie_name, "sso",
|
||||||
|
http_only: true,
|
||||||
|
secure: secure_cookie,
|
||||||
|
max_age: @cookie_max_age,
|
||||||
|
same_site: "Lax"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec clear(Plug.Conn.t()) :: Plug.Conn.t()
|
||||||
|
def clear(conn) do
|
||||||
|
Plug.Conn.delete_resp_cookie(conn, @cookie_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec get(Plug.Conn.t()) :: String.t() | nil
|
||||||
|
def get(conn) do
|
||||||
|
case Plug.Conn.fetch_cookies(conn) do
|
||||||
|
%{cookies: %{@cookie_name => "sso"}} ->
|
||||||
|
"sso"
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -29,8 +29,8 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= if @conn.assigns[:error] do %>
|
<%= if login_error = Phoenix.Flash.get(@flash, :login_error) do %>
|
||||||
<div class="text-red-500 mt-4">{@conn.assigns[:error]}</div>
|
<div class="text-red-500 mt-4">{login_error}</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<.input type="hidden" field={f[:return_to]} />
|
<.input type="hidden" field={f[:return_to]} />
|
||||||
|
|
@ -53,7 +53,10 @@
|
||||||
<%= on_ee do %>
|
<%= on_ee do %>
|
||||||
Have a Single Sign-on account?
|
Have a Single Sign-on account?
|
||||||
<.styled_link href={
|
<.styled_link href={
|
||||||
Routes.sso_path(@conn, :login_form, return_to: @conn.params["return_to"])
|
Routes.sso_path(@conn, :login_form,
|
||||||
|
return_to: @conn.params["return_to"],
|
||||||
|
prefer: "manual"
|
||||||
|
)
|
||||||
}>
|
}>
|
||||||
Sign in here
|
Sign in here
|
||||||
</.styled_link>
|
</.styled_link>
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,16 @@ defmodule PlausibleWeb.UserAuth do
|
||||||
conn
|
conn
|
||||||
|> set_user_token(session.token)
|
|> set_user_token(session.token)
|
||||||
|> Plug.Conn.put_session("current_team_id", team.identifier)
|
|> Plug.Conn.put_session("current_team_id", team.identifier)
|
||||||
|
|> PlausibleWeb.LoginPreference.set_sso()
|
||||||
|> set_logged_in_cookie()
|
|> set_logged_in_cookie()
|
||||||
|> Phoenix.Controller.redirect(to: redirect_to)
|
|> Phoenix.Controller.redirect(to: redirect_to)
|
||||||
|
|
||||||
{:error, :integration_not_found} ->
|
{:error, :integration_not_found} ->
|
||||||
conn
|
conn
|
||||||
|> log_out_user()
|
|> log_out_user()
|
||||||
|
|> Phoenix.Controller.put_flash(:login_error, "Wrong email.")
|
||||||
|> Phoenix.Controller.redirect(
|
|> Phoenix.Controller.redirect(
|
||||||
to:
|
to: Routes.sso_path(conn, :login_form, return_to: redirect_path)
|
||||||
Routes.sso_path(conn, :login_form, error: "Wrong email.", return_to: redirect_path)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
{:error, :over_limit} ->
|
{:error, :over_limit} ->
|
||||||
|
|
@ -60,8 +61,9 @@ defmodule PlausibleWeb.UserAuth do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> log_out_user()
|
|> log_out_user()
|
||||||
|
|> Phoenix.Controller.put_flash(:login_error, error)
|
||||||
|> Phoenix.Controller.redirect(
|
|> Phoenix.Controller.redirect(
|
||||||
to: Routes.sso_path(conn, :login_form, error: error, return_to: redirect_path)
|
to: Routes.sso_path(conn, :login_form, return_to: redirect_path)
|
||||||
)
|
)
|
||||||
|
|
||||||
{:error, reason, team, user}
|
{:error, reason, team, user}
|
||||||
|
|
|
||||||
|
|
@ -488,6 +488,20 @@ defmodule PlausibleWeb.AuthControllerTest do
|
||||||
|
|
||||||
assert input_value == "/dummy.site"
|
assert input_value == "/dummy.site"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag :ee_only
|
||||||
|
test "redirects to sso login if preferred", %{conn: conn} do
|
||||||
|
conn = PlausibleWeb.LoginPreference.set_sso(conn)
|
||||||
|
conn = get(conn, "/login?return_to=foo")
|
||||||
|
assert redirected_to(conn, 302) == "/sso/login?return_to=foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
@tag :ee_only
|
||||||
|
test "keeps standard login form if preference manually overridden", %{conn: conn} do
|
||||||
|
conn = PlausibleWeb.LoginPreference.set_sso(conn)
|
||||||
|
conn = get(conn, "/login?prefer=manual")
|
||||||
|
assert html_response(conn, 200) =~ "Enter your account credentials"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "POST /login" do
|
describe "POST /login" do
|
||||||
|
|
|
||||||
|
|
@ -223,8 +223,9 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form, error: "Wrong email.", return_to: "/sites")
|
|
||||||
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) == "Wrong email."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -341,8 +342,9 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
|
|
||||||
conn = post(conn, Routes.sso_path(conn, :saml_consume, Ecto.UUID.generate()), params)
|
conn = post(conn, Routes.sso_path(conn, :saml_consume, Ecto.UUID.generate()), params)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form, error: "Wrong email.", return_to: "/sites")
|
|
||||||
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) == "Wrong email."
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects with error on mismatch of RelayState", %{
|
test "redirects with error on mismatch of RelayState", %{
|
||||||
|
|
@ -356,11 +358,10 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
|
|
||||||
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form,
|
|
||||||
error: "Authentication failed (reason: :invalid_relay_state).",
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) ==
|
||||||
return_to: "/sites"
|
"Authentication failed (reason: :invalid_relay_state)."
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects with error on missing relay state", %{
|
test "redirects with error on missing relay state", %{
|
||||||
|
|
@ -371,11 +372,10 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
|
|
||||||
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form,
|
|
||||||
error: "Authentication failed (reason: :invalid_relay_state).",
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) ==
|
||||||
return_to: "/sites"
|
"Authentication failed (reason: :invalid_relay_state)."
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects with error on malformed assertion", %{
|
test "redirects with error on malformed assertion", %{
|
||||||
|
|
@ -390,11 +390,10 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
|
|
||||||
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form,
|
|
||||||
error: "Authentication failed (reason: :base64_decoding_failed).",
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) ==
|
||||||
return_to: "/sites"
|
"Authentication failed (reason: :base64_decoding_failed)."
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects with error on malformed certificate in config (should not happen)", %{
|
test "redirects with error on malformed certificate in config (should not happen)", %{
|
||||||
|
|
@ -417,11 +416,10 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
|
|
||||||
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form,
|
|
||||||
error: "Authentication failed (reason: :malformed_certificate).",
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) ==
|
||||||
return_to: "/sites"
|
"Authentication failed (reason: :malformed_certificate)."
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects with error on mismatched certificate in config", %{
|
test "redirects with error on mismatched certificate in config", %{
|
||||||
|
|
@ -438,11 +436,10 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
|
|
||||||
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form,
|
|
||||||
error: "Authentication failed (reason: :digest_verification_failed).",
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) ==
|
||||||
return_to: "/sites"
|
"Authentication failed (reason: :digest_verification_failed)."
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects with error on missing email attribute in assertion", %{
|
test "redirects with error on missing email attribute in assertion", %{
|
||||||
|
|
@ -457,11 +454,10 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
|
|
||||||
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form,
|
|
||||||
error: "Authentication failed (reason: :missing_email_attribute).",
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) ==
|
||||||
return_to: "/sites"
|
"Authentication failed (reason: :missing_email_attribute)."
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects with error on invalid email attribute in assertion", %{
|
test "redirects with error on invalid email attribute in assertion", %{
|
||||||
|
|
@ -476,11 +472,10 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
|
|
||||||
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form,
|
|
||||||
error: "Authentication failed (reason: :invalid_email_attribute).",
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) ==
|
||||||
return_to: "/sites"
|
"Authentication failed (reason: :invalid_email_attribute)."
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects with error on missing name attributes in assertion", %{
|
test "redirects with error on missing name attributes in assertion", %{
|
||||||
|
|
@ -495,11 +490,10 @@ defmodule PlausibleWeb.SSOControllerSyncTest do
|
||||||
|
|
||||||
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
conn = post(conn, Routes.sso_path(conn, :saml_consume, integration.identifier), params)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form,
|
|
||||||
error: "Authentication failed (reason: :missing_name_attributes).",
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) ==
|
||||||
return_to: "/sites"
|
"Authentication failed (reason: :missing_name_attributes)."
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ defmodule PlausibleWeb.SSOControllerTest do
|
||||||
|
|
||||||
describe "login_form/2" do
|
describe "login_form/2" do
|
||||||
test "renders login view", %{conn: conn} do
|
test "renders login view", %{conn: conn} do
|
||||||
conn = get(conn, Routes.sso_path(conn, :login_form))
|
conn = get(conn, Routes.sso_path(conn, :login_form, prefer: "sso"))
|
||||||
|
|
||||||
assert html = html_response(conn, 200)
|
assert html = html_response(conn, 200)
|
||||||
|
|
||||||
|
|
@ -34,10 +34,27 @@ defmodule PlausibleWeb.SSOControllerTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "passes return_to parameter to form", %{conn: conn} do
|
test "passes return_to parameter to form", %{conn: conn} do
|
||||||
|
conn = get(conn, Routes.sso_path(conn, :login_form, return_to: "/sites", prefer: "sso"))
|
||||||
|
|
||||||
|
assert html = html_response(conn, 200)
|
||||||
|
|
||||||
|
assert text_of_attr(html, "input[name=return_to]", "value") == "/sites"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders error if provided in login_error flash message", %{conn: conn} do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> init_session()
|
||||||
|
|> fetch_session()
|
||||||
|
|> fetch_flash()
|
||||||
|
|> put_flash(:login_error, "Wrong email.")
|
||||||
|
|
||||||
conn = get(conn, Routes.sso_path(conn, :login_form, return_to: "/sites"))
|
conn = get(conn, Routes.sso_path(conn, :login_form, return_to: "/sites"))
|
||||||
|
|
||||||
assert html = html_response(conn, 200)
|
assert html = html_response(conn, 200)
|
||||||
|
|
||||||
|
assert html =~ "Wrong email."
|
||||||
|
assert element_exists?(html, "input[name=email]")
|
||||||
assert text_of_attr(html, "input[name=return_to]", "value") == "/sites"
|
assert text_of_attr(html, "input[name=return_to]", "value") == "/sites"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -83,11 +100,9 @@ defmodule PlausibleWeb.SSOControllerTest do
|
||||||
"return_to" => "/sites"
|
"return_to" => "/sites"
|
||||||
})
|
})
|
||||||
|
|
||||||
assert html = html_response(conn, 200)
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form)
|
||||||
|
|
||||||
assert html =~ "Wrong email."
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) == "Wrong email."
|
||||||
assert element_exists?(html, "input[name=email]")
|
|
||||||
assert text_of_attr(html, "input[name=return_to]", "value") == "/sites"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -177,8 +192,9 @@ defmodule PlausibleWeb.SSOControllerTest do
|
||||||
"return_to" => "/sites"
|
"return_to" => "/sites"
|
||||||
})
|
})
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "/sites")
|
||||||
Routes.sso_path(conn, :login_form, error: "Wrong email.", return_to: "/sites")
|
|
||||||
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) == "Wrong email."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,12 +140,14 @@ defmodule PlausibleWeb.UserAuthTest do
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|> init_session()
|
|> init_session()
|
||||||
|
|> fetch_flash()
|
||||||
|> UserAuth.log_in_user(identity)
|
|> UserAuth.log_in_user(identity)
|
||||||
|
|
||||||
assert %{sessions: []} = user |> Repo.reload!() |> Repo.preload(:sessions)
|
assert %{sessions: []} = user |> Repo.reload!() |> Repo.preload(:sessions)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "")
|
||||||
Routes.sso_path(conn, :login_form, error: "Wrong email.", return_to: "")
|
|
||||||
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) == "Wrong email."
|
||||||
|
|
||||||
assert conn.private[:plug_session_info] == :renew
|
assert conn.private[:plug_session_info] == :renew
|
||||||
refute get_session(conn, :user_token)
|
refute get_session(conn, :user_token)
|
||||||
|
|
@ -170,15 +172,15 @@ defmodule PlausibleWeb.UserAuthTest do
|
||||||
conn =
|
conn =
|
||||||
conn
|
conn
|
||||||
|> init_session()
|
|> init_session()
|
||||||
|
|> fetch_flash()
|
||||||
|> UserAuth.log_in_user(identity)
|
|> UserAuth.log_in_user(identity)
|
||||||
|
|
||||||
assert %{sessions: []} = user |> Repo.reload!() |> Repo.preload(:sessions)
|
assert %{sessions: []} = user |> Repo.reload!() |> Repo.preload(:sessions)
|
||||||
|
|
||||||
assert redirected_to(conn, 302) ==
|
assert redirected_to(conn, 302) == Routes.sso_path(conn, :login_form, return_to: "")
|
||||||
Routes.sso_path(conn, :login_form,
|
|
||||||
error: "Team can't accept more members. Please contact the owner.",
|
assert Phoenix.Flash.get(conn.assigns.flash, :login_error) ==
|
||||||
return_to: ""
|
"Team can't accept more members. Please contact the owner."
|
||||||
)
|
|
||||||
|
|
||||||
assert conn.private[:plug_session_info] == :renew
|
assert conn.private[:plug_session_info] == :renew
|
||||||
refute get_session(conn, :user_token)
|
refute get_session(conn, :user_token)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue