feat: user v2 service query (#7095)

* feat: add query endpoints for user v2 api

* fix: correct integration tests

* fix: correct linting

* fix: correct linting

* fix: comment out permission check on user get and list

* fix: permission check on user v2 query

* fix: merge back origin/main

* fix: add search query in user emails

* fix: reset count for SearchUser if users are removed due to permissions

* fix: reset count for SearchUser if users are removed due to permissions

---------

Co-authored-by: Elio Bischof <elio@zitadel.com>
This commit is contained in:
Stefan Benz
2024-01-17 10:00:10 +01:00
committed by GitHub
parent 853181155d
commit d9d376a275
18 changed files with 1667 additions and 45 deletions

View File

@@ -122,6 +122,29 @@ type NotifyUser struct {
PasswordSet bool
}
func (u *Users) RemoveNoPermission(ctx context.Context, permissionCheck domain.PermissionCheck) {
removableIndexes := make([]int, 0)
for i := range u.Users {
ctxData := authz.GetCtxData(ctx)
if ctxData.UserID != u.Users[i].ID {
if err := permissionCheck(ctx, domain.PermissionUserRead, ctxData.OrgID, u.Users[i].ID); err != nil {
removableIndexes = append(removableIndexes, i)
}
}
}
removed := 0
for _, removeIndex := range removableIndexes {
u.Users = removeUser(u.Users, removeIndex-removed)
removed++
}
// reset count as some users could be removed
u.SearchResponse.Count = uint64(len(u.Users))
}
func removeUser(slice []*User, s int) []*User {
return append(slice[:s], slice[s+1:]...)
}
type UserSearchQueries struct {
SearchRequest
Queries []SearchQuery
@@ -579,7 +602,6 @@ func (q *Queries) SearchUsers(ctx context.Context, queries *UserSearchQueries) (
if err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-AG4gs", "Errors.Internal")
}
users.State, err = q.latestState(ctx, userTable)
return users, err
}

View File

@@ -1,6 +1,7 @@
package query
import (
"context"
"database/sql"
"database/sql/driver"
"errors"
@@ -8,6 +9,7 @@ import (
"regexp"
"testing"
"github.com/stretchr/testify/require"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/crypto"
@@ -16,6 +18,129 @@ import (
"github.com/zitadel/zitadel/internal/zerrors"
)
func Test_RemoveNoPermission(t *testing.T) {
type want struct {
users []*User
}
tests := []struct {
name string
want want
users *Users
permissions []string
}{
{
"permissions for all users",
want{
users: []*User{
{ID: "first"}, {ID: "second"}, {ID: "third"},
},
},
&Users{
Users: []*User{
{ID: "first"}, {ID: "second"}, {ID: "third"},
},
},
[]string{"first", "second", "third"},
},
{
"permissions for one user, first",
want{
users: []*User{
{ID: "first"},
},
},
&Users{
Users: []*User{
{ID: "first"}, {ID: "second"}, {ID: "third"},
},
},
[]string{"first"},
},
{
"permissions for one user, second",
want{
users: []*User{
{ID: "second"},
},
},
&Users{
Users: []*User{
{ID: "first"}, {ID: "second"}, {ID: "third"},
},
},
[]string{"second"},
},
{
"permissions for one user, third",
want{
users: []*User{
{ID: "third"},
},
},
&Users{
Users: []*User{
{ID: "first"}, {ID: "second"}, {ID: "third"},
},
},
[]string{"third"},
},
{
"permissions for two users, first",
want{
users: []*User{
{ID: "first"}, {ID: "third"},
},
},
&Users{
Users: []*User{
{ID: "first"}, {ID: "second"}, {ID: "third"},
},
},
[]string{"first", "third"},
},
{
"permissions for two users, second",
want{
users: []*User{
{ID: "second"}, {ID: "third"},
},
},
&Users{
Users: []*User{
{ID: "first"}, {ID: "second"}, {ID: "third"},
},
},
[]string{"second", "third"},
},
{
"no permissions",
want{
users: []*User{},
},
&Users{
Users: []*User{
{ID: "first"}, {ID: "second"}, {ID: "third"},
},
},
[]string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
checkPermission := func(ctx context.Context, permission, orgID, resourceID string) (err error) {
for _, perm := range tt.permissions {
if resourceID == perm {
return nil
}
}
return errors.New("failed")
}
tt.users.RemoveNoPermission(context.Background(), checkPermission)
require.Equal(t, tt.want.users, tt.users.Users)
})
}
}
var (
loginNamesQuery = `SELECT login_names.user_id, ARRAY_AGG(login_names.login_name)::TEXT[] AS loginnames, ARRAY_AGG(LOWER(login_names.login_name))::TEXT[] AS loginnames_lower, login_names.instance_id` +
` FROM projections.login_names3 AS login_names` +