Add http endpoint to list permissions (#5571)
* Add http endpoint to list permissions Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * extract handler registration Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * use generated protobuf Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * update permissions mock in graph service Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * add unit test Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * return correct userid Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> * assert error message type in tests Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de> --------- Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
@@ -47,6 +47,36 @@ func (_m *Permissions) GetPermissionByID(ctx context.Context, request *v0.GetPer
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListPermissions provides a mock function with given fields: ctx, req, opts
|
||||
func (_m *Permissions) ListPermissions(ctx context.Context, req *v0.ListPermissionsRequest, opts ...client.CallOption) (*v0.ListPermissionsResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, req)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *v0.ListPermissionsResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v0.ListPermissionsRequest, ...client.CallOption) *v0.ListPermissionsResponse); ok {
|
||||
r0 = rf(ctx, req, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v0.ListPermissionsResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *v0.ListPermissionsRequest, ...client.CallOption) error); ok {
|
||||
r1 = rf(ctx, req, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListPermissionsByResource provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *Permissions) ListPermissionsByResource(ctx context.Context, in *v0.ListPermissionsByResourceRequest, opts ...client.CallOption) (*v0.ListPermissionsByResourceResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
|
||||
@@ -71,6 +71,7 @@ type Publisher interface {
|
||||
|
||||
// Permissions is the interface used to access the permissions service
|
||||
type Permissions interface {
|
||||
ListPermissions(ctx context.Context, req *settingssvc.ListPermissionsRequest, opts ...client.CallOption) (*settingssvc.ListPermissionsResponse, error)
|
||||
GetPermissionByID(ctx context.Context, request *settingssvc.GetPermissionByIDRequest, opts ...client.CallOption) (*settingssvc.GetPermissionByIDResponse, error)
|
||||
ListPermissionsByResource(ctx context.Context, in *settingssvc.ListPermissionsByResourceRequest, opts ...client.CallOption) (*settingssvc.ListPermissionsByResourceResponse, error)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
cs3permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
@@ -54,20 +54,20 @@ func NewService(cfg *config.Config, logger log.Logger) Service {
|
||||
|
||||
// CheckPermission implements the CS3 API Permssions service.
|
||||
// It's used to check if a subject (user or group) has a permission.
|
||||
func (g Service) CheckPermission(ctx context.Context, req *permissions.CheckPermissionRequest) (*permissions.CheckPermissionResponse, error) {
|
||||
func (g Service) CheckPermission(ctx context.Context, req *cs3permissions.CheckPermissionRequest) (*cs3permissions.CheckPermissionResponse, error) {
|
||||
spec := req.SubjectRef.Spec
|
||||
|
||||
var accountID string
|
||||
switch ref := spec.(type) {
|
||||
case *permissions.SubjectReference_UserId:
|
||||
case *cs3permissions.SubjectReference_UserId:
|
||||
accountID = ref.UserId.OpaqueId
|
||||
case *permissions.SubjectReference_GroupId:
|
||||
case *cs3permissions.SubjectReference_GroupId:
|
||||
accountID = ref.GroupId.OpaqueId
|
||||
}
|
||||
|
||||
assignments, err := g.manager.ListRoleAssignments(accountID)
|
||||
if err != nil {
|
||||
return &permissions.CheckPermissionResponse{
|
||||
return &cs3permissions.CheckPermissionResponse{
|
||||
Status: status.NewInternal(ctx, err.Error()),
|
||||
}, nil
|
||||
}
|
||||
@@ -80,21 +80,21 @@ func (g Service) CheckPermission(ctx context.Context, req *permissions.CheckPerm
|
||||
permission, err := g.manager.ReadPermissionByName(req.Permission, roleIDs)
|
||||
if err != nil {
|
||||
if !errors.Is(err, settings.ErrNotFound) {
|
||||
return &permissions.CheckPermissionResponse{
|
||||
return &cs3permissions.CheckPermissionResponse{
|
||||
Status: status.NewInternal(ctx, err.Error()),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
if permission == nil {
|
||||
return &permissions.CheckPermissionResponse{
|
||||
return &cs3permissions.CheckPermissionResponse{
|
||||
Status: &rpcv1beta1.Status{
|
||||
Code: rpcv1beta1.Code_CODE_PERMISSION_DENIED,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &permissions.CheckPermissionResponse{
|
||||
return &cs3permissions.CheckPermissionResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
}, nil
|
||||
}
|
||||
@@ -463,6 +463,55 @@ func (g Service) RemoveRoleFromUser(ctx context.Context, req *settingssvc.Remove
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListPermissions implements the PermissionServiceHandler interface
|
||||
func (g Service) ListPermissions(ctx context.Context, req *settingssvc.ListPermissionsRequest, res *settingssvc.ListPermissionsResponse) error {
|
||||
ownAccountUUID, ok := metadata.Get(ctx, middleware.AccountID)
|
||||
if !ok {
|
||||
g.logger.Debug().Str("id", g.id).Msg("user not in context")
|
||||
return merrors.InternalServerError(g.id, "user not in context")
|
||||
}
|
||||
|
||||
if ownAccountUUID != req.AccountUuid {
|
||||
return merrors.NotFound(g.id, "user not found: %s", req.AccountUuid)
|
||||
}
|
||||
|
||||
assignments, err := g.manager.ListRoleAssignments(req.AccountUuid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// deduplicate role ids
|
||||
roleIDs := map[string]struct{}{}
|
||||
for _, a := range assignments {
|
||||
roleIDs[a.RoleId] = struct{}{}
|
||||
}
|
||||
|
||||
// deduplicate permission names
|
||||
permissionNames := map[string]struct{}{}
|
||||
for roleID := range roleIDs {
|
||||
bundle, err := g.manager.ReadBundle(roleID)
|
||||
if err != nil {
|
||||
if !errors.Is(err, settings.ErrNotFound) {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if bundle != nil {
|
||||
for _, setting := range bundle.GetSettings() {
|
||||
permissionNames[setting.Name] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.Permissions = make([]string, 0, len(permissionNames))
|
||||
for p := range permissionNames {
|
||||
res.Permissions = append(res.Permissions, p)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListPermissionsByResource implements the PermissionServiceHandler interface
|
||||
func (g Service) ListPermissionsByResource(ctx context.Context, req *settingssvc.ListPermissionsByResourceRequest, res *settingssvc.ListPermissionsByResourceResponse) error {
|
||||
if validationError := validateListPermissionsByResource(req); validationError != nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package svc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"github.com/owncloud/ocis/v2/services/settings/pkg/store/defaults"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/test-go/testify/mock"
|
||||
merrors "go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/metadata"
|
||||
)
|
||||
|
||||
@@ -169,3 +171,66 @@ func TestRemoveOwnRoleAssignment(t *testing.T) {
|
||||
err = svc.RemoveRoleFromUser(ctxWithUUID, &req, nil)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestListPermissionsOfCurrentUser(t *testing.T) {
|
||||
manager := &mocks.Manager{}
|
||||
a := []*settingsmsg.UserRoleAssignment{
|
||||
{
|
||||
Id: "00000000-0000-0000-0000-000000000001",
|
||||
AccountUuid: "61445573-4dbe-4d56-88dc-88ab47aceba7",
|
||||
RoleId: "aceb15b8-7486-479f-ae32-c91118e07a39",
|
||||
},
|
||||
}
|
||||
manager.On("ListRoleAssignments", mock.Anything).Return(a, nil)
|
||||
b := &settingsmsg.Bundle{
|
||||
Id: "aceb15b8-7486-479f-ae32-c91118e07a39",
|
||||
Settings: []*settingsmsg.Setting{
|
||||
{
|
||||
Name: "some-permission",
|
||||
},
|
||||
{
|
||||
Name: "other-permission",
|
||||
},
|
||||
{
|
||||
Name: "duplicate-permission",
|
||||
},
|
||||
{
|
||||
Name: "duplicate-permission",
|
||||
},
|
||||
},
|
||||
}
|
||||
manager.On("ReadBundle", mock.Anything).Return(b, nil)
|
||||
svc := Service{
|
||||
manager: manager,
|
||||
}
|
||||
|
||||
// Listing permissions for yourself
|
||||
req := v0.ListPermissionsRequest{
|
||||
AccountUuid: "61445573-4dbe-4d56-88dc-88ab47aceba7",
|
||||
}
|
||||
res := v0.ListPermissionsResponse{}
|
||||
err := svc.ListPermissions(ctxWithUUID, &req, &res)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, res.Permissions, 3)
|
||||
}
|
||||
|
||||
func TestListPermissionsOfOtherUser(t *testing.T) {
|
||||
manager := &mocks.Manager{}
|
||||
svc := Service{
|
||||
manager: manager,
|
||||
}
|
||||
|
||||
// Listing permissions for another user produces a not found error
|
||||
req := v0.ListPermissionsRequest{
|
||||
AccountUuid: "66666666-4444-4444-8888-88ab47aceba7",
|
||||
}
|
||||
res := v0.ListPermissionsResponse{}
|
||||
err := svc.ListPermissions(ctxWithUUID, &req, &res)
|
||||
assert.Error(t, err)
|
||||
|
||||
// assert the requested account uuid was not found
|
||||
merr, ok := merrors.As(err)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, int32(http.StatusNotFound), merr.Code)
|
||||
assert.Contains(t, err.Error(), req.AccountUuid)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user