Skip to content

Commit

Permalink
fix(graph): Allow to combine $search and $filter in users query
Browse files Browse the repository at this point in the history
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"
  • Loading branch information
rhafer committed Dec 2, 2024
1 parent 53d8d92 commit 82d2193
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
32 changes: 24 additions & 8 deletions services/graph/pkg/identity/ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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{}
Expand All @@ -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")
Expand Down
4 changes: 2 additions & 2 deletions services/graph/pkg/identity/ldap_education_class.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
11 changes: 8 additions & 3 deletions services/graph/pkg/identity/ldap_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 82d2193

Please sign in to comment.