From de7ccce1a40b93d8690338812089bbe539f178b1 Mon Sep 17 00:00:00 2001 From: Jim Date: Thu, 7 Sep 2023 08:33:30 -0400 Subject: [PATCH 1/2] feat (ldap): add worker pool for LDAP token group lookups --- ldap/client.go | 77 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/ldap/client.go b/ldap/client.go index 53ad477..b57ebb8 100644 --- a/ldap/client.go +++ b/ldap/client.go @@ -15,6 +15,7 @@ import ( "net" "net/url" "strings" + "sync" "text/template" "time" @@ -458,35 +459,63 @@ func (c *Client) tokenGroupsSearch(userDN string) ([]*ldap.Entry, []Warning, err userEntry := result.Entries[0] groupAttrValues := userEntry.GetRawAttributeValues("tokenGroups") - groupEntries := make([]*ldap.Entry, 0, len(groupAttrValues)) - for _, sidBytes := range groupAttrValues { - sidString, err := sidBytesToString(sidBytes) - if err != nil { - warnings = append(warnings, fmtWarning("%s: unable to read sid: %s", op, err.Error())) - continue - } - groupResult, err := c.conn.Search(&ldap.SearchRequest{ - BaseDN: fmt.Sprintf("", sidString), - Scope: ldap.ScopeBaseObject, - DerefAliases: derefAliasMap[c.conf.DerefAliases], - Filter: "(objectClass=*)", - Attributes: []string{ - "1.1", // RFC no attributes - }, - SizeLimit: 1, - }) - if err != nil { - warnings = append(warnings, fmtWarning("%s: unable to read the group sid (baseDN: %q / filter: %q): %s", op, fmt.Sprintf("", sidString), "(objectClass=*)", sidString)) - continue + { + // we're using worker pool to make looking up token groups more + // performant. token groups have to be looked up individually, so if a + // user is a member of MANY groups it can be helpful to do these lookups + // concurrently vs serially. This is based on benchmarks and a + // subsequent implementation within vault's codebase for looking up token + // groups. See: https://github.com/hashicorp/vault/pull/22659 + const maxWorkers = 10 + var wg sync.WaitGroup + var lock sync.Mutex + taskChan := make(chan string) // intentionally an unbuffered chan so we can iterate (range) over it before it's closed. + for i := 0; i < maxWorkers; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for sidString := range taskChan { + groupResult, err := c.conn.Search(&ldap.SearchRequest{ + BaseDN: fmt.Sprintf("", sidString), + Scope: ldap.ScopeBaseObject, + DerefAliases: derefAliasMap[c.conf.DerefAliases], + Filter: "(objectClass=*)", + Attributes: []string{ + "1.1", // RFC no attributes + }, + SizeLimit: 1, + }) + if err != nil { + warnings = append(warnings, fmtWarning("%s: unable to read the group sid (baseDN: %q / filter: %q): %s", op, fmt.Sprintf("", sidString), "(objectClass=*)", sidString)) + continue + } + if len(groupResult.Entries) == 0 { + warnings = append(warnings, fmtWarning("%s: unable to find the group sid (baseDN: %q / filter: %q): %s", op, fmt.Sprintf("", sidString), "(objectClass=*)", sidString)) + continue + } + lock.Lock() + groupEntries = append(groupEntries, groupResult.Entries[0]) + lock.Unlock() + } + }() } - if len(groupResult.Entries) == 0 { - warnings = append(warnings, fmtWarning("%s: unable to find the group sid (baseDN: %q / filter: %q): %s", op, fmt.Sprintf("", sidString), "(objectClass=*)", sidString)) - continue + for _, sidBytes := range groupAttrValues { + sidString, err := sidBytesToString(sidBytes) + if err != nil { + warnings = append(warnings, fmtWarning("%s: unable to read sid: %s", op, err.Error())) + continue + } + taskChan <- sidString } + // closing the taskChan will allow the workers to start iterating + // (range) - this unblocks them + close(taskChan) - groupEntries = append(groupEntries, groupResult.Entries[0]) + // wait for all the workers to finish up the token group lookups and + // adding all the groups to the slice of group entries + wg.Wait() } return groupEntries, warnings, nil From 999237ac5a68ce056a4d4d4dc3da50902f73a944 Mon Sep 17 00:00:00 2001 From: Jim Date: Thu, 7 Sep 2023 08:35:28 -0400 Subject: [PATCH 2/2] chore: add CHANGELOG entry for ldap token group worker pool --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57fd772..c53f5c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Canonical reference for changes, improvements, and bugfixes for cap. +## Next + +* LDAP + * Add worker pool for LDAP token group lookups ([**PR**](https://github.com/hashicorp/cap/pull/98)) + ## 0.3.4 ### Bug fixes