settings: Add ListRoleAssignmentByRole
This adds the implementation for ListRolesAssignments by role-id to the metadata backend. Because of the current layout of the account folders and assignment files this is currently still very inefficient. Related Issue: #8939
This commit is contained in:
committed by
Ralf Haferkamp
parent
90f7cc23f4
commit
d7f10f38a0
@@ -355,7 +355,8 @@ func (g Service) ListRoleAssignmentsFiltered(ctx context.Context, req *settingss
|
|||||||
accountUUID := getValidatedAccountUUID(ctx, filters[0].GetAccountUuid())
|
accountUUID := getValidatedAccountUUID(ctx, filters[0].GetAccountUuid())
|
||||||
r, err = g.manager.ListRoleAssignments(accountUUID)
|
r, err = g.manager.ListRoleAssignments(accountUUID)
|
||||||
case settingsmsg.UserRoleAssignmentFilter_TYPE_ROLE:
|
case settingsmsg.UserRoleAssignmentFilter_TYPE_ROLE:
|
||||||
err = fmt.Errorf("filtering by role not implemented")
|
roleID := filters[0].GetRoleId()
|
||||||
|
r, err = g.manager.ListRoleAssignmentsByRole(roleID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return merrors.NotFound(g.id, "%s", err)
|
return merrors.NotFound(g.id, "%s", err)
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ func TestListPermissionsOfOtherUser(t *testing.T) {
|
|||||||
assert.Contains(t, err.Error(), req.AccountUuid)
|
assert.Contains(t, err.Error(), req.AccountUuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestListRoleAssignmentsFiltered(t *testing.T) {
|
func TestListRoleAssignmentsFilteredValidation(t *testing.T) {
|
||||||
manager := &mocks.Manager{}
|
manager := &mocks.Manager{}
|
||||||
svc := Service{
|
svc := Service{
|
||||||
manager: manager,
|
manager: manager,
|
||||||
@@ -336,3 +336,117 @@ func TestListRoleAssignmentsFiltered(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListRoleAssignmentsFilteredByAccount(t *testing.T) {
|
||||||
|
accountUUID := "61445573-4dbe-4d56-88dc-88ab47aceba7"
|
||||||
|
|
||||||
|
tests := map[string]struct {
|
||||||
|
result []*settingsmsg.UserRoleAssignment
|
||||||
|
err error
|
||||||
|
status int32
|
||||||
|
}{
|
||||||
|
"handles manager error": {
|
||||||
|
result: nil,
|
||||||
|
err: assert.AnError,
|
||||||
|
status: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
"succeeds with results": {
|
||||||
|
result: []*settingsmsg.UserRoleAssignment{
|
||||||
|
{
|
||||||
|
Id: "00000000-0000-0000-0000-000000000001",
|
||||||
|
AccountUuid: accountUUID,
|
||||||
|
RoleId: "aceb15b8-7486-479f-ae32-c91118e07a39",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
status: http.StatusOK,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, test := range tests {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
manager := &mocks.Manager{}
|
||||||
|
svc := Service{
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
manager.On("ListRoleAssignments", mock.Anything).Return(test.result, test.err)
|
||||||
|
req := &v0.ListRoleAssignmentsFilteredRequest{
|
||||||
|
Filters: []*settingsmsg.UserRoleAssignmentFilter{
|
||||||
|
{
|
||||||
|
Type: settingsmsg.UserRoleAssignmentFilter_TYPE_ACCOUNT,
|
||||||
|
Term: &settingsmsg.UserRoleAssignmentFilter_AccountUuid{
|
||||||
|
AccountUuid: accountUUID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res := v0.ListRoleAssignmentsResponse{}
|
||||||
|
err := svc.ListRoleAssignmentsFiltered(ctxWithUUID, req, &res)
|
||||||
|
switch test.err {
|
||||||
|
case nil:
|
||||||
|
assert.Nil(t, err)
|
||||||
|
default:
|
||||||
|
merr, ok := merrors.As(err)
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, int32(test.status), merr.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListRoleAssignmentsFilteredByRole(t *testing.T) {
|
||||||
|
roleID := "61445573-4dbe-4d56-88dc-88ab47aceba7"
|
||||||
|
|
||||||
|
tests := map[string]struct {
|
||||||
|
result []*settingsmsg.UserRoleAssignment
|
||||||
|
err error
|
||||||
|
status int32
|
||||||
|
}{
|
||||||
|
"handles manager error": {
|
||||||
|
result: nil,
|
||||||
|
err: assert.AnError,
|
||||||
|
status: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
"succeeds with results": {
|
||||||
|
result: []*settingsmsg.UserRoleAssignment{
|
||||||
|
{
|
||||||
|
Id: "00000000-0000-0000-0000-000000000001",
|
||||||
|
AccountUuid: "aceb15b8-7486-479f-ae32-c91118e07a39",
|
||||||
|
RoleId: roleID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
status: http.StatusOK,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, test := range tests {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
manager := &mocks.Manager{}
|
||||||
|
svc := Service{
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
manager.On("ListRoleAssignmentsByRole", mock.Anything).Return(test.result, test.err)
|
||||||
|
req := &v0.ListRoleAssignmentsFilteredRequest{
|
||||||
|
Filters: []*settingsmsg.UserRoleAssignmentFilter{
|
||||||
|
{
|
||||||
|
Type: settingsmsg.UserRoleAssignmentFilter_TYPE_ROLE,
|
||||||
|
Term: &settingsmsg.UserRoleAssignmentFilter_RoleId{
|
||||||
|
RoleId: roleID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res := v0.ListRoleAssignmentsResponse{}
|
||||||
|
err := svc.ListRoleAssignmentsFiltered(ctxWithUUID, req, &res)
|
||||||
|
switch test.err {
|
||||||
|
case nil:
|
||||||
|
assert.Nil(t, err)
|
||||||
|
default:
|
||||||
|
merr, ok := merrors.As(err)
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, int32(test.status), merr.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -256,6 +256,64 @@ func (_c *Manager_ListRoleAssignments_Call) RunAndReturn(run func(string) ([]*v0
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListRoleAssignmentsByRole provides a mock function with given fields: roleID
|
||||||
|
func (_m *Manager) ListRoleAssignmentsByRole(roleID string) ([]*v0.UserRoleAssignment, error) {
|
||||||
|
ret := _m.Called(roleID)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for ListRoleAssignmentsByRole")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*v0.UserRoleAssignment
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(string) ([]*v0.UserRoleAssignment, error)); ok {
|
||||||
|
return rf(roleID)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(string) []*v0.UserRoleAssignment); ok {
|
||||||
|
r0 = rf(roleID)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*v0.UserRoleAssignment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||||
|
r1 = rf(roleID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manager_ListRoleAssignmentsByRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListRoleAssignmentsByRole'
|
||||||
|
type Manager_ListRoleAssignmentsByRole_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRoleAssignmentsByRole is a helper method to define mock.On call
|
||||||
|
// - roleID string
|
||||||
|
func (_e *Manager_Expecter) ListRoleAssignmentsByRole(roleID interface{}) *Manager_ListRoleAssignmentsByRole_Call {
|
||||||
|
return &Manager_ListRoleAssignmentsByRole_Call{Call: _e.mock.On("ListRoleAssignmentsByRole", roleID)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Manager_ListRoleAssignmentsByRole_Call) Run(run func(roleID string)) *Manager_ListRoleAssignmentsByRole_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].(string))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Manager_ListRoleAssignmentsByRole_Call) Return(_a0 []*v0.UserRoleAssignment, _a1 error) *Manager_ListRoleAssignmentsByRole_Call {
|
||||||
|
_c.Call.Return(_a0, _a1)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Manager_ListRoleAssignmentsByRole_Call) RunAndReturn(run func(string) ([]*v0.UserRoleAssignment, error)) *Manager_ListRoleAssignmentsByRole_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
// ListValues provides a mock function with given fields: bundleID, accountUUID
|
// ListValues provides a mock function with given fields: bundleID, accountUUID
|
||||||
func (_m *Manager) ListValues(bundleID string, accountUUID string) ([]*v0.Value, error) {
|
func (_m *Manager) ListValues(bundleID string, accountUUID string) ([]*v0.Value, error) {
|
||||||
ret := _m.Called(bundleID, accountUUID)
|
ret := _m.Called(bundleID, accountUUID)
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ type ValueManager interface {
|
|||||||
// RoleAssignmentManager is a role assignment service interface for abstraction of storage implementations
|
// RoleAssignmentManager is a role assignment service interface for abstraction of storage implementations
|
||||||
type RoleAssignmentManager interface {
|
type RoleAssignmentManager interface {
|
||||||
ListRoleAssignments(accountUUID string) ([]*settingsmsg.UserRoleAssignment, error)
|
ListRoleAssignments(accountUUID string) ([]*settingsmsg.UserRoleAssignment, error)
|
||||||
|
ListRoleAssignmentsByRole(roleID string) ([]*settingsmsg.UserRoleAssignment, error)
|
||||||
WriteRoleAssignment(accountUUID, roleID string) (*settingsmsg.UserRoleAssignment, error)
|
WriteRoleAssignment(accountUUID, roleID string) (*settingsmsg.UserRoleAssignment, error)
|
||||||
RemoveRoleAssignment(assignmentID string) error
|
RemoveRoleAssignment(assignmentID string) error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,59 @@ func (s *Store) ListRoleAssignments(accountUUID string) ([]*settingsmsg.UserRole
|
|||||||
return ass, nil
|
return ass, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListRoleAssignmentsByRole returns all role assignmentes matching the give roleID
|
||||||
|
func (s *Store) ListRoleAssignmentsByRole(roleID string) ([]*settingsmsg.UserRoleAssignment, error) {
|
||||||
|
s.Init()
|
||||||
|
ctx := context.TODO()
|
||||||
|
accountIDs, err := s.mdc.ReadDir(ctx, accountsFolderLocation)
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
// continue
|
||||||
|
case errtypes.NotFound:
|
||||||
|
return make([]*settingsmsg.UserRoleAssignment, 0), nil
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
assignments := make([]*settingsmsg.UserRoleAssignment, 0, len(accountIDs))
|
||||||
|
|
||||||
|
// This is very inefficient, with the current layout we need to iterated through all
|
||||||
|
// account folders and read each assignment file in there to check if that contains
|
||||||
|
// the give role ID.
|
||||||
|
for _, account := range accountIDs {
|
||||||
|
assignmentIDs, err := s.mdc.ReadDir(ctx, accountPath(account))
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
// continue
|
||||||
|
case errtypes.NotFound:
|
||||||
|
return make([]*settingsmsg.UserRoleAssignment, 0), nil
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, assignmentID := range assignmentIDs {
|
||||||
|
b, err := s.mdc.SimpleDownload(ctx, assignmentPath(account, assignmentID))
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
// continue
|
||||||
|
case errtypes.NotFound:
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a := &settingsmsg.UserRoleAssignment{}
|
||||||
|
err = json.Unmarshal(b, a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if a.GetRoleId() == roleID {
|
||||||
|
assignments = append(assignments, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assignments, nil
|
||||||
|
}
|
||||||
|
|
||||||
// WriteRoleAssignment appends the given role assignment to the existing assignments of the respective account.
|
// WriteRoleAssignment appends the given role assignment to the existing assignments of the respective account.
|
||||||
func (s *Store) WriteRoleAssignment(accountUUID, roleID string) (*settingsmsg.UserRoleAssignment, error) {
|
func (s *Store) WriteRoleAssignment(accountUUID, roleID string) (*settingsmsg.UserRoleAssignment, error) {
|
||||||
s.Init()
|
s.Init()
|
||||||
|
|||||||
@@ -14,8 +14,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
einstein = "a4d07560-a670-4be9-8d60-9b547751a208"
|
einstein = "00000000-0000-0000-0000-000000000001"
|
||||||
//marie = "3c054db3-eec1-4ca4-b985-bc56dcf560cb"
|
marie = "00000000-0000-0000-0000-000000000002"
|
||||||
|
moss = "00000000-0000-0000-0000-000000000003"
|
||||||
|
|
||||||
|
role1 = "11111111-1111-1111-1111-111111111111"
|
||||||
|
role2 = "22222222-2222-2222-2222-222222222222"
|
||||||
|
|
||||||
s = &Store{
|
s = &Store{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
@@ -149,6 +153,79 @@ func TestAssignmentUniqueness(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListRoleAssignmentByRole(t *testing.T) {
|
||||||
|
type assignment struct {
|
||||||
|
userID string
|
||||||
|
roleID string
|
||||||
|
}
|
||||||
|
|
||||||
|
var scenarios = map[string]struct {
|
||||||
|
assignments []assignment
|
||||||
|
queryRole string
|
||||||
|
numResults int
|
||||||
|
}{
|
||||||
|
"just 2 assignments": {
|
||||||
|
assignments: []assignment{
|
||||||
|
{
|
||||||
|
userID: einstein,
|
||||||
|
roleID: role1,
|
||||||
|
}, {
|
||||||
|
userID: marie,
|
||||||
|
roleID: role1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
queryRole: role1,
|
||||||
|
numResults: 2,
|
||||||
|
},
|
||||||
|
"no assignments match": {
|
||||||
|
assignments: []assignment{
|
||||||
|
{
|
||||||
|
userID: einstein,
|
||||||
|
roleID: role1,
|
||||||
|
}, {
|
||||||
|
userID: marie,
|
||||||
|
roleID: role1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
queryRole: role2,
|
||||||
|
numResults: 0,
|
||||||
|
},
|
||||||
|
"only one assignment matches": {
|
||||||
|
assignments: []assignment{
|
||||||
|
{
|
||||||
|
userID: einstein,
|
||||||
|
roleID: role1,
|
||||||
|
}, {
|
||||||
|
userID: marie,
|
||||||
|
roleID: role1,
|
||||||
|
}, {
|
||||||
|
userID: moss,
|
||||||
|
roleID: role2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
queryRole: role2,
|
||||||
|
numResults: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, scenario := range scenarios {
|
||||||
|
scenario := scenario
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
for _, a := range scenario.assignments {
|
||||||
|
ass, err := s.WriteRoleAssignment(a.userID, a.roleID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ass.RoleId, a.roleID)
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := s.ListRoleAssignmentsByRole(scenario.queryRole)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, scenario.numResults, len(list))
|
||||||
|
for _, ass := range list {
|
||||||
|
require.Equal(t, ass.RoleId, scenario.queryRole)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
func TestDeleteAssignment(t *testing.T) {
|
func TestDeleteAssignment(t *testing.T) {
|
||||||
var scenarios = []struct {
|
var scenarios = []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
Reference in New Issue
Block a user