From 14d242c8d1096a80f149fe1de9b0bc3d4b09d84f Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Tue, 21 Apr 2026 13:50:07 +1000 Subject: [PATCH] optimising ldap lookup --- internal/auth/ldap.go | 71 +++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/internal/auth/ldap.go b/internal/auth/ldap.go index bc667e7..89f43d7 100644 --- a/internal/auth/ldap.go +++ b/internal/auth/ldap.go @@ -321,32 +321,63 @@ func (a *LDAPAuthenticator) lookupUserEntry(conn *ldap.Conn, username string, us } for _, principal := range principalCandidates(username) { - searchRes, err := conn.Search(ldap.NewSearchRequest( - a.baseDN, - ldap.ScopeWholeSubtree, - ldap.NeverDerefAliases, - 2, - 0, - false, - fmt.Sprintf("(|(uid=%s)(cn=%s)(sAMAccountName=%s)(userPrincipalName=%s))", - ldap.EscapeFilter(principal), - ldap.EscapeFilter(principal), - ldap.EscapeFilter(principal), - ldap.EscapeFilter(principal), - ), - []string{"uid", "sAMAccountName", "userPrincipalName", "cn", "memberOf"}, - nil, - )) - if err != nil { - return nil, "", fmt.Errorf("%w: user lookup failed: %v", ErrLDAPOperationFailed, err) + if strings.Contains(principal, "@") { + entry, err := a.searchUserByAttribute(conn, "userPrincipalName", principal) + if err != nil { + return nil, "", err + } + if entry != nil { + return entry, "principal_upn", nil + } } - if len(searchRes.Entries) > 0 { - return searchRes.Entries[0], "principal", nil + + entry, err := a.searchUserByAttribute(conn, "sAMAccountName", principal) + if err != nil { + return nil, "", err + } + if entry != nil { + return entry, "principal_samaccountname", nil + } + + // Keep uid lookup as a fallback for non-AD LDAP directories. + entry, err = a.searchUserByAttribute(conn, "uid", principal) + if err != nil { + return nil, "", err + } + if entry != nil { + return entry, "principal_uid", nil } } return nil, "", nil } +func (a *LDAPAuthenticator) searchUserByAttribute(conn *ldap.Conn, attribute string, value string) (*ldap.Entry, error) { + attribute = strings.TrimSpace(attribute) + value = strings.TrimSpace(value) + if attribute == "" || value == "" { + return nil, nil + } + + searchRes, err := conn.Search(ldap.NewSearchRequest( + a.baseDN, + ldap.ScopeWholeSubtree, + ldap.NeverDerefAliases, + 2, + 0, + false, + fmt.Sprintf("(%s=%s)", attribute, ldap.EscapeFilter(value)), + []string{"uid", "sAMAccountName", "userPrincipalName", "cn", "memberOf"}, + nil, + )) + if err != nil { + return nil, fmt.Errorf("%w: user lookup failed (%s): %v", ErrLDAPOperationFailed, attribute, err) + } + if len(searchRes.Entries) == 0 { + return nil, nil + } + return searchRes.Entries[0], nil +} + func normalizeDN(value string) string { return strings.ToLower(strings.TrimSpace(value)) }