Compare commits

..

4 Commits

Author SHA1 Message Date
Ryc O'Chet 42ce47dab3 Ensure the ldap service uses the correct value 2026-06-09 10:53:44 +01:00
Ryc O'Chet b68426d931 Move secret loading to only run once 2026-06-09 10:28:23 +01:00
Ryc O'Chet b90f95a17d Fix missing import 2026-06-08 12:55:01 +01:00
Ryc O'Chet 3d28c6e6d9 Add LDAP BindPasswordFile
Fixes #927
2026-06-08 12:46:39 +01:00
3 changed files with 21 additions and 22 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ import (
) )
func (app *BootstrapApp) setupServices() error { func (app *BootstrapApp) setupServices() error {
ldapService, err := service.NewLdapService(app.log, app.config, app.ctx, app.ding) ldapService, err := service.NewLdapService(app.log, app.config, app.ding)
if err != nil { if err != nil {
app.log.App.Warn().Err(err).Msg("Failed to initialize LDAP connection, will continue without it") app.log.App.Warn().Err(err).Msg("Failed to initialize LDAP connection, will continue without it")
+10 -9
View File
@@ -178,15 +178,16 @@ type UIConfig struct {
} }
type LDAPConfig struct { type LDAPConfig struct {
Address string `description:"LDAP server address." yaml:"address"` Address string `description:"LDAP server address." yaml:"address"`
BindDN string `description:"Bind DN for LDAP authentication." yaml:"bindDn"` BindDN string `description:"Bind DN for LDAP authentication." yaml:"bindDn"`
BindPassword string `description:"Bind password for LDAP authentication." yaml:"bindPassword"` BindPassword string `description:"Bind password for LDAP authentication." yaml:"bindPassword"`
BaseDN string `description:"Base DN for LDAP searches." yaml:"baseDn"` BindPasswordFile string `description:"Path to the Bind password." yaml:"bindPasswordFile"`
Insecure bool `description:"Allow insecure LDAP connections." yaml:"insecure"` BaseDN string `description:"Base DN for LDAP searches." yaml:"baseDn"`
SearchFilter string `description:"LDAP search filter." yaml:"searchFilter"` Insecure bool `description:"Allow insecure LDAP connections." yaml:"insecure"`
AuthCert string `description:"Certificate for mTLS authentication." yaml:"authCert"` SearchFilter string `description:"LDAP search filter." yaml:"searchFilter"`
AuthKey string `description:"Certificate key for mTLS authentication." yaml:"authKey"` AuthCert string `description:"Certificate for mTLS authentication." yaml:"authCert"`
GroupCacheTTL int `description:"Cache duration for LDAP group membership in seconds." yaml:"groupCacheTTL"` AuthKey string `description:"Certificate key for mTLS authentication." yaml:"authKey"`
GroupCacheTTL int `description:"Cache duration for LDAP group membership in seconds." yaml:"groupCacheTTL"`
} }
type LogConfig struct { type LogConfig struct {
+10 -12
View File
@@ -11,13 +11,13 @@ import (
ldapgo "github.com/go-ldap/ldap/v3" ldapgo "github.com/go-ldap/ldap/v3"
"github.com/steveiliop56/ding" "github.com/steveiliop56/ding"
"github.com/tinyauthapp/tinyauth/internal/model" "github.com/tinyauthapp/tinyauth/internal/model"
"github.com/tinyauthapp/tinyauth/internal/utils"
"github.com/tinyauthapp/tinyauth/internal/utils/logger" "github.com/tinyauthapp/tinyauth/internal/utils/logger"
) )
type LdapService struct { type LdapService struct {
log *logger.Logger log *logger.Logger
config model.Config config model.Config
ctx context.Context
conn *ldapgo.Conn conn *ldapgo.Conn
mutex sync.RWMutex mutex sync.RWMutex
@@ -27,17 +27,19 @@ type LdapService struct {
func NewLdapService( func NewLdapService(
log *logger.Logger, log *logger.Logger,
config model.Config, config model.Config,
ctx context.Context,
dg *ding.Ding, dg *ding.Ding,
) (*LdapService, error) { ) (*LdapService, error) {
if config.LDAP.Address == "" { if config.LDAP.Address == "" {
return nil, nil return nil, nil
} }
secret := utils.GetSecret(config.LDAP.BindPassword, config.LDAP.BindPasswordFile)
config.LDAP.BindPassword = secret
config.LDAP.BindPasswordFile = ""
ldap := &LdapService{ ldap := &LdapService{
log: log, log: log,
config: config, config: config,
ctx: ctx,
} }
// Check whether authentication with client certificate is possible // Check whether authentication with client certificate is possible
@@ -66,9 +68,7 @@ func NewLdapService(
_, err := ldap.connect() _, err := ldap.connect()
// Warn: This will hang the tinyauth startup for a good 45 seconds until it fails
if err != nil { if err != nil {
err = ldap.reconnect(10 * time.Second)
return nil, fmt.Errorf("failed to connect to ldap server: %w", err) return nil, fmt.Errorf("failed to connect to ldap server: %w", err)
} }
@@ -84,7 +84,7 @@ func NewLdapService(
err := ldap.heartbeat() err := ldap.heartbeat()
if err != nil { if err != nil {
ldap.log.App.Warn().Err(err).Msg("LDAP connection heartbeat failed, attempting to reconnect") ldap.log.App.Warn().Err(err).Msg("LDAP connection heartbeat failed, attempting to reconnect")
if reconnectErr := ldap.reconnect(5 * time.Second); reconnectErr != nil { if reconnectErr := ldap.reconnect(); reconnectErr != nil {
ldap.log.App.Error().Err(reconnectErr).Msg("Failed to reconnect to LDAP server") ldap.log.App.Error().Err(reconnectErr).Msg("Failed to reconnect to LDAP server")
continue continue
} }
@@ -252,19 +252,17 @@ func (ldap *LdapService) heartbeat() error {
return nil return nil
} }
func (ldap *LdapService) reconnect(interval time.Duration) error { func (ldap *LdapService) reconnect() error {
ldap.log.App.Info().Msg("Attempting to reconnect to LDAP server") ldap.log.App.Info().Msg("Attempting to reconnect to LDAP server")
exp := backoff.NewExponentialBackOff() exp := backoff.NewExponentialBackOff()
exp.InitialInterval = interval exp.InitialInterval = 500 * time.Millisecond
exp.RandomizationFactor = 0.1 exp.RandomizationFactor = 0.1
exp.Multiplier = 1.5 exp.Multiplier = 1.5
exp.Reset() exp.Reset()
operation := func() (*ldapgo.Conn, error) { operation := func() (*ldapgo.Conn, error) {
if ldap.conn != nil { ldap.conn.Close()
ldap.conn.Close()
}
conn, err := ldap.connect() conn, err := ldap.connect()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -272,7 +270,7 @@ func (ldap *LdapService) reconnect(interval time.Duration) error {
return conn, nil return conn, nil
} }
_, err := backoff.Retry(ldap.ctx, operation, backoff.WithBackOff(exp), backoff.WithMaxTries(3)) _, err := backoff.Retry(context.TODO(), operation, backoff.WithBackOff(exp), backoff.WithMaxTries(3))
if err != nil { if err != nil {
return err return err