diff --git a/changelog/unreleased/eos-projects-share-perm.md b/changelog/unreleased/eos-projects-share-perm.md new file mode 100644 index 0000000000..41605fb6c0 --- /dev/null +++ b/changelog/unreleased/eos-projects-share-perm.md @@ -0,0 +1,3 @@ +Bugfix: Restrict EOS project spaces sharing permissions to admins and writers + +https://github.com/cs3org/reva/pull/2153 \ No newline at end of file diff --git a/internal/grpc/services/gateway/storageprovider.go b/internal/grpc/services/gateway/storageprovider.go index 974349cac9..249aac85e6 100644 --- a/internal/grpc/services/gateway/storageprovider.go +++ b/internal/grpc/services/gateway/storageprovider.go @@ -28,16 +28,16 @@ import ( "sync" "time" - rtrace "github.com/cs3org/reva/pkg/trace" "google.golang.org/protobuf/types/known/fieldmaskpb" - collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" - types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" - gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1" + types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + rtrace "github.com/cs3org/reva/pkg/trace" + "github.com/cs3org/reva/pkg/appctx" "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/rgrpc/status" diff --git a/pkg/cbox/share/sql/sql.go b/pkg/cbox/share/sql/sql.go index 7ab01b26d7..0987aa711b 100644 --- a/pkg/cbox/share/sql/sql.go +++ b/pkg/cbox/share/sql/sql.go @@ -531,7 +531,7 @@ func translateFilters(filters []*collaboration.Filter) (string, []interface{}, e case collaboration.Filter_TYPE_RESOURCE_ID: filterQuery += "(" for i, f := range filters { - filterQuery += "(fileid_prefix =? AND item_source=?" + filterQuery += "(fileid_prefix =? AND item_source=?)" params = append(params, f.GetResourceId().StorageId, f.GetResourceId().OpaqueId) if i != len(filters)-1 { diff --git a/pkg/cbox/storage/eoswrapper/eoswrapper.go b/pkg/cbox/storage/eoswrapper/eoswrapper.go index 2f27c42230..9f7bfa0fb2 100644 --- a/pkg/cbox/storage/eoswrapper/eoswrapper.go +++ b/pkg/cbox/storage/eoswrapper/eoswrapper.go @@ -21,10 +21,13 @@ package eoshome import ( "bytes" "context" + "strings" "text/template" "github.com/Masterminds/sprig" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + ctxpkg "github.com/cs3org/reva/pkg/ctx" + "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/storage" "github.com/cs3org/reva/pkg/storage/fs/registry" "github.com/cs3org/reva/pkg/storage/utils/eosfs" @@ -36,6 +39,14 @@ func init() { registry.Register("eoswrapper", New) } +const ( + eosProjectsNamespace = "/eos/project/" + + // We can use a regex for these, but that might have inferior performance + projectSpaceGroupsPrefix = "cernbox-project-" + projectSpaceAdminGroupsSuffix = "-admins" +) + type wrapper struct { storage.FS mountIDTemplate *template.Template @@ -96,6 +107,11 @@ func (w *wrapper) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []s // Take the first letter of the resource path after the namespace has been removed. // If it's empty, leave it empty to be filled by storageprovider. res.Id.StorageId = w.getMountID(ctx, res) + + if err = w.setProjectSharingPermissions(ctx, res); err != nil { + return nil, err + } + return res, nil } @@ -107,6 +123,9 @@ func (w *wrapper) ListFolder(ctx context.Context, ref *provider.Reference, mdKey } for _, r := range res { r.Id.StorageId = w.getMountID(ctx, r) + if err = w.setProjectSharingPermissions(ctx, r); err != nil { + continue + } } return res, nil } @@ -121,3 +140,28 @@ func (w *wrapper) getMountID(ctx context.Context, r *provider.ResourceInfo) stri } return b.String() } + +func (w *wrapper) setProjectSharingPermissions(ctx context.Context, r *provider.ResourceInfo) error { + if strings.HasPrefix(r.Path, eosProjectsNamespace) { + + // Extract project name from the path resembling /eos/project/c/cernbox/minutes/.. + path := strings.TrimPrefix(r.Path, eosProjectsNamespace) + parts := strings.SplitN(path, "/", 3) + if len(parts) != 3 { + return errtypes.BadRequest("eoswrapper: path does not follow the allowed format") + } + adminGroup := projectSpaceGroupsPrefix + parts[1] + projectSpaceAdminGroupsSuffix + user := ctxpkg.ContextMustGetUser(ctx) + + for _, g := range user.Groups { + if g == adminGroup { + r.PermissionSet.AddGrant = true + r.PermissionSet.RemoveGrant = true + r.PermissionSet.UpdateGrant = true + r.PermissionSet.ListGrants = true + return nil + } + } + } + return nil +}