From 6a2dc6e2ba68090296f6bd31798da80be3d7d132 Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Tue, 26 Nov 2024 15:42:47 +0100 Subject: [PATCH] fix(graph): Allow to combine $search and $filter in users query This fixes the 'graph/v1.0/users' endpoint to allow a combination of a memberOf filter in $filter with a search string in $search. Allowing queries like: $filter=(memberOf/any(m:m/id eq 509a9dcd-bb37-4f4f-a01a-19dca27d9cfa))&$search="example" --- services/graph/pkg/identity/ldap.go | 32 ++++++++++++++----- .../pkg/identity/ldap_education_class.go | 4 +-- services/graph/pkg/identity/ldap_group.go | 11 +++++-- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/services/graph/pkg/identity/ldap.go b/services/graph/pkg/identity/ldap.go index 4ff8b63a377..199fc5f28b9 100644 --- a/services/graph/pkg/identity/ldap.go +++ b/services/graph/pkg/identity/ldap.go @@ -217,7 +217,7 @@ func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregrap } // Read back user from LDAP to get the generated UUID - e, err := i.getUserByDN(ar.DN) + e, err := i.getUserByDN(ar.DN, "") if err != nil { return nil, err } @@ -390,7 +390,7 @@ func (i *LDAP) UpdateUser(ctx context.Context, nameOrID string, user libregraph. } // Read back user from LDAP to get the generated UUID - e, err = i.getUserByDN(e.DN) + e, err = i.getUserByDN(e.DN, "") if err != nil { return nil, err } @@ -406,11 +406,27 @@ func (i *LDAP) UpdateUser(ctx context.Context, nameOrID string, user libregraph. return returnUser, nil } -func (i *LDAP) getUserByDN(dn string) (*ldap.Entry, error) { - filter := fmt.Sprintf("(objectClass=%s)", i.userObjectClass) +func (i *LDAP) getUserByDN(dn, searchTerm string) (*ldap.Entry, error) { + baseFilter := fmt.Sprintf("(objectClass=%s)", i.userObjectClass) + userFilter := "" if i.userFilter != "" { - filter = fmt.Sprintf("(&%s(%s))", filter, i.userFilter) + userFilter = fmt.Sprintf("(%s)", i.userFilter) + } + searchFilter := "" + if searchTerm != "" { + searchTerm = ldap.EscapeFilter(searchTerm) + searchFilter = fmt.Sprintf( + "(|(%s=*%s*)(%s=*%s*)(%s=*%s*))", + i.userAttributeMap.userName, searchTerm, + i.userAttributeMap.mail, searchTerm, + i.userAttributeMap.displayName, searchTerm, + ) + } + + filter := baseFilter + if userFilter != "" || searchFilter != "" { + filter = fmt.Sprintf("(&%s%s%s)", baseFilter, userFilter, searchFilter) } return i.getEntryByDN(dn, i.getUserAttrTypesForSearch(), filter) @@ -722,7 +738,7 @@ func (i *LDAP) changeUserName(ctx context.Context, dn, originalUserName, newUser return nil, err } - u, err := i.getUserByDN(newFullDN) + u, err := i.getUserByDN(newFullDN, "") if err != nil { return nil, err } @@ -1071,7 +1087,7 @@ func (i *LDAP) removeEntryByDNAndAttributeFromEntry(entry *ldap.Entry, dn string } // expandLDAPAttributeEntries reads an attribute from a ldap entry and expands to users -func (i *LDAP) expandLDAPAttributeEntries(ctx context.Context, e *ldap.Entry, attribute string) ([]*ldap.Entry, error) { +func (i *LDAP) expandLDAPAttributeEntries(ctx context.Context, e *ldap.Entry, attribute, searchTerm string) ([]*ldap.Entry, error) { logger := i.logger.SubloggerWithRequestID(ctx) logger.Debug().Str("backend", "ldap").Msg("ExpandLDAPAttributeEntries") result := []*ldap.Entry{} @@ -1081,7 +1097,7 @@ func (i *LDAP) expandLDAPAttributeEntries(ctx context.Context, e *ldap.Entry, at continue } logger.Debug().Str("entryDN", entryDN).Msg("lookup") - ue, err := i.getUserByDN(entryDN) + ue, err := i.getUserByDN(entryDN, searchTerm) if err != nil { // Ignore errors when reading a specific entry fails, just log them and continue logger.Debug().Err(err).Str("entry", entryDN).Msg("error reading attribute member entry") diff --git a/services/graph/pkg/identity/ldap_education_class.go b/services/graph/pkg/identity/ldap_education_class.go index 351c7c6c6c4..88ade7912dc 100644 --- a/services/graph/pkg/identity/ldap_education_class.go +++ b/services/graph/pkg/identity/ldap_education_class.go @@ -239,7 +239,7 @@ func (i *LDAP) GetEducationClassMembers(ctx context.Context, id string) ([]*libr return nil, err } - memberEntries, err := i.expandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member) + memberEntries, err := i.expandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member, "") result := make([]*libregraph.EducationUser, 0, len(memberEntries)) if err != nil { return nil, err @@ -366,7 +366,7 @@ func (i *LDAP) GetEducationClassTeachers(ctx context.Context, classID string) ([ return nil, err } - teacherEntries, err := i.expandLDAPAttributeEntries(ctx, class, i.educationConfig.classAttributeMap.teachers) + teacherEntries, err := i.expandLDAPAttributeEntries(ctx, class, i.educationConfig.classAttributeMap.teachers, "") result := make([]*libregraph.EducationUser, 0, len(teacherEntries)) if err != nil { return nil, err diff --git a/services/graph/pkg/identity/ldap_group.go b/services/graph/pkg/identity/ldap_group.go index 67d3de3f35c..ff7d74c3381 100644 --- a/services/graph/pkg/identity/ldap_group.go +++ b/services/graph/pkg/identity/ldap_group.go @@ -38,7 +38,7 @@ func (i *LDAP) GetGroup(ctx context.Context, nameOrID string, queryParam url.Val return nil, errorcode.New(errorcode.ItemNotFound, "not found") } if slices.Contains(sel, "members") || slices.Contains(exp, "members") { - members, err := i.expandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member) + members, err := i.expandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member, "") if err != nil { return nil, err } @@ -123,7 +123,7 @@ func (i *LDAP) GetGroups(ctx context.Context, oreq *godata.GoDataRequest) ([]*li continue } if expandMembers { - members, err := i.expandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member) + members, err := i.expandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member, "") if err != nil { return nil, err } @@ -156,7 +156,12 @@ func (i *LDAP) GetGroupMembers(ctx context.Context, groupID string, req *godata. return nil, err } - memberEntries, err := i.expandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member) + searchTerm, err := GetSearchValues(req.Query) + if err != nil { + return nil, err + } + + memberEntries, err := i.expandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member, searchTerm) result := make([]*libregraph.User, 0, len(memberEntries)) if err != nil { return nil, err