Improve oidc only mode (#474)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
## Description of the implemented changes The changes were: - [x] Bugfixing - [x] New Feature - [ ] Breaking Change - [x] Refactoring **OIDC-only mode improvements and UX tweaks (success toasts, unauthenticated redirect).** ## What has been changed? ### OIDC-only mode (new feature) - **Admin settings:** "Only OIDC sign-in" is an immediate toggle at the top of the OIDC section (no save button). Enabling it also turns off "Allow direct registration". When OIDC-only is on, the registration checkbox is disabled and shows a tooltip (DaisyUI `<.tooltip>`). - **Backend:** Password sign-in is forbidden via Ash policy (`OidcOnlyActive` check). Password registration is blocked via validation `OidcOnlyBlocksPasswordRegistration`. New plug `OidcOnlySignInRedirect`: when OIDC-only and OIDC are configured, GET `/sign-in` redirects to the OIDC flow; GET `/auth/user/password/sign_in_with_token` is rejected with redirect + flash. `AuthController.success/4` also rejects password sign-in when OIDC-only. - **Tests:** GlobalSettingsLive (OIDC-only UI), AuthController (redirect and password sign-in rejection), User authentication (register_with_password blocked when OIDC-only). ### UX / behaviour (no new feature flag) - **Success toasts:** Success flash messages auto-dismiss after 5 seconds via JS hook `FlashAutoDismiss` and optional `auto_clear_ms` on `<.flash>` (used for success in root layout and `flash_group`). - **Unauthenticated users:** Redirect to sign-in without the "You don't have permission to access this page" flash; that message is only shown to logged-in users who lack access. Logic in `LiveHelpers` and `CheckPagePermission` plug; test updated accordingly. ### Other - Layouts: comment about unprocessed join-request count no longer uses "TODO" (Credo). - Gettext: German translation for "Home" (Startseite); POT/PO kept in sync. - CHANGELOG: Unreleased section updated with the above. ## Definition of Done ### Code Quality - [x] No new technical depths - [x] Linting passed - [x] Documentation is added where needed (module docs, comments where non-obvious) ### Accessibility - [x] New elements are properly defined with html-tags (labels, aria-label on checkboxes) - [x] Colour contrast follows WCAG criteria (unchanged) - [x] Aria labels are added when needed (e.g. oidc-only and registration checkboxes) - [x] Everything is accessible by keyboard (toggles and buttons unchanged) - [x] Tab-Order is comprehensible - [x] All interactive elements have a visible focus (existing patterns) ### Testing - [x] Tests for new code are written (OIDC-only UI, auth controller, user auth; SMTP config builder and mailer) - [x] All tests pass - [ ] axe-core dev tools show no critical or major issues (not re-run for this PR; suggest spot-check on settings and sign-in) ## Additional Notes - **OIDC-only:** When the `OIDC_ONLY` env var is set, the toggle is read-only and shows "(From OIDC_ONLY)". When OIDC is not configured, the toggle is disabled. - **Invalidation:** Enabling OIDC-only sets `registration_enabled: false` in one update; disabling OIDC-only only updates `oidc_only` (registration left as-is). - **Review focus:** Plug order in router (OidcOnlySignInRedirect), policy/validation order in User, and that all OIDC-only paths (form, plug, controller) stay consistent. Reviewed-on: #474 Co-authored-by: Simon <s.thiessen@local-it.org> Co-committed-by: Simon <s.thiessen@local-it.org>
This commit is contained in:
parent
9b0f269ab6
commit
c381b86b5e
23 changed files with 579 additions and 54 deletions
|
|
@ -63,6 +63,11 @@ defmodule MvWeb.CoreComponents do
|
|||
values: [:info, :error, :success, :warning],
|
||||
doc: "used for styling and flash lookup"
|
||||
|
||||
attr :auto_clear_ms, :integer,
|
||||
default: nil,
|
||||
doc:
|
||||
"when set, flash is auto-dismissed after this many milliseconds (e.g. 5000 for success toasts)"
|
||||
|
||||
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the flash container"
|
||||
|
||||
slot :inner_block, doc: "the optional inner block that renders the flash message"
|
||||
|
|
@ -74,6 +79,9 @@ defmodule MvWeb.CoreComponents do
|
|||
<div
|
||||
:if={msg = render_slot(@inner_block) || Phoenix.Flash.get(@flash, @kind)}
|
||||
id={@id}
|
||||
phx-hook={@auto_clear_ms && "FlashAutoDismiss"}
|
||||
data-auto-clear-ms={@auto_clear_ms}
|
||||
data-clear-flash-key={@auto_clear_ms && @kind}
|
||||
phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")}
|
||||
role="alert"
|
||||
class="pointer-events-auto"
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ defmodule MvWeb.Layouts do
|
|||
aria-live="polite"
|
||||
class="z-50 toast toast-bottom toast-end flex flex-col gap-2 pointer-events-none"
|
||||
>
|
||||
<.flash kind={:success} flash={@flash} />
|
||||
<.flash kind={:success} flash={@flash} auto_clear_ms={5000} />
|
||||
<.flash kind={:warning} flash={@flash} />
|
||||
<.flash kind={:info} flash={@flash} />
|
||||
<.flash kind={:error} flash={@flash} />
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@
|
|||
aria-live="polite"
|
||||
class="z-50 flex flex-col gap-2 toast toast-bottom toast-end"
|
||||
>
|
||||
<.flash id="flash-success-root" kind={:success} flash={@flash} />
|
||||
<.flash id="flash-success-root" kind={:success} flash={@flash} auto_clear_ms={5000} />
|
||||
<.flash id="flash-warning-root" kind={:warning} flash={@flash} />
|
||||
<.flash id="flash-info-root" kind={:info} flash={@flash} />
|
||||
<.flash id="flash-error-root" kind={:error} flash={@flash} />
|
||||
|
|
|
|||
|
|
@ -15,8 +15,23 @@ defmodule MvWeb.AuthController do
|
|||
use AshAuthentication.Phoenix.Controller
|
||||
|
||||
alias Mv.Accounts.User.Errors.PasswordVerificationRequired
|
||||
alias Mv.Config
|
||||
|
||||
def success(conn, activity, user, _token) do
|
||||
def success(conn, {:password, :sign_in} = _activity, user, token) do
|
||||
if Config.oidc_only?() do
|
||||
conn
|
||||
|> put_flash(:error, gettext("Only sign-in via Single Sign-On (SSO) is allowed."))
|
||||
|> redirect(to: sign_in_path_after_oidc_failure())
|
||||
else
|
||||
success_continue(conn, {:password, :sign_in}, user, token)
|
||||
end
|
||||
end
|
||||
|
||||
def success(conn, activity, user, token) do
|
||||
success_continue(conn, activity, user, token)
|
||||
end
|
||||
|
||||
defp success_continue(conn, activity, user, _token) do
|
||||
return_to = get_session(conn, :return_to) || ~p"/"
|
||||
|
||||
message =
|
||||
|
|
@ -134,7 +149,7 @@ defmodule MvWeb.AuthController do
|
|||
_ ->
|
||||
conn
|
||||
|> put_flash(:error, gettext("Unable to authenticate with OIDC. Please try again."))
|
||||
|> redirect(to: ~p"/sign-in")
|
||||
|> redirect(to: sign_in_path_after_oidc_failure())
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -148,7 +163,7 @@ defmodule MvWeb.AuthController do
|
|||
:error,
|
||||
gettext("The authentication server is currently unavailable. Please try again later.")
|
||||
)
|
||||
|> redirect(to: ~p"/sign-in")
|
||||
|> redirect(to: sign_in_path_after_oidc_failure())
|
||||
end
|
||||
|
||||
# Handle Assent invalid response errors (configuration or malformed responses)
|
||||
|
|
@ -161,7 +176,7 @@ defmodule MvWeb.AuthController do
|
|||
:error,
|
||||
gettext("Authentication configuration error. Please contact the administrator.")
|
||||
)
|
||||
|> redirect(to: ~p"/sign-in")
|
||||
|> redirect(to: sign_in_path_after_oidc_failure())
|
||||
end
|
||||
|
||||
# Catch-all clause for any other error types
|
||||
|
|
@ -171,7 +186,7 @@ defmodule MvWeb.AuthController do
|
|||
|
||||
conn
|
||||
|> put_flash(:error, gettext("Unable to authenticate with OIDC. Please try again."))
|
||||
|> redirect(to: ~p"/sign-in")
|
||||
|> redirect(to: sign_in_path_after_oidc_failure())
|
||||
end
|
||||
|
||||
# Handle generic AuthenticationFailed errors
|
||||
|
|
@ -211,10 +226,14 @@ defmodule MvWeb.AuthController do
|
|||
|
||||
conn
|
||||
|> put_flash(:error, error_message)
|
||||
|> redirect(to: ~p"/sign-in")
|
||||
|> redirect(to: sign_in_path_after_oidc_failure())
|
||||
end
|
||||
end
|
||||
|
||||
# Path used when redirecting to sign-in after an OIDC failure. The query param tells
|
||||
# OidcOnlySignInRedirect to show the sign-in page instead of redirecting back to OIDC (avoids loop).
|
||||
defp sign_in_path_after_oidc_failure, do: "/sign-in?oidc_failed=1"
|
||||
|
||||
# Extract meaningful error message from Ash errors
|
||||
defp extract_meaningful_error_message(errors) do
|
||||
# Look for specific error messages in InvalidAttribute errors
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ defmodule MvWeb.GlobalSettingsLive do
|
|||
## Events
|
||||
- `validate` / `save` - Club settings form
|
||||
- `toggle_registration_enabled` - Enable/disable direct registration (/register)
|
||||
- `toggle_oidc_only` - Enable/disable OIDC-only sign-in (immediate, outside OIDC form)
|
||||
- `toggle_join_form_enabled` - Enable/disable the join form
|
||||
- `add_join_form_field` / `remove_join_form_field` - Manage join form fields
|
||||
- `toggle_join_form_field_required` - Toggle required flag per field
|
||||
|
|
@ -80,6 +81,7 @@ defmodule MvWeb.GlobalSettingsLive do
|
|||
|> assign(:oidc_admin_group_name_env_set, Mv.Config.oidc_admin_group_name_env_set?())
|
||||
|> assign(:oidc_groups_claim_env_set, Mv.Config.oidc_groups_claim_env_set?())
|
||||
|> assign(:oidc_only_env_set, Mv.Config.oidc_only_env_set?())
|
||||
|> assign(:oidc_only, Mv.Config.oidc_only?())
|
||||
|> assign(:oidc_configured, Mv.Config.oidc_configured?())
|
||||
|> assign(:oidc_client_secret_set, Mv.Config.oidc_client_secret_set?())
|
||||
|> assign(:registration_enabled, settings.registration_enabled != false)
|
||||
|
|
@ -625,11 +627,30 @@ defmodule MvWeb.GlobalSettingsLive do
|
|||
class="checkbox checkbox-sm"
|
||||
checked={@registration_enabled}
|
||||
phx-click="toggle_registration_enabled"
|
||||
disabled={@oidc_only}
|
||||
aria-label={gettext("Allow direct registration (/register)")}
|
||||
/>
|
||||
<label for="registration-enabled-checkbox" class="cursor-pointer font-medium">
|
||||
<label
|
||||
for="registration-enabled-checkbox"
|
||||
class={
|
||||
if @oidc_only, do: "cursor-not-allowed opacity-70", else: "cursor-pointer font-medium"
|
||||
}
|
||||
>
|
||||
{gettext("Allow direct registration (/register)")}
|
||||
</label>
|
||||
<%= if @oidc_only do %>
|
||||
<.tooltip
|
||||
content={gettext("Only OIDC sign-in is active. This option is disabled.")}
|
||||
position="top"
|
||||
>
|
||||
<span
|
||||
data-testid="oidc-only-registration-hint"
|
||||
class="cursor-help text-base-content/70"
|
||||
>
|
||||
ⓘ
|
||||
</span>
|
||||
</.tooltip>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<h3 class="font-medium mb-3">{gettext("OIDC (Single Sign-On)")}</h3>
|
||||
|
|
@ -638,6 +659,38 @@ defmodule MvWeb.GlobalSettingsLive do
|
|||
{gettext("Some values are set via environment variables. Those fields are read-only.")}
|
||||
</p>
|
||||
<% end %>
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="oidc-only-checkbox"
|
||||
data-testid="oidc-only-checkbox"
|
||||
class="checkbox checkbox-sm"
|
||||
checked={@oidc_only}
|
||||
phx-click="toggle_oidc_only"
|
||||
disabled={@oidc_only_env_set or not @oidc_configured}
|
||||
aria-label={gettext("Only OIDC sign-in (hide password login)")}
|
||||
/>
|
||||
<label
|
||||
for="oidc-only-checkbox"
|
||||
class={
|
||||
if @oidc_only_env_set or not @oidc_configured,
|
||||
do: "cursor-not-allowed opacity-70",
|
||||
else: "cursor-pointer font-medium"
|
||||
}
|
||||
>
|
||||
{if @oidc_only_env_set do
|
||||
gettext("Only OIDC sign-in (hide password login)") <>
|
||||
" (" <> gettext("From OIDC_ONLY") <> ")"
|
||||
else
|
||||
gettext("Only OIDC sign-in (hide password login)")
|
||||
end}
|
||||
</label>
|
||||
</div>
|
||||
<p class="label-text-alt text-base-content/70 mb-4">
|
||||
{gettext(
|
||||
"When enabled and OIDC is configured, the sign-in page shows only the Single Sign-On button."
|
||||
)}
|
||||
</p>
|
||||
<.form for={@form} id="oidc-form" phx-change="validate" phx-submit="save">
|
||||
<div class="grid gap-4">
|
||||
<.input
|
||||
|
|
@ -744,27 +797,6 @@ defmodule MvWeb.GlobalSettingsLive do
|
|||
)
|
||||
}
|
||||
/>
|
||||
<div class="form-control">
|
||||
<.input
|
||||
field={@form[:oidc_only]}
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm"
|
||||
disabled={@oidc_only_env_set or not @oidc_configured}
|
||||
label={
|
||||
if @oidc_only_env_set do
|
||||
gettext("Only OIDC sign-in (hide password login)") <>
|
||||
" (" <> gettext("From OIDC_ONLY") <> ")"
|
||||
else
|
||||
gettext("Only OIDC sign-in (hide password login)")
|
||||
end
|
||||
}
|
||||
/>
|
||||
<p class="label-text-alt text-base-content/70 mt-1">
|
||||
{gettext(
|
||||
"When enabled and OIDC is configured, the sign-in page shows only the Single Sign-On button."
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<.button
|
||||
:if={
|
||||
|
|
@ -868,18 +900,19 @@ defmodule MvWeb.GlobalSettingsLive do
|
|||
saves_vereinfacht = vereinfacht_params?(setting_params_clean)
|
||||
|
||||
case MvWeb.LiveHelpers.submit_form(socket.assigns.form, setting_params_clean, actor) do
|
||||
{:ok, _updated_settings} ->
|
||||
{:ok, fresh_settings} = Membership.get_settings()
|
||||
|
||||
{:ok, updated_settings} ->
|
||||
# Use the returned record for the form so saved values show immediately;
|
||||
# get_settings() can return cached data without the new attribute until reload.
|
||||
test_result =
|
||||
if saves_vereinfacht, do: Mv.Vereinfacht.test_connection(), else: nil
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(:settings, fresh_settings)
|
||||
|> assign(:registration_enabled, fresh_settings.registration_enabled != false)
|
||||
|> assign(:vereinfacht_api_key_set, present?(fresh_settings.vereinfacht_api_key))
|
||||
|> assign(:settings, updated_settings)
|
||||
|> assign(:registration_enabled, updated_settings.registration_enabled != false)
|
||||
|> assign(:vereinfacht_api_key_set, present?(updated_settings.vereinfacht_api_key))
|
||||
|> assign(:oidc_client_secret_set, Mv.Config.oidc_client_secret_set?())
|
||||
|> assign(:oidc_only, Mv.Config.oidc_only?())
|
||||
|> assign(:oidc_configured, Mv.Config.oidc_configured?())
|
||||
|> assign(:smtp_configured, Mv.Config.smtp_configured?())
|
||||
|> assign(:smtp_password_set, present?(Mv.Config.smtp_password()))
|
||||
|
|
@ -916,19 +949,53 @@ defmodule MvWeb.GlobalSettingsLive do
|
|||
|
||||
@impl true
|
||||
def handle_event("toggle_registration_enabled", _params, socket) do
|
||||
settings = socket.assigns.settings
|
||||
new_value = not socket.assigns.registration_enabled
|
||||
if Mv.Config.oidc_only?() do
|
||||
{:noreply, socket}
|
||||
else
|
||||
settings = socket.assigns.settings
|
||||
new_value = not socket.assigns.registration_enabled
|
||||
|
||||
case Membership.update_settings(settings, %{registration_enabled: new_value}) do
|
||||
{:ok, updated_settings} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:settings, updated_settings)
|
||||
|> assign(:registration_enabled, updated_settings.registration_enabled != false)
|
||||
|> assign_form()}
|
||||
case Membership.update_settings(settings, %{registration_enabled: new_value}) do
|
||||
{:ok, updated_settings} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:settings, updated_settings)
|
||||
|> assign(:registration_enabled, updated_settings.registration_enabled != false)
|
||||
|> assign_form()}
|
||||
|
||||
{:error, _} ->
|
||||
{:noreply, put_flash(socket, :error, gettext("Failed to update setting."))}
|
||||
{:error, _} ->
|
||||
{:noreply, put_flash(socket, :error, gettext("Failed to update setting."))}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("toggle_oidc_only", _params, socket) do
|
||||
if socket.assigns.oidc_only_env_set do
|
||||
{:noreply, socket}
|
||||
else
|
||||
settings = socket.assigns.settings
|
||||
new_value = not socket.assigns.oidc_only
|
||||
|
||||
# When enabling OIDC-only, also disable direct registration; when disabling, only change oidc_only.
|
||||
params =
|
||||
if new_value,
|
||||
do: %{oidc_only: true, registration_enabled: false},
|
||||
else: %{oidc_only: false}
|
||||
|
||||
case Membership.update_settings(settings, params) do
|
||||
{:ok, updated_settings} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:settings, updated_settings)
|
||||
|> assign(:oidc_only, updated_settings.oidc_only == true)
|
||||
|> assign(:registration_enabled, updated_settings.registration_enabled != false)
|
||||
|> assign_form()
|
||||
|> put_flash(:success, gettext("Settings updated successfully"))}
|
||||
|
||||
{:error, _} ->
|
||||
{:noreply, put_flash(socket, :error, gettext("Failed to update setting."))}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ defmodule MvWeb.LiveHelpers do
|
|||
|
||||
socket =
|
||||
socket
|
||||
|> Phoenix.LiveView.put_flash(:error, "You don't have permission to access this page.")
|
||||
|> maybe_put_access_denied_flash(user)
|
||||
|> Phoenix.LiveView.push_navigate(to: redirect_to)
|
||||
|
||||
{:halt, socket}
|
||||
|
|
@ -82,6 +82,13 @@ defmodule MvWeb.LiveHelpers do
|
|||
end
|
||||
end
|
||||
|
||||
# Only show "no permission" when user is logged in; unauthenticated users are redirected to sign-in without flash.
|
||||
defp maybe_put_access_denied_flash(socket, nil), do: socket
|
||||
|
||||
defp maybe_put_access_denied_flash(socket, _user) do
|
||||
Phoenix.LiveView.put_flash(socket, :error, "You don't have permission to access this page.")
|
||||
end
|
||||
|
||||
defp ensure_user_role_loaded(socket) do
|
||||
user = socket.assigns[:current_user]
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ defmodule MvWeb.Plugs.CheckPagePermission do
|
|||
conn
|
||||
|> fetch_session()
|
||||
|> fetch_flash()
|
||||
|> put_flash(:error, "You don't have permission to access this page.")
|
||||
|> maybe_put_access_denied_flash(user)
|
||||
|> redirect(to: redirect_to)
|
||||
|> halt()
|
||||
end
|
||||
|
|
@ -75,6 +75,13 @@ defmodule MvWeb.Plugs.CheckPagePermission do
|
|||
|
||||
defp redirect_target(user), do: redirect_target_for_user(user)
|
||||
|
||||
# Only set "no permission" flash when user is logged in; unauthenticated users get redirect only, no flash.
|
||||
defp maybe_put_access_denied_flash(conn, nil), do: conn
|
||||
|
||||
defp maybe_put_access_denied_flash(conn, _user) do
|
||||
put_flash(conn, :error, "You don't have permission to access this page.")
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns true if the path is public (no auth/permission check).
|
||||
Used by LiveView hook to skip redirect on sign-in etc.
|
||||
|
|
|
|||
73
lib/mv_web/plugs/oidc_only_sign_in_redirect.ex
Normal file
73
lib/mv_web/plugs/oidc_only_sign_in_redirect.ex
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
defmodule MvWeb.Plugs.OidcOnlySignInRedirect do
|
||||
@moduledoc """
|
||||
When OIDC-only mode is active:
|
||||
- GET /sign-in redirects to the OIDC flow when OIDC is configured (sign-in page skipped).
|
||||
- GET /sign-in?oidc_failed=1 is not redirected, so the sign-in page is shown after an OIDC
|
||||
failure (avoids redirect loop when the provider is down or misconfigured).
|
||||
- GET /auth/user/password/sign_in_with_token is rejected (redirect to /sign-in with error)
|
||||
so password sign-in cannot complete.
|
||||
"""
|
||||
import Plug.Conn
|
||||
import Phoenix.Controller
|
||||
|
||||
alias Mv.Config
|
||||
|
||||
def init(opts), do: opts
|
||||
|
||||
def call(conn, _opts) do
|
||||
conn
|
||||
|> maybe_redirect_sign_in_to_oidc()
|
||||
|> maybe_reject_password_token_sign_in()
|
||||
end
|
||||
|
||||
defp maybe_redirect_sign_in_to_oidc(conn) do
|
||||
if conn.request_path != "/sign-in" or conn.method != "GET" do
|
||||
conn
|
||||
else
|
||||
conn = fetch_query_params(conn)
|
||||
maybe_redirect_sign_in_to_oidc_checked(conn)
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_redirect_sign_in_to_oidc_checked(conn) do
|
||||
cond do
|
||||
# Show sign-in page when returning from OIDC failure to avoid redirect loop.
|
||||
conn.query_params["oidc_failed"] -> conn
|
||||
Config.oidc_only?() and Config.oidc_configured?() -> redirect_and_halt(conn)
|
||||
true -> conn
|
||||
end
|
||||
end
|
||||
|
||||
defp redirect_and_halt(conn) do
|
||||
conn
|
||||
|> redirect(to: "/auth/user/oidc")
|
||||
|> halt()
|
||||
end
|
||||
|
||||
defp maybe_reject_password_token_sign_in(conn) do
|
||||
if conn.halted, do: conn, else: reject_password_token_sign_in_if_applicable(conn)
|
||||
end
|
||||
|
||||
defp reject_password_token_sign_in_if_applicable(conn) do
|
||||
path = conn.request_path
|
||||
|
||||
password_token_path? =
|
||||
path =~ ~r|/auth/user/password/sign_in_with_token| and conn.method == "GET"
|
||||
|
||||
if password_token_path? and Config.oidc_only?() do
|
||||
message =
|
||||
Gettext.dgettext(
|
||||
MvWeb.Gettext,
|
||||
"default",
|
||||
"Only sign-in via Single Sign-On (SSO) is allowed."
|
||||
)
|
||||
|
||||
conn
|
||||
|> put_flash(:error, message)
|
||||
|> redirect(to: "/sign-in")
|
||||
|> halt()
|
||||
else
|
||||
conn
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -18,6 +18,7 @@ defmodule MvWeb.Router do
|
|||
plug MvWeb.Plugs.CheckPagePermission
|
||||
plug MvWeb.Plugs.JoinFormEnabled
|
||||
plug MvWeb.Plugs.RegistrationEnabled
|
||||
plug MvWeb.Plugs.OidcOnlySignInRedirect
|
||||
end
|
||||
|
||||
pipeline :api do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue