outposts/ldap: Handle comma-separated attributes in LDAP search requests (#15000)

Closes https://github.com/goauthentik/authentik/issues/13539

When LDAP clients like Jira submit search requests with comma-separated attributes
(e.g., ["uid,cn,sn"] instead of ["uid", "cn", "sn"]), the LDAP outpost would return
an "Operations Error". Ths fix adds attribute normalization to properly handle
both formats by splitting comma separated attributes into individual entries.

Tests pass:
```
=== RUN   TestNormalizeAttributes
=== RUN   TestNormalizeAttributes/Empty_input
=== RUN   TestNormalizeAttributes/No_commas
=== RUN   TestNormalizeAttributes/Single_comma-separated_string
=== RUN   TestNormalizeAttributes/Mixed_input
=== RUN   TestNormalizeAttributes/With_spaces
=== RUN   TestNormalizeAttributes/Empty_parts
=== RUN   TestNormalizeAttributes/Single_element
=== RUN   TestNormalizeAttributes/Only_commas
=== RUN   TestNormalizeAttributes/Multiple_comma-separated_attributes
=== RUN   TestNormalizeAttributes/Case_preservation
=== RUN   TestNormalizeAttributes/Leading_and_trailing_spaces
=== RUN   TestNormalizeAttributes/Real-world_LDAP_attribute_examples
=== RUN   TestNormalizeAttributes/Jira-style_attribute_format
=== RUN   TestNormalizeAttributes/Single_string_with_single_attribute
=== RUN   TestNormalizeAttributes/Mix_of_standard_and_operational_attributes
--- PASS: TestNormalizeAttributes (0.00s)
    --- PASS: TestNormalizeAttributes/Empty_input (0.00s)
    --- PASS: TestNormalizeAttributes/No_commas (0.00s)
    --- PASS: TestNormalizeAttributes/Single_comma-separated_string (0.00s)
    --- PASS: TestNormalizeAttributes/Mixed_input (0.00s)
    --- PASS: TestNormalizeAttributes/With_spaces (0.00s)
    --- PASS: TestNormalizeAttributes/Empty_parts (0.00s)
    --- PASS: TestNormalizeAttributes/Single_element (0.00s)
    --- PASS: TestNormalizeAttributes/Only_commas (0.00s)
    --- PASS: TestNormalizeAttributes/Multiple_comma-separated_attributes (0.00s)
    --- PASS: TestNormalizeAttributes/Case_preservation (0.00s)
    --- PASS: TestNormalizeAttributes/Leading_and_trailing_spaces (0.00s)
    --- PASS: TestNormalizeAttributes/Real-world_LDAP_attribute_examples (0.00s)
    --- PASS: TestNormalizeAttributes/Jira-style_attribute_format (0.00s)
    --- PASS: TestNormalizeAttributes/Single_string_with_single_attribute (0.00s)
    --- PASS: TestNormalizeAttributes/Mix_of_standard_and_operational_attributes (0.00s)
PASS
ok      goauthentik.io/internal/outpost/ldap/search     0.194s
```
This commit is contained in:
Dominic R
2025-06-11 12:16:40 -04:00
committed by GitHub
parent 6ec745ddc0
commit 5af2378738
2 changed files with 131 additions and 0 deletions

View File

@ -53,6 +53,14 @@ func NewRequest(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (*Re
if err != nil && len(searchReq.Filter) > 0 {
l.WithError(err).WithField("objectClass", filterOC).Warning("invalid filter object class")
}
// Handle comma-separated attributes
normalizedAttributes := normalizeAttributes(searchReq.Attributes)
if len(normalizedAttributes) != len(searchReq.Attributes) {
// Create a copy of the search request with normalized attributes
searchReq.Attributes = normalizedAttributes
}
return &Request{
SearchRequest: searchReq,
BindDN: bindDN,
@ -64,6 +72,31 @@ func NewRequest(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (*Re
}, span
}
// normalizeAttributes handles the case where attributes might be passed as comma-separated strings
// rather than as individual array elements
func normalizeAttributes(attributes []string) []string {
if len(attributes) == 0 {
return attributes
}
result := make([]string, 0, len(attributes))
for _, attr := range attributes {
if strings.Contains(attr, ",") {
// Split comma-separated attributes and add them individually
parts := strings.Split(attr, ",")
for _, part := range parts {
part = strings.TrimSpace(part)
if part != "" {
result = append(result, part)
}
}
} else {
result = append(result, attr)
}
}
return result
}
func (r *Request) Context() context.Context {
return r.ctx
}