From fc3c653b8b77e265b3bca2f0950a77580d09a8fa Mon Sep 17 00:00:00 2001 From: David Christofas Date: Tue, 26 Oct 2021 14:00:06 +0200 Subject: [PATCH] allow users with the list-all-spaces permission to list all spaces This implementation is just a quick hack which is definitely not production ready. It should be changed as soon as we have a proper permission system in reva. --- changelog/unreleased/list-all-spaces.md | 6 ++++++ .../services/storageprovider/storageprovider.go | 16 +++++++++++++++- pkg/storage/fs/nextcloud/nextcloud.go | 2 +- pkg/storage/fs/nextcloud/nextcloud_test.go | 2 +- pkg/storage/fs/owncloud/owncloud.go | 2 +- pkg/storage/fs/owncloudsql/owncloudsql.go | 2 +- pkg/storage/fs/s3/s3.go | 2 +- pkg/storage/storage.go | 2 +- pkg/storage/utils/decomposedfs/spaces.go | 9 +++++---- pkg/storage/utils/eosfs/eosfs.go | 2 +- pkg/storage/utils/localfs/localfs.go | 2 +- 11 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 changelog/unreleased/list-all-spaces.md diff --git a/changelog/unreleased/list-all-spaces.md b/changelog/unreleased/list-all-spaces.md new file mode 100644 index 0000000000..ee14057905 --- /dev/null +++ b/changelog/unreleased/list-all-spaces.md @@ -0,0 +1,6 @@ +Enhancement: Enable users to list all spaces + +Added a permission check if the user has the `list-all-spaces` permission. +This enables users to list all spaces, even those which they are not members of. + +https://github.com/cs3org/reva/pull/2207 diff --git a/internal/grpc/services/storageprovider/storageprovider.go b/internal/grpc/services/storageprovider/storageprovider.go index aefc6f22ee..562abcd7a3 100644 --- a/internal/grpc/services/storageprovider/storageprovider.go +++ b/internal/grpc/services/storageprovider/storageprovider.go @@ -20,6 +20,7 @@ package storageprovider import ( "context" + "encoding/json" "fmt" "net/url" "os" @@ -449,7 +450,20 @@ func hasNodeID(s *provider.StorageSpace) bool { func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStorageSpacesRequest) (*provider.ListStorageSpacesResponse, error) { log := appctx.GetLogger(ctx) - spaces, err := s.storage.ListStorageSpaces(ctx, req.Filters) + + // This is just a quick hack to get the users permission into reva. + // Replace this as soon as we have a proper system to check the users permissions. + opaque := req.Opaque + var permissions map[string]struct{} + if opaque != nil { + entry := opaque.Map["permissions"] + err := json.Unmarshal(entry.Value, &permissions) + if err != nil { + return nil, err + } + } + + spaces, err := s.storage.ListStorageSpaces(ctx, req.Filters, permissions) if err != nil { var st *rpc.Status switch err.(type) { diff --git a/pkg/storage/fs/nextcloud/nextcloud.go b/pkg/storage/fs/nextcloud/nextcloud.go index 8e7c3af44d..7ee908beda 100644 --- a/pkg/storage/fs/nextcloud/nextcloud.go +++ b/pkg/storage/fs/nextcloud/nextcloud.go @@ -758,7 +758,7 @@ func (nc *StorageDriver) UnsetArbitraryMetadata(ctx context.Context, ref *provid } // ListStorageSpaces as defined in the storage.FS interface -func (nc *StorageDriver) ListStorageSpaces(ctx context.Context, f []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) { +func (nc *StorageDriver) ListStorageSpaces(ctx context.Context, f []*provider.ListStorageSpacesRequest_Filter, _ map[string]struct{}) ([]*provider.StorageSpace, error) { bodyStr, _ := json.Marshal(f) _, respBody, err := nc.do(ctx, Action{"ListStorageSpaces", string(bodyStr)}) if err != nil { diff --git a/pkg/storage/fs/nextcloud/nextcloud_test.go b/pkg/storage/fs/nextcloud/nextcloud_test.go index f4565a54b5..b81edd643b 100644 --- a/pkg/storage/fs/nextcloud/nextcloud_test.go +++ b/pkg/storage/fs/nextcloud/nextcloud_test.go @@ -987,7 +987,7 @@ var _ = Describe("Nextcloud", func() { }, } filters := []*provider.ListStorageSpacesRequest_Filter{filter1, filter2, filter3} - spaces, err := nc.ListStorageSpaces(ctx, filters) + spaces, err := nc.ListStorageSpaces(ctx, filters, nil) Expect(err).ToNot(HaveOccurred()) Expect(len(spaces)).To(Equal(1)) // https://github.com/cs3org/go-cs3apis/blob/970eec3/cs3/storage/provider/v1beta1/resources.pb.go#L1341-L1366 diff --git a/pkg/storage/fs/owncloud/owncloud.go b/pkg/storage/fs/owncloud/owncloud.go index c1e3fe0612..51a1299ec3 100644 --- a/pkg/storage/fs/owncloud/owncloud.go +++ b/pkg/storage/fs/owncloud/owncloud.go @@ -2230,7 +2230,7 @@ func (fs *ocfs) RestoreRecycleItem(ctx context.Context, basePath, key, relativeP return fs.propagate(ctx, tgt) } -func (fs *ocfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) { +func (fs *ocfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter, _ map[string]struct{}) ([]*provider.StorageSpace, error) { return nil, errtypes.NotSupported("list storage spaces") } diff --git a/pkg/storage/fs/owncloudsql/owncloudsql.go b/pkg/storage/fs/owncloudsql/owncloudsql.go index f02cf31b38..43db8f3b89 100644 --- a/pkg/storage/fs/owncloudsql/owncloudsql.go +++ b/pkg/storage/fs/owncloudsql/owncloudsql.go @@ -1925,7 +1925,7 @@ func (fs *owncloudsqlfs) HashFile(path string) (string, string, string, error) { } } -func (fs *owncloudsqlfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) { +func (fs *owncloudsqlfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter, _ map[string]struct{}) ([]*provider.StorageSpace, error) { // TODO(corby): Implement return nil, errtypes.NotSupported("list storage spaces") } diff --git a/pkg/storage/fs/s3/s3.go b/pkg/storage/fs/s3/s3.go index 6082075975..39d9fb7d6a 100644 --- a/pkg/storage/fs/s3/s3.go +++ b/pkg/storage/fs/s3/s3.go @@ -677,7 +677,7 @@ func (fs *s3FS) RestoreRecycleItem(ctx context.Context, basePath, key, relativeP return errtypes.NotSupported("restore recycle") } -func (fs *s3FS) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) { +func (fs *s3FS) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter, _ map[string]struct{}) ([]*provider.StorageSpace, error) { return nil, errtypes.NotSupported("list storage spaces") } diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 2e43154c97..f43a938152 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -57,7 +57,7 @@ type FS interface { Shutdown(ctx context.Context) error SetArbitraryMetadata(ctx context.Context, ref *provider.Reference, md *provider.ArbitraryMetadata) error UnsetArbitraryMetadata(ctx context.Context, ref *provider.Reference, keys []string) error - ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) + ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter, permissions map[string]struct{}) ([]*provider.StorageSpace, error) CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error) UpdateStorageSpace(ctx context.Context, req *provider.UpdateStorageSpaceRequest) (*provider.UpdateStorageSpaceResponse, error) } diff --git a/pkg/storage/utils/decomposedfs/spaces.go b/pkg/storage/utils/decomposedfs/spaces.go index d84e9600c9..8c61ecf1e1 100644 --- a/pkg/storage/utils/decomposedfs/spaces.go +++ b/pkg/storage/utils/decomposedfs/spaces.go @@ -156,7 +156,7 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr // The list can be filtered by space type or space id. // Spaces are persisted with symlinks in /spaces// pointing to ../../nodes/, the root node of the space // The spaceid is a concatenation of storageid + "!" + nodeid -func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) { +func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter, permissions map[string]struct{}) ([]*provider.StorageSpace, error) { // TODO check filters // TODO when a space symlink is broken delete the space for cleanup @@ -226,7 +226,7 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide } // TODO apply more filters - space, err := fs.storageSpaceFromNode(ctx, n, matches[i], spaceType) + space, err := fs.storageSpaceFromNode(ctx, n, matches[i], spaceType, permissions) if err != nil { appctx.GetLogger(ctx).Error().Err(err).Interface("node", n).Msg("could not convert to storage space") continue @@ -318,7 +318,7 @@ func (fs *Decomposedfs) createStorageSpace(ctx context.Context, spaceType, nodeI return nil } -func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, node *node.Node, nodePath, spaceType string) (*provider.StorageSpace, error) { +func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, node *node.Node, nodePath, spaceType string, permissions map[string]struct{}) (*provider.StorageSpace, error) { owner, err := node.Owner() if err != nil { return nil, err @@ -346,11 +346,12 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, node *node.Nod user := ctxpkg.ContextMustGetUser(ctx) // filter out spaces user cannot access (currently based on stat permission) + _, canListAllSpaces := permissions["list-all-spaces"] p, err := node.ReadUserPermissions(ctx, user) if err != nil { return nil, err } - if !p.Stat { + if !(canListAllSpaces || p.Stat) { return nil, errors.New("user is not allowed to Stat the space") } diff --git a/pkg/storage/utils/eosfs/eosfs.go b/pkg/storage/utils/eosfs/eosfs.go index 362922dfb7..0f923d59ac 100644 --- a/pkg/storage/utils/eosfs/eosfs.go +++ b/pkg/storage/utils/eosfs/eosfs.go @@ -1551,7 +1551,7 @@ func (fs *eosfs) RestoreRecycleItem(ctx context.Context, basePath, key, relative return fs.c.RestoreDeletedEntry(ctx, auth, key) } -func (fs *eosfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) { +func (fs *eosfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter, _ map[string]struct{}) ([]*provider.StorageSpace, error) { return nil, errtypes.NotSupported("list storage spaces") } diff --git a/pkg/storage/utils/localfs/localfs.go b/pkg/storage/utils/localfs/localfs.go index 6ad3341462..a28f98e33d 100644 --- a/pkg/storage/utils/localfs/localfs.go +++ b/pkg/storage/utils/localfs/localfs.go @@ -1260,7 +1260,7 @@ func (fs *localfs) RestoreRecycleItem(ctx context.Context, basePath, key, relati return fs.propagate(ctx, localRestorePath) } -func (fs *localfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) { +func (fs *localfs) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter, _ map[string]struct{}) ([]*provider.StorageSpace, error) { return nil, errtypes.NotSupported("list storage spaces") }