add memberOf slice to /user/{id} & members slice to /groups/{id} endpoint

Signed-off-by: Christian Richter <crichter@owncloud.com>
This commit is contained in:
Christian Richter
2022-06-09 14:36:23 +02:00
parent fff40db69c
commit c358540361
6 changed files with 139 additions and 22 deletions
+2 -2
View File
@@ -15,14 +15,14 @@ type Backend interface {
DeleteUser(ctx context.Context, nameOrID string) error
// UpdateUser applies changes to given user, identified by username or id
UpdateUser(ctx context.Context, nameOrID string, user libregraph.User) (*libregraph.User, error)
GetUser(ctx context.Context, nameOrID string) (*libregraph.User, error)
GetUser(ctx context.Context, nameOrID string, queryParam url.Values) (*libregraph.User, error)
GetUsers(ctx context.Context, queryParam url.Values) ([]*libregraph.User, error)
// CreateGroup creates the supplied group in the identity backend.
CreateGroup(ctx context.Context, group libregraph.Group) (*libregraph.Group, error)
// DeleteGroup deletes a given group, identified by id
DeleteGroup(ctx context.Context, id string) error
GetGroup(ctx context.Context, nameOrID string) (*libregraph.Group, 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)
// AddMembersToGroup adds new members (reference by a slice of IDs) to supplied group in the identity backend.
+2 -2
View File
@@ -39,7 +39,7 @@ func (i *CS3) UpdateUser(ctx context.Context, nameOrID string, user libregraph.U
return nil, errNotImplemented
}
func (i *CS3) GetUser(ctx context.Context, userID string) (*libregraph.User, error) {
func (i *CS3) GetUser(ctx context.Context, userID string, queryParam url.Values) (*libregraph.User, error) {
client, err := pool.GetGatewayServiceClient(i.Config.Address)
if err != nil {
i.Logger.Error().Err(err).Msg("could not get client")
@@ -147,7 +147,7 @@ func (i *CS3) CreateGroup(ctx context.Context, group libregraph.Group) (*libregr
return nil, errorcode.New(errorcode.NotSupported, "not implemented")
}
func (i *CS3) GetGroup(ctx context.Context, groupID string) (*libregraph.Group, error) {
func (i *CS3) GetGroup(ctx context.Context, groupID string, queryParam url.Values) (*libregraph.Group, error) {
client, err := pool.GetGatewayServiceClient(i.Config.Address)
if err != nil {
i.Logger.Error().Err(err).Msg("could not get client")
+52 -10
View File
@@ -355,13 +355,32 @@ func (i *LDAP) getLDAPUserByFilter(filter string) (*ldap.Entry, error) {
return res.Entries[0], nil
}
func (i *LDAP) GetUser(ctx context.Context, nameOrID string) (*libregraph.User, error) {
func (i *LDAP) GetUser(ctx context.Context, nameOrID string, queryParam url.Values) (*libregraph.User, error) {
i.logger.Debug().Str("backend", "ldap").Msg("GetUser")
e, err := i.getLDAPUserByNameOrID(nameOrID)
if err != nil {
return nil, err
}
return i.createUserModelFromLDAP(e), nil
userGroups, err := i.getGroupsForUser(e.DN)
if err != nil {
return nil, err
}
sel := strings.Split(queryParam.Get("$select"), ",")
exp := strings.Split(queryParam.Get("$expand"), ",")
u := i.createUserModelFromLDAP(e)
if slices.Contains(sel, "memberOf") || slices.Contains(exp, "memberOf") {
if err != nil {
return nil, err
}
if len(userGroups) > 0 {
groups := make([]libregraph.Group, 0, len(userGroups))
for _, g := range userGroups {
groups = append(groups, *i.createGroupModelFromLDAP(g))
}
u.MemberOf = groups
}
}
return u, nil
}
func (i *LDAP) GetUsers(ctx context.Context, queryParam url.Values) ([]*libregraph.User, error) {
@@ -406,11 +425,7 @@ func (i *LDAP) GetUsers(ctx context.Context, queryParam url.Values) ([]*libregra
exp := strings.Split(queryParam.Get("$expand"), ",")
u := i.createUserModelFromLDAP(e)
if slices.Contains(sel, "memberOf") || slices.Contains(exp, "memberOf") {
groupFilter := fmt.Sprintf(
"(%s=%s)",
i.groupAttributeMap.member, e.DN,
)
userGroups, err := i.getLDAPGroupsByFilter(groupFilter, false, false)
userGroups, err := i.getGroupsForUser(e.DN)
if err != nil {
return nil, err
}
@@ -431,13 +446,41 @@ func (i *LDAP) GetUsers(ctx context.Context, queryParam url.Values) ([]*libregra
return users, nil
}
func (i *LDAP) GetGroup(ctx context.Context, nameOrID string) (*libregraph.Group, error) {
func (i *LDAP) getGroupsForUser(dn string) ([]*ldap.Entry, error) {
groupFilter := fmt.Sprintf(
"(%s=%s)",
i.groupAttributeMap.member, dn,
)
userGroups, err := i.getLDAPGroupsByFilter(groupFilter, false, false)
if err != nil {
return nil, err
}
return userGroups, nil
}
func (i *LDAP) GetGroup(ctx context.Context, nameOrID string, queryParam url.Values) (*libregraph.Group, error) {
i.logger.Debug().Str("backend", "ldap").Msg("GetGroup")
e, err := i.getLDAPGroupByNameOrID(nameOrID, true)
if err != nil {
return nil, err
}
return i.createGroupModelFromLDAP(e), nil
sel := strings.Split(queryParam.Get("$select"), ",")
exp := strings.Split(queryParam.Get("$expand"), ",")
g := i.createGroupModelFromLDAP(e)
if slices.Contains(sel, "members") || slices.Contains(exp, "members") {
members, err := i.GetGroupMembers(ctx, *g.Id)
if err != nil {
return nil, err
}
if len(members) > 1 {
m := make([]libregraph.User, 0, len(members))
for _, u := range members {
m = append(m, *u)
}
g.Members = m
}
}
return g, nil
}
func (i *LDAP) getLDAPGroupByID(id string, requestMembers bool) (*ldap.Entry, error) {
@@ -581,7 +624,6 @@ func (i *LDAP) GetGroups(ctx context.Context, queryParam url.Values) ([]*libregr
exp := strings.Split(queryParam.Get("$expand"), ",")
g := i.createGroupModelFromLDAP(e)
if slices.Contains(sel, "members") || slices.Contains(exp, "members") {
members, err := i.GetGroupMembers(ctx, *g.Id)
if err != nil {
return nil, err
+81 -6
View File
@@ -125,7 +125,24 @@ func TestGetUser(t *testing.T) {
return nil, ldap.NewError(ldap.LDAPResultSizeLimitExceeded, errors.New("mock"))
}
b, _ := getMockedBackend(&sf, lconfig, &logger)
_, err := b.GetUser(context.Background(), "fred")
queryParamExpand := url.Values{
"$expand": []string{"memberOf"},
}
queryParamSelect := url.Values{
"$select": []string{"memberOf"},
}
_, err := b.GetUser(context.Background(), "fred", nil)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
_, err = b.GetUser(context.Background(), "fred", queryParamExpand)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
_, err = b.GetUser(context.Background(), "fred", queryParamSelect)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
@@ -135,7 +152,17 @@ func TestGetUser(t *testing.T) {
return &ldap.SearchResult{}, nil
}
b, _ = getMockedBackend(&sf, lconfig, &logger)
_, err = b.GetUser(context.Background(), "fred")
_, err = b.GetUser(context.Background(), "fred", nil)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
_, err = b.GetUser(context.Background(), "fred", queryParamExpand)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
_, err = b.GetUser(context.Background(), "fred", queryParamSelect)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
@@ -147,7 +174,21 @@ func TestGetUser(t *testing.T) {
}, nil
}
b, _ = getMockedBackend(&sf, lconfig, &logger)
u, err := b.GetUser(context.Background(), "user")
u, err := b.GetUser(context.Background(), "user", nil)
if err != nil {
t.Errorf("Expected GetUser to succeed. Got %s", err.Error())
} else if *u.Id != userEntry.GetEqualFoldAttributeValue(b.userAttributeMap.id) {
t.Errorf("Expected GetUser to return a valid user")
}
u, err = b.GetUser(context.Background(), "user", queryParamExpand)
if err != nil {
t.Errorf("Expected GetUser to succeed. Got %s", err.Error())
} else if *u.Id != userEntry.GetEqualFoldAttributeValue(b.userAttributeMap.id) {
t.Errorf("Expected GetUser to return a valid user")
}
u, err = b.GetUser(context.Background(), "user", queryParamSelect)
if err != nil {
t.Errorf("Expected GetUser to succeed. Got %s", err.Error())
} else if *u.Id != userEntry.GetEqualFoldAttributeValue(b.userAttributeMap.id) {
@@ -182,8 +223,22 @@ func TestGetGroup(t *testing.T) {
var sf searchFunc = func(*ldap.SearchRequest) (*ldap.SearchResult, error) {
return nil, ldap.NewError(ldap.LDAPResultSizeLimitExceeded, errors.New("mock"))
}
queryParamExpand := url.Values{
"$expand": []string{"memberOf"},
}
queryParamSelect := url.Values{
"$select": []string{"memberOf"},
}
b, _ := getMockedBackend(&sf, lconfig, &logger)
_, err := b.GetGroup(context.Background(), "group")
_, err := b.GetGroup(context.Background(), "group", nil)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
_, err = b.GetGroup(context.Background(), "group", queryParamExpand)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
_, err = b.GetGroup(context.Background(), "group", queryParamSelect)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
@@ -193,7 +248,15 @@ func TestGetGroup(t *testing.T) {
return &ldap.SearchResult{}, nil
}
b, _ = getMockedBackend(&sf, lconfig, &logger)
_, err = b.GetGroup(context.Background(), "group")
_, err = b.GetGroup(context.Background(), "group", nil)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
_, err = b.GetGroup(context.Background(), "group", queryParamExpand)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
_, err = b.GetGroup(context.Background(), "group", queryParamSelect)
if err == nil || err.Error() != "itemNotFound" {
t.Errorf("Expected 'itemNotFound' got '%s'", err.Error())
}
@@ -205,7 +268,19 @@ func TestGetGroup(t *testing.T) {
}, nil
}
b, _ = getMockedBackend(&sf, lconfig, &logger)
g, err := b.GetGroup(context.Background(), "group")
g, err := b.GetGroup(context.Background(), "group", nil)
if err != nil {
t.Errorf("Expected GetGroup to succeed. Got %s", err.Error())
} else if *g.Id != groupEntry.GetEqualFoldAttributeValue(b.groupAttributeMap.id) {
t.Errorf("Expected GetGroup to return a valid group")
}
g, err = b.GetGroup(context.Background(), "group", queryParamExpand)
if err != nil {
t.Errorf("Expected GetGroup to succeed. Got %s", err.Error())
} else if *g.Id != groupEntry.GetEqualFoldAttributeValue(b.groupAttributeMap.id) {
t.Errorf("Expected GetGroup to return a valid group")
}
g, err = b.GetGroup(context.Background(), "group", queryParamSelect)
if err != nil {
t.Errorf("Expected GetGroup to succeed. Got %s", err.Error())
} else if *g.Id != groupEntry.GetEqualFoldAttributeValue(b.groupAttributeMap.id) {
+1 -1
View File
@@ -162,7 +162,7 @@ func (g Graph) GetGroup(w http.ResponseWriter, r *http.Request) {
return
}
group, err := g.identityBackend.GetGroup(r.Context(), groupID)
group, err := g.identityBackend.GetGroup(r.Context(), groupID, r.URL.Query())
if err != nil {
var errcode errorcode.Error
if errors.As(err, &errcode) {
+1 -1
View File
@@ -159,7 +159,7 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
return
}
user, err := g.identityBackend.GetUser(r.Context(), userID)
user, err := g.identityBackend.GetUser(r.Context(), userID, r.URL.Query())
if err != nil {
var errcode errorcode.Error