Added ldap and pam authentication

This commit is contained in:
Martino Ferrari
2026-06-23 17:59:40 +02:00
parent ac24011487
commit 11120bedca
36 changed files with 1935 additions and 66 deletions
+90 -1
View File
@@ -13,6 +13,7 @@ import (
"path/filepath"
"syscall"
"github.com/jcmturner/gokrb5/v8/keytab"
"github.com/uopi/uopi/internal/access"
"github.com/uopi/uopi/internal/audit"
"github.com/uopi/uopi/internal/broker"
@@ -24,6 +25,8 @@ import (
"github.com/uopi/uopi/internal/datasource/servervar"
"github.com/uopi/uopi/internal/datasource/stub"
"github.com/uopi/uopi/internal/datasource/synthetic"
"github.com/uopi/uopi/internal/ldapauth"
"github.com/uopi/uopi/internal/pamauth"
"github.com/uopi/uopi/internal/panelacl"
"github.com/uopi/uopi/internal/server"
"github.com/uopi/uopi/internal/storage"
@@ -220,7 +223,93 @@ func main() {
ctrlEngine.SetDebugObserver(debugHub)
ctrlEngine.Reload()
srv := server.New(cfg.Server.Listen, webFS, brk, synthDS, store, cfgStore, policy, aclStore, ctrlStore, ctrlEngine, dialogs, debugHub, recorder, cfg.Datasource.EPICS.ChannelFinderURL, cfg.Datasource.EPICS.ArchiveURL, cfg.Server.TrustedUserHeader, log)
// Native SPNEGO/Kerberos authentication (optional): load the service keytab so
// the server can validate browser Negotiate tickets and resolve users directly.
var krbKeytab *keytab.Keytab
if cfg.Server.Kerberos.Enabled {
if cfg.Server.Kerberos.Keytab == "" {
log.Error("kerberos enabled but no keytab configured (server.kerberos.keytab)")
os.Exit(1)
}
kt, err := keytab.Load(cfg.Server.Kerberos.Keytab)
if err != nil {
log.Error("failed to load kerberos keytab", "path", cfg.Server.Kerberos.Keytab, "err", err)
os.Exit(1)
}
krbKeytab = kt
log.Info("native SPNEGO/Kerberos authentication enabled",
"keytab", cfg.Server.Kerberos.Keytab, "service_principal", cfg.Server.Kerberos.ServicePrincipal)
}
// Built-in HTTP Basic authentication (optional): challenge the browser with a
// login dialog and validate credentials against either the host PAM stack
// (basic_auth) or an LDAP directory (ldap), so users log in with their normal
// accounts. The three built-in auth methods (kerberos, basic_auth, ldap) are
// mutually exclusive.
var basicAuthFn func(user, pass string) error
var basicAuthRealm string
enabledAuth := 0
for _, on := range []bool{cfg.Server.Kerberos.Enabled, cfg.Server.BasicAuth.Enabled, cfg.Server.LDAP.Enabled} {
if on {
enabledAuth++
}
}
if enabledAuth > 1 {
log.Error("server.kerberos, server.basic_auth and server.ldap are mutually exclusive; enable only one")
os.Exit(1)
}
if cfg.Server.BasicAuth.Enabled {
if !pamauth.Available {
log.Error("basic_auth enabled but this binary lacks PAM support; rebuild with: make backend-pam (or use server.ldap, which needs no cgo)")
os.Exit(1)
}
service := cfg.Server.BasicAuth.PAMService
if service == "" {
service = "uopi"
}
basicAuthFn = func(user, pass string) error {
return pamauth.Authenticate(service, user, pass)
}
basicAuthRealm = "uopi"
log.Info("built-in HTTP Basic authentication enabled (PAM)", "pam_service", service)
}
if cfg.Server.LDAP.Enabled {
ldapAuth, err := ldapauth.New(ldapauth.Config{
URIs: cfg.Server.LDAP.URIs,
SearchBase: cfg.Server.LDAP.SearchBase,
UserAttr: cfg.Server.LDAP.UserAttr,
UserObjectClass: cfg.Server.LDAP.UserObjectClass,
BindDN: cfg.Server.LDAP.BindDN,
BindPassword: cfg.Server.LDAP.BindPassword,
StartTLS: cfg.Server.LDAP.StartTLS,
CACertFile: cfg.Server.LDAP.CACert,
InsecureSkipVerify: cfg.Server.LDAP.InsecureSkipVerify,
})
if err != nil {
log.Error("ldap auth misconfigured", "err", err)
os.Exit(1)
}
basicAuthFn = ldapAuth.Authenticate
basicAuthRealm = "uopi"
log.Info("built-in HTTP Basic authentication enabled (LDAP)", "uri", cfg.Server.LDAP.URIs, "search_base", cfg.Server.LDAP.SearchBase)
}
if basicAuthFn != nil && !cfg.Server.TLS.Enabled {
log.Warn("HTTP Basic authentication enabled without TLS; credentials are sent in clear text — enable server.tls unless on a fully isolated network")
}
// Built-in TLS (optional): terminate HTTPS directly, recommended whenever
// Basic auth is enabled.
var tlsCert, tlsKey string
if cfg.Server.TLS.Enabled {
if cfg.Server.TLS.Cert == "" || cfg.Server.TLS.Key == "" {
log.Error("server.tls enabled but cert/key not configured (server.tls.cert, server.tls.key)")
os.Exit(1)
}
tlsCert, tlsKey = cfg.Server.TLS.Cert, cfg.Server.TLS.Key
log.Info("built-in TLS enabled", "cert", tlsCert)
}
srv := server.New(cfg.Server.Listen, webFS, brk, synthDS, store, cfgStore, policy, aclStore, ctrlStore, ctrlEngine, dialogs, debugHub, recorder, cfg.Datasource.EPICS.ChannelFinderURL, cfg.Datasource.EPICS.ArchiveURL, cfg.Server.TrustedUserHeader, krbKeytab, cfg.Server.Kerberos.ServicePrincipal, basicAuthFn, basicAuthRealm, tlsCert, tlsKey, cfg.UI.DefaultZoom, log)
if err := srv.Start(ctx); err != nil {
fmt.Fprintf(os.Stderr, "server error: %v\n", err)