From dfcf7a8bc5f0e5293e2ea25659ac6886b77b5640 Mon Sep 17 00:00:00 2001 From: Til Wegener <38760774+tilwegener@users.noreply.github.com> Date: Fri, 18 Sep 2026 15:05:39 +0200 Subject: [PATCH 1/2] Update LDAP search filter for group membership --- internal/service/ldap_service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/ldap_service.go b/internal/service/ldap_service.go index 2a5a5adb..78605d2f 100644 --- a/internal/service/ldap_service.go +++ b/internal/service/ldap_service.go @@ -200,7 +200,7 @@ func (ldap *LdapService) GetUserGroups(userDN string) ([]string, error) { searchRequest := ldapgo.NewSearchRequest( ldap.config.LDAP.BaseDN, ldapgo.ScopeWholeSubtree, ldapgo.NeverDerefAliases, 0, 0, false, - fmt.Sprintf("(&(objectclass=groupOfUniqueNames)(uniquemember=%s))", escapedUserDN), + fmt.Sprintf("(&(objectClass=group)(member:1.2.840.113556.1.4.1941:=%s))", escapedUserDN), []string{"dn"}, nil, ) From 33280d6db08cc8813788cf06938e84d0c4391c3e Mon Sep 17 00:00:00 2001 From: Til Wegener <38760774+tilwegener@users.noreply.github.com> Date: Fri, 18 Sep 2026 13:29:12 +0000 Subject: [PATCH 2/2] feat: make group search filter configurable --- .env.example | 4 +++- internal/model/config.go | 28 +++++++++++++++------------- internal/service/ldap_service.go | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/.env.example b/.env.example index bfdc357d..6b39832b 100644 --- a/.env.example +++ b/.env.example @@ -222,8 +222,10 @@ TINYAUTH_LDAP_BINDPASSWORDFILE= TINYAUTH_LDAP_BASEDN= # Allow insecure LDAP connections. TINYAUTH_LDAP_INSECURE=false -# LDAP search filter. +# LDAP user search filter. Use %s as the username placeholder. TINYAUTH_LDAP_SEARCHFILTER="(uid=%s)" +# LDAP group search filter. Use %s as the user DN placeholder. +TINYAUTH_LDAP_GROUPSEARCHFILTER="(&(objectclass=groupOfUniqueNames)(uniquemember=%s))" # Certificate for mTLS authentication. TINYAUTH_LDAP_AUTHCERT= # Certificate key for mTLS authentication. diff --git a/internal/model/config.go b/internal/model/config.go index 24ba6302..25736c40 100644 --- a/internal/model/config.go +++ b/internal/model/config.go @@ -57,9 +57,10 @@ func NewDefaultConfiguration(runtimeEnv RuntimeEnv) *Config { WarningsEnabled: true, }, LDAP: LDAPConfig{ - Insecure: false, - SearchFilter: "(uid=%s)", - GroupCacheTTL: 900, // 15 minutes + Insecure: false, + SearchFilter: "(uid=%s)", + GroupSearchFilter: "(&(objectclass=groupOfUniqueNames)(uniquemember=%s))", + GroupCacheTTL: 900, // 15 minutes }, Log: LogConfig{ Level: "info", @@ -209,16 +210,17 @@ type UIConfig struct { } type LDAPConfig struct { - Address string `description:"LDAP server address." yaml:"address,omitempty"` - BindDN string `description:"Bind DN for LDAP authentication." yaml:"bindDn,omitempty"` - BindPassword string `description:"Bind password for LDAP authentication." yaml:"bindPassword,omitempty"` - BindPasswordFile string `description:"Path to the Bind password." yaml:"bindPasswordFile,omitempty"` - BaseDN string `description:"Base DN for LDAP searches." yaml:"baseDn,omitempty"` - Insecure bool `description:"Allow insecure LDAP connections." yaml:"insecure,omitempty"` - SearchFilter string `description:"LDAP search filter." yaml:"searchFilter,omitempty"` - AuthCert string `description:"Certificate for mTLS authentication." yaml:"authCert,omitempty"` - AuthKey string `description:"Certificate key for mTLS authentication." yaml:"authKey,omitempty"` - GroupCacheTTL int `description:"Cache duration for LDAP group membership in seconds." yaml:"groupCacheTTL,omitempty"` + Address string `description:"LDAP server address." yaml:"address,omitempty"` + BindDN string `description:"Bind DN for LDAP authentication." yaml:"bindDn,omitempty"` + BindPassword string `description:"Bind password for LDAP authentication." yaml:"bindPassword,omitempty"` + BindPasswordFile string `description:"Path to the Bind password." yaml:"bindPasswordFile,omitempty"` + BaseDN string `description:"Base DN for LDAP searches." yaml:"baseDn,omitempty"` + Insecure bool `description:"Allow insecure LDAP connections." yaml:"insecure,omitempty"` + SearchFilter string `description:"LDAP user search filter. Use %s as the username placeholder." yaml:"searchFilter,omitempty"` + GroupSearchFilter string `description:"LDAP group search filter. Use %s as the user DN placeholder." yaml:"groupSearchFilter,omitempty"` + AuthCert string `description:"Certificate for mTLS authentication." yaml:"authCert,omitempty"` + AuthKey string `description:"Certificate key for mTLS authentication." yaml:"authKey,omitempty"` + GroupCacheTTL int `description:"Cache duration for LDAP group membership in seconds." yaml:"groupCacheTTL,omitempty"` } type LogConfig struct { diff --git a/internal/service/ldap_service.go b/internal/service/ldap_service.go index 78605d2f..6ded3aab 100644 --- a/internal/service/ldap_service.go +++ b/internal/service/ldap_service.go @@ -200,7 +200,7 @@ func (ldap *LdapService) GetUserGroups(userDN string) ([]string, error) { searchRequest := ldapgo.NewSearchRequest( ldap.config.LDAP.BaseDN, ldapgo.ScopeWholeSubtree, ldapgo.NeverDerefAliases, 0, 0, false, - fmt.Sprintf("(&(objectClass=group)(member:1.2.840.113556.1.4.1941:=%s))", escapedUserDN), + fmt.Sprintf(ldap.config.LDAP.GroupSearchFilter, escapedUserDN), []string{"dn"}, nil, )