graph: Initial support for $filter in /users (#5533)
This adds some initial support for using $filter (as defined in the odata spec) on the /users endpoint. Currently the following filters are supported: A single filter on `id` property of the `memberOf` relation of users. To list all users that are members of a specific group: ``` curl 'https://localhost:9200/graph/v1.0/users?$filter=memberOf/any(m:m/id eq '262982c1-2362-4afa-bfdf-8cbfef64a06e') ``` A logical AND filteri on the `id` property of the `memberOf` relation of users. `$filter=memberOf/any(m:m/id eq 262982c1-2362-4afa-bfdf-8cbfef64a06e) and memberOf/any(m:m/id eq 6040aa17-9c64-4fef-9bd0-77234d71bad0)` This will cause at least two queries on the identity backend. The `and` operation is performed locally. Closes: #5487
This commit is contained in:
@@ -35,7 +35,8 @@ type Backend interface {
|
||||
DeleteGroup(ctx context.Context, id string) error
|
||||
GetGroup(ctx context.Context, nameOrID string, queryParam url.Values) (*libregraph.Group, error)
|
||||
GetGroups(ctx context.Context, queryParam url.Values) ([]*libregraph.Group, error)
|
||||
GetGroupMembers(ctx context.Context, id string) ([]*libregraph.User, error)
|
||||
// GetGroupMembers list all members of a group
|
||||
GetGroupMembers(ctx context.Context, id string, oreq *godata.GoDataRequest) ([]*libregraph.User, error)
|
||||
// AddMembersToGroup adds new members (reference by a slice of IDs) to supplied group in the identity backend.
|
||||
AddMembersToGroup(ctx context.Context, groupID string, memberID []string) error
|
||||
// RemoveMemberFromGroup removes a single member (by ID) from a group
|
||||
|
||||
@@ -193,7 +193,7 @@ func (i *CS3) DeleteGroup(ctx context.Context, id string) error {
|
||||
}
|
||||
|
||||
// GetGroupMembers implements the Backend Interface. It's currently not supported for the CS3 backend
|
||||
func (i *CS3) GetGroupMembers(ctx context.Context, groupID string) ([]*libregraph.User, error) {
|
||||
func (i *CS3) GetGroupMembers(ctx context.Context, groupID string, _ *godata.GoDataRequest) ([]*libregraph.User, error) {
|
||||
return nil, errorcode.New(errorcode.NotSupported, "not implemented")
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/CiscoM31/godata"
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/gofrs/uuid"
|
||||
ldapdn "github.com/libregraph/idm/pkg/ldapdn"
|
||||
@@ -134,9 +135,15 @@ func (i *LDAP) GetGroups(ctx context.Context, queryParam url.Values) ([]*libregr
|
||||
}
|
||||
|
||||
// GetGroupMembers implements the Backend Interface for the LDAP Backend
|
||||
func (i *LDAP) GetGroupMembers(ctx context.Context, groupID string) ([]*libregraph.User, error) {
|
||||
func (i *LDAP) GetGroupMembers(ctx context.Context, groupID string, req *godata.GoDataRequest) ([]*libregraph.User, error) {
|
||||
logger := i.logger.SubloggerWithRequestID(ctx)
|
||||
logger.Debug().Str("backend", "ldap").Msg("GetGroupMembers")
|
||||
|
||||
exp, err := GetExpandValues(req.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e, err := i.getLDAPGroupByNameOrID(groupID, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -149,6 +156,13 @@ func (i *LDAP) GetGroupMembers(ctx context.Context, groupID string) ([]*libregra
|
||||
}
|
||||
for _, member := range memberEntries {
|
||||
if u := i.createUserModelFromLDAP(member); u != nil {
|
||||
if slices.Contains(exp, "memberOf") {
|
||||
userGroups, err := i.getGroupsForUser(member.DN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.MemberOf = i.groupsFromLDAPEntries(userGroups)
|
||||
}
|
||||
result = append(result, u)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,13 +130,13 @@ func (_m *Backend) GetGroup(ctx context.Context, nameOrID string, queryParam url
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetGroupMembers provides a mock function with given fields: ctx, id
|
||||
func (_m *Backend) GetGroupMembers(ctx context.Context, id string) ([]*libregraph.User, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
// GetGroupMembers provides a mock function with given fields: ctx, id, oreq
|
||||
func (_m *Backend) GetGroupMembers(ctx context.Context, id string, oreq *godata.GoDataRequest) ([]*libregraph.User, error) {
|
||||
ret := _m.Called(ctx, id, oreq)
|
||||
|
||||
var r0 []*libregraph.User
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []*libregraph.User); ok {
|
||||
r0 = rf(ctx, id)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, *godata.GoDataRequest) []*libregraph.User); ok {
|
||||
r0 = rf(ctx, id, oreq)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*libregraph.User)
|
||||
@@ -144,8 +144,8 @@ func (_m *Backend) GetGroupMembers(ctx context.Context, id string) ([]*libregrap
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, *godata.GoDataRequest) error); ok {
|
||||
r1 = rf(ctx, id, oreq)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user