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"
This commit is contained in:
Ralf Haferkamp
2024-11-26 15:42:47 +01:00
committed by Ralf Haferkamp
parent 53d8d928f8
commit 82d2193ad6
3 changed files with 34 additions and 13 deletions

View File

@@ -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")

View File

@@ -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

View File

@@ -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