ui: login page — SSO button + oidc_error banner
This commit is contained in:
@@ -922,7 +922,14 @@ func (s *Server) handleUILoginGet(w stdhttp.ResponseWriter, r *stdhttp.Request)
|
|||||||
stdhttp.Redirect(w, r, "/", stdhttp.StatusSeeOther)
|
stdhttp.Redirect(w, r, "/", stdhttp.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
view := ui.ViewData{Version: s.version()}
|
view := ui.ViewData{
|
||||||
|
Version: s.version(),
|
||||||
|
OIDCError: r.URL.Query().Get("oidc_error"),
|
||||||
|
}
|
||||||
|
if s.deps.OIDC != nil {
|
||||||
|
view.OIDCEnabled = true
|
||||||
|
view.OIDCDisplayName = s.deps.OIDC.DisplayName()
|
||||||
|
}
|
||||||
if err := s.deps.UI.Render(w, "login", view); err != nil {
|
if err := s.deps.UI.Render(w, "login", view); err != nil {
|
||||||
slog.Error("ui: render login", "err", err)
|
slog.Error("ui: render login", "err", err)
|
||||||
stdhttp.Error(w, "internal", stdhttp.StatusInternalServerError)
|
stdhttp.Error(w, "internal", stdhttp.StatusInternalServerError)
|
||||||
@@ -948,6 +955,10 @@ func (s *Server) handleUILoginPost(w stdhttp.ResponseWriter, r *stdhttp.Request)
|
|||||||
Username: username,
|
Username: username,
|
||||||
Error: "Invalid username or password.",
|
Error: "Invalid username or password.",
|
||||||
}
|
}
|
||||||
|
if s.deps.OIDC != nil {
|
||||||
|
view.OIDCEnabled = true
|
||||||
|
view.OIDCDisplayName = s.deps.OIDC.DisplayName()
|
||||||
|
}
|
||||||
w.WriteHeader(stdhttp.StatusUnauthorized)
|
w.WriteHeader(stdhttp.StatusUnauthorized)
|
||||||
if err := s.deps.UI.Render(w, "login", view); err != nil {
|
if err := s.deps.UI.Render(w, "login", view); err != nil {
|
||||||
slog.Error("ui: render login (post-fail)", "err", err)
|
slog.Error("ui: render login (post-fail)", "err", err)
|
||||||
|
|||||||
@@ -56,6 +56,19 @@ type ViewData struct {
|
|||||||
// today; other pages can adopt the same field.
|
// today; other pages can adopt the same field.
|
||||||
Error string
|
Error string
|
||||||
|
|
||||||
|
// OIDCEnabled is true when the server has an OIDC provider
|
||||||
|
// configured. The login page uses it to show the SSO button.
|
||||||
|
OIDCEnabled bool
|
||||||
|
|
||||||
|
// OIDCDisplayName is the human-readable label for the OIDC
|
||||||
|
// provider (e.g. "Authelia"). Shown on the SSO button.
|
||||||
|
OIDCDisplayName string
|
||||||
|
|
||||||
|
// OIDCError holds an error code returned via ?oidc_error=… after
|
||||||
|
// a failed OIDC callback. The login page maps it to a user-facing
|
||||||
|
// message.
|
||||||
|
OIDCError string
|
||||||
|
|
||||||
// Page carries page-specific data. Concrete type is the page's
|
// Page carries page-specific data. Concrete type is the page's
|
||||||
// own struct.
|
// own struct.
|
||||||
Page any
|
Page any
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -10,6 +10,18 @@
|
|||||||
|
|
||||||
<h2 class="text-lg font-medium tracking-[-0.005em] text-center mb-7">Sign in to continue</h2>
|
<h2 class="text-lg font-medium tracking-[-0.005em] text-center mb-7">Sign in to continue</h2>
|
||||||
|
|
||||||
|
{{if .OIDCError}}
|
||||||
|
<div class="panel rounded-[7px] p-4 mb-5"
|
||||||
|
style="border-color: color-mix(in oklch, var(--bad), transparent 60%);">
|
||||||
|
<div class="text-bad text-[12.5px]">
|
||||||
|
{{if eq .OIDCError "no_role_match"}}Your account does not match any role mapping. Contact your administrator.
|
||||||
|
{{else if eq .OIDCError "username_taken"}}A local account with the same username already exists. Contact your administrator.
|
||||||
|
{{else if eq .OIDCError "user_disabled"}}Your account has been disabled. Contact your administrator.
|
||||||
|
{{else}}Sign-in via SSO failed ({{.OIDCError}}). Try again or use a local account.{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if .Error}}
|
{{if .Error}}
|
||||||
<div class="mb-4 px-3 py-2.5 rounded-[5px] text-xs"
|
<div class="mb-4 px-3 py-2.5 rounded-[5px] text-xs"
|
||||||
style="background: color-mix(in oklch, var(--bad), transparent 88%); border: 1px solid color-mix(in oklch, var(--bad), transparent 70%); color: oklch(0.85 0.10 25);">
|
style="background: color-mix(in oklch, var(--bad), transparent 88%); border: 1px solid color-mix(in oklch, var(--bad), transparent 70%); color: oklch(0.85 0.10 25);">
|
||||||
@@ -17,6 +29,17 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if .OIDCEnabled}}
|
||||||
|
<a href="/auth/oidc/login" class="btn btn-primary btn-block btn-lg mb-4">
|
||||||
|
Sign in with {{.OIDCDisplayName}}
|
||||||
|
</a>
|
||||||
|
<div class="flex items-center gap-3 my-5 text-[11px] text-ink-fade uppercase tracking-[0.08em]">
|
||||||
|
<div class="flex-1 border-t border-line-soft"></div>
|
||||||
|
<span>or sign in with a local account</span>
|
||||||
|
<div class="flex-1 border-t border-line-soft"></div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<form method="post" action="/login">
|
<form method="post" action="/login">
|
||||||
<div class="mb-3.5">
|
<div class="mb-3.5">
|
||||||
<label class="field-label" for="login-username">Username</label>
|
<label class="field-label" for="login-username">Username</label>
|
||||||
@@ -33,7 +56,7 @@
|
|||||||
<p class="text-pretty text-xs text-ink-mute leading-[1.65]">
|
<p class="text-pretty text-xs text-ink-mute leading-[1.65]">
|
||||||
Forgot your password? An admin can reset it from
|
Forgot your password? An admin can reset it from
|
||||||
<span class="mono text-ink-mid">Settings → Users</span>.
|
<span class="mono text-ink-mid">Settings → Users</span>.
|
||||||
There’s no recovery email — this is self-hosted infrastructure.
|
There's no recovery email — this is self-hosted infrastructure.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user