mirror of
https://github.com/abhinavxd/libredesk.git
synced 2026-09-11 13:28:57 +00:00
Merge pull request #492 from pat-s/agent/sso-only-auth
feat(auth): add SSO-only login mode
This commit is contained in:
@@ -4,9 +4,12 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/abhinavxd/libredesk/internal/envelope"
|
||||
oidcmodels "github.com/abhinavxd/libredesk/internal/oidc/models"
|
||||
"github.com/zerodha/fastglue"
|
||||
)
|
||||
|
||||
const localLoginEnabledKey = "auth.local_login_enabled"
|
||||
|
||||
// handleGetConfig returns the public configuration needed for app initialization, this includes minimal app settings and enabled SSO providers (without secrets).
|
||||
func handleGetConfig(r *fastglue.Request) error {
|
||||
var app = r.Context.(*App)
|
||||
@@ -58,6 +61,23 @@ func handleGetConfig(r *fastglue.Request) error {
|
||||
|
||||
// Add SSO providers to the response
|
||||
publicSettings["app.sso_providers"] = enabledProviders
|
||||
publicSettings["auth.local_login_enabled"] = isLocalLoginEnabled(oidcProviders)
|
||||
|
||||
return r.SendEnvelope(publicSettings)
|
||||
}
|
||||
|
||||
func localLoginDisabledInConfig() bool {
|
||||
return ko.Exists(localLoginEnabledKey) && !ko.Bool(localLoginEnabledKey)
|
||||
}
|
||||
|
||||
func isLocalLoginEnabled(providers []oidcmodels.OIDC) bool {
|
||||
if !localLoginDisabledInConfig() {
|
||||
return true
|
||||
}
|
||||
for _, provider := range providers {
|
||||
if provider.Enabled {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
oidcmodels "github.com/abhinavxd/libredesk/internal/oidc/models"
|
||||
)
|
||||
|
||||
func TestIsLocalLoginEnabled(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
configured *bool
|
||||
providers []oidcmodels.OIDC
|
||||
want bool
|
||||
}{
|
||||
{name: "defaults to enabled", want: true},
|
||||
{name: "remains enabled when configured", configured: boolPointer(true), want: true},
|
||||
{name: "remains enabled without an enabled OIDC provider", configured: boolPointer(false), providers: []oidcmodels.OIDC{{Enabled: false}}, want: true},
|
||||
{name: "is disabled with an enabled OIDC provider", configured: boolPointer(false), providers: []oidcmodels.OIDC{{Enabled: true}}, want: false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ko.Delete(localLoginEnabledKey)
|
||||
if tt.configured != nil {
|
||||
if err := ko.Set(localLoginEnabledKey, *tt.configured); err != nil {
|
||||
t.Fatalf("set config: %v", err)
|
||||
}
|
||||
}
|
||||
t.Cleanup(func() { ko.Delete(localLoginEnabledKey) })
|
||||
|
||||
if got := isLocalLoginEnabled(tt.providers); got != tt.want {
|
||||
t.Fatalf("isLocalLoginEnabled() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func boolPointer(value bool) *bool {
|
||||
return &value
|
||||
}
|
||||
@@ -21,6 +21,17 @@ func handleLogin(r *fastglue.Request) error {
|
||||
loginReq loginRequest
|
||||
)
|
||||
|
||||
if localLoginDisabledInConfig() {
|
||||
oidcProviders, err := app.oidc.GetAll()
|
||||
if err != nil {
|
||||
return sendErrorEnvelope(r, err)
|
||||
}
|
||||
if !isLocalLoginEnabled(oidcProviders) {
|
||||
return r.SendErrorEnvelope(fasthttp.StatusForbidden, app.i18n.T("auth.localLoginDisabled"), nil, envelope.PermissionError)
|
||||
}
|
||||
app.lo.Warn("local login is disabled in config but no OIDC provider is enabled, allowing password login")
|
||||
}
|
||||
|
||||
// Decode JSON request.
|
||||
if err := r.Decode(&loginReq, "json"); err != nil {
|
||||
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.T("errors.parsingRequest"), nil, envelope.InputError)
|
||||
|
||||
@@ -34,6 +34,13 @@ read_buffer_size = 65536
|
||||
# Keepalive settings.
|
||||
keepalive_timeout = "10s"
|
||||
|
||||
[auth]
|
||||
# Allow users to sign in with their libredesk email and password.
|
||||
# Disable this only after configuring and enabling at least one OIDC provider.
|
||||
# libredesk automatically keeps local login available when no OIDC provider is enabled to prevent lockout.
|
||||
# If an enabled provider is unavailable or misconfigured, set auth.local_login_enabled = true to restore password login.
|
||||
local_login_enabled = true
|
||||
|
||||
# File upload provider to use, either `fs` or `s3`.
|
||||
[upload]
|
||||
provider = "fs"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
{{ oidcProvider.name }}
|
||||
</Button>
|
||||
|
||||
<div class="relative">
|
||||
<div v-if="localLoginEnabled" class="relative">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<span class="w-full border-t border-border"></span>
|
||||
</div>
|
||||
@@ -42,7 +42,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="loginAction" class="space-y-3">
|
||||
<form v-if="localLoginEnabled" @submit.prevent="loginAction" class="space-y-3">
|
||||
<div class="space-y-2">
|
||||
<Label for="email" class="text-muted-foreground">{{ t('globals.terms.email') }}</Label>
|
||||
<Input
|
||||
@@ -259,6 +259,10 @@ const enabledOIDCProviders = computed(() => {
|
||||
return oidcProviders.value.filter((provider) => !provider.disabled)
|
||||
})
|
||||
|
||||
const localLoginEnabled = computed(
|
||||
() => appSettingsStore.public_config?.['auth.local_login_enabled'] !== false
|
||||
)
|
||||
|
||||
const emailHasError = computed(() => {
|
||||
if (!submitted.value) return false
|
||||
const email = loginForm.value.email
|
||||
|
||||
@@ -608,6 +608,7 @@
|
||||
"auth.invalidOrExpiredSessionClearCookie": "Invalid or expired session. Please clear your cookies and try again.",
|
||||
"auth.invalidResetLink": "Invalid reset link. Please request a new password reset link.",
|
||||
"auth.loggingIn": "Logging in...",
|
||||
"auth.localLoginDisabled": "Password login is disabled. Sign in with your SSO provider.",
|
||||
"auth.newPassword": "New password",
|
||||
"auth.oidcAccessDenied": "The sign-in was cancelled or denied at the identity provider. Try signing in again.",
|
||||
"auth.oidcInvalidClient": "Sign-in is unavailable due to a configuration problem. Ask your administrator to check the SSO client ID and secret.",
|
||||
|
||||
Reference in New Issue
Block a user