Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reuse ocs role objects in other drivers #2514

Merged
merged 7 commits into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/unreleased/uniform-ocs-roles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Enhancement: Reuse ocs role objects in other drivers

https://github.com/cs3org/reva/pull/2514
22 changes: 3 additions & 19 deletions cmd/reva/ocm-share-create.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/pkg/utils"
"github.com/jedib0t/go-pretty/table"
"github.com/pkg/errors"
Expand Down Expand Up @@ -165,28 +166,11 @@ func ocmShareCreateCommand() *command {
func getOCMSharePerm(p string) (*ocm.SharePermissions, int, error) {
if p == viewerPermission {
return &ocm.SharePermissions{
Permissions: &provider.ResourcePermissions{
GetPath: true,
InitiateFileDownload: true,
ListFileVersions: true,
ListContainer: true,
Stat: true,
},
Permissions: conversions.NewViewerRole().CS3ResourcePermissions(),
}, 1, nil
} else if p == editorPermission {
return &ocm.SharePermissions{
Permissions: &provider.ResourcePermissions{
GetPath: true,
InitiateFileDownload: true,
ListFileVersions: true,
ListContainer: true,
Stat: true,
CreateContainer: true,
Delete: true,
InitiateFileUpload: true,
RestoreFileVersion: true,
Move: true,
},
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}, 15, nil
}
return nil, 0, errors.New("invalid rol: " + p)
Expand Down
75 changes: 59 additions & 16 deletions internal/grpc/interceptors/auth/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,7 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s
return err
}

hasEditorRole := false
for _, v := range tokenScope {
if v.Role == authpb.Role_ROLE_OWNER || v.Role == authpb.Role_ROLE_EDITOR {
hasEditorRole = true
break
}
}

if ref, ok := extractRef(req, hasEditorRole); ok {
if ref, ok := extractRef(req, tokenScope); ok {
// The request is for a storage reference. This can be the case for multiple scenarios:
// - If the path is not empty, the request might be coming from a share where the accessor is
// trying to impersonate the owner, since the share manager doesn't know the
Expand Down Expand Up @@ -240,7 +232,7 @@ func checkIfNestedResource(ctx context.Context, ref *provider.Reference, parent

}

func extractRef(req interface{}, hasEditorRole bool) (*provider.Reference, bool) {
func extractRefForReaderRole(req interface{}) (*provider.Reference, bool) {
switch v := req.(type) {
// Read requests
case *registry.GetStorageProvidersRequest:
Expand All @@ -256,33 +248,84 @@ func extractRef(req interface{}, hasEditorRole bool) (*provider.Reference, bool)
case *gateway.OpenInAppRequest:
return v.GetRef(), true

// App provider requests
// App provider requests
case *appregistry.GetAppProvidersRequest:
return &provider.Reference{ResourceId: v.ResourceInfo.Id}, true
}

if !hasEditorRole {
return nil, false
}
return nil, false

}

func extractRefForUploaderRole(req interface{}) (*provider.Reference, bool) {
switch v := req.(type) {
// Write Requests
case *registry.GetStorageProvidersRequest:
return v.GetRef(), true
case *provider.StatRequest:
return v.GetRef(), true
case *provider.CreateContainerRequest:
return v.GetRef(), true
case *provider.TouchFileRequest:
return v.GetRef(), true
case *provider.InitiateFileUploadRequest:
return v.GetRef(), true
}

return nil, false

}

func extractRefForEditorRole(req interface{}) (*provider.Reference, bool) {
switch v := req.(type) {
// Remaining edit Requests
case *provider.DeleteRequest:
return v.GetRef(), true
case *provider.MoveRequest:
return v.GetSource(), true
case *provider.InitiateFileUploadRequest:
return v.GetRef(), true
case *provider.SetArbitraryMetadataRequest:
return v.GetRef(), true
case *provider.UnsetArbitraryMetadataRequest:
return v.GetRef(), true
}

return nil, false

}

func extractRef(req interface{}, tokenScope map[string]*authpb.Scope) (*provider.Reference, bool) {
var readPerm, uploadPerm, editPerm bool
for _, v := range tokenScope {
if v.Role == authpb.Role_ROLE_OWNER || v.Role == authpb.Role_ROLE_EDITOR || v.Role == authpb.Role_ROLE_VIEWER {
readPerm = true
}
if v.Role == authpb.Role_ROLE_OWNER || v.Role == authpb.Role_ROLE_EDITOR || v.Role == authpb.Role_ROLE_UPLOADER {
uploadPerm = true
}
if v.Role == authpb.Role_ROLE_OWNER || v.Role == authpb.Role_ROLE_EDITOR {
editPerm = true
}
}

if readPerm {
ref, ok := extractRefForReaderRole(req)
if ok {
return ref, true
}
}
if uploadPerm {
ref, ok := extractRefForUploaderRole(req)
if ok {
return ref, true
}
}
if editPerm {
ref, ok := extractRefForEditorRole(req)
if ok {
return ref, true
}
}

return nil, false
}

Expand Down
30 changes: 17 additions & 13 deletions internal/grpc/services/gateway/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ import (
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
ctxpkg "github.com/cs3org/reva/pkg/ctx"
rtrace "github.com/cs3org/reva/pkg/trace"
"github.com/cs3org/reva/pkg/useragent"
ua "github.com/mileusna/useragent"

"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
Expand Down Expand Up @@ -1778,30 +1776,36 @@ func (s *svc) listSharesFolder(ctx context.Context) (*provider.ListContainerResp
return lcr, nil
}

func (s *svc) isPathAllowed(ua *ua.UserAgent, path string) bool {
uaLst, ok := s.c.AllowedUserAgents[path]
if !ok {
// if no user agent is defined for a path, all user agents are allowed
return true
}
return useragent.IsUserAgentAllowed(ua, uaLst)
}

func (s *svc) filterProvidersByUserAgent(ctx context.Context, providers []*registry.ProviderInfo) []*registry.ProviderInfo {
ua, ok := ctxpkg.ContextGetUserAgent(ctx)
cat, ok := ctxpkg.ContextGetUserAgentCategory(ctx)
if !ok {
return providers
}

filters := []*registry.ProviderInfo{}
for _, p := range providers {
if s.isPathAllowed(ua, p.ProviderPath) {
if s.isPathAllowed(cat, p.ProviderPath) {
filters = append(filters, p)
}
}
return filters
}

func (s *svc) isPathAllowed(cat string, path string) bool {
allowedUserAgents, ok := s.c.AllowedUserAgents[path]
if !ok {
// if no user agent is defined for a path, all user agents are allowed
return true
}

for _, userAgent := range allowedUserAgents {
if userAgent == cat {
return true
}
}
return false
}

func (s *svc) listContainer(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) {
providers, err := s.findProviders(ctx, req.Ref)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions internal/http/interceptors/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func New(m map[string]interface{}, unprotected []string) (global.Middleware, err
isUnprotectedEndpoint = true
}

ctx, err := authenticateUser(w, r, conf, unprotected, tokenStrategy, tokenManager, tokenWriter, credChain, isUnprotectedEndpoint)
ctx, err := authenticateUser(w, r, conf, tokenStrategy, tokenManager, tokenWriter, credChain, isUnprotectedEndpoint)
if err != nil {
if !isUnprotectedEndpoint {
return
Expand All @@ -187,7 +187,7 @@ func New(m map[string]interface{}, unprotected []string) (global.Middleware, err
return chain, nil
}

func authenticateUser(w http.ResponseWriter, r *http.Request, conf *config, unprotected []string, tokenStrategy auth.TokenStrategy, tokenManager token.Manager, tokenWriter auth.TokenWriter, credChain map[string]auth.CredentialStrategy, isUnprotectedEndpoint bool) (context.Context, error) {
func authenticateUser(w http.ResponseWriter, r *http.Request, conf *config, tokenStrategy auth.TokenStrategy, tokenManager token.Manager, tokenWriter auth.TokenWriter, credChain map[string]auth.CredentialStrategy, isUnprotectedEndpoint bool) (context.Context, error) {
ctx := r.Context()
log := appctx.GetLogger(ctx)

Expand Down
2 changes: 1 addition & 1 deletion internal/http/services/owncloud/ocs/conversions/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func NewCoownerRole() *Role {
// NewUploaderRole creates an uploader role
func NewUploaderRole() *Role {
return &Role{
Name: RoleViewer,
Name: RoleUploader,
cS3ResourcePermissions: &provider.ResourcePermissions{
Stat: true,
ListContainer: true,
Expand Down
6 changes: 5 additions & 1 deletion pkg/auth/manager/publicshares/publicshares.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,14 @@ func (m *manager) Authenticate(ctx context.Context, token, secret string) (*user
share := publicShareResponse.GetShare()
role := authpb.Role_ROLE_VIEWER
roleStr := "viewer"
if share.Permissions.Permissions.InitiateFileUpload {
if share.Permissions.Permissions.InitiateFileUpload && !share.Permissions.Permissions.InitiateFileDownload {
role = authpb.Role_ROLE_UPLOADER
roleStr = "uploader"
} else if share.Permissions.Permissions.InitiateFileUpload {
role = authpb.Role_ROLE_EDITOR
roleStr = "editor"
}

scope, err := scope.AddPublicShareScope(share, role, nil)
if err != nil {
return nil, nil, err
Expand Down
2 changes: 1 addition & 1 deletion pkg/auth/scope/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ func VerifyScope(ctx context.Context, scopeMap map[string]*authpb.Scope, resourc
}

func hasRoleEditor(scope authpb.Scope) bool {
return scope.Role == authpb.Role_ROLE_EDITOR
return scope.Role == authpb.Role_ROLE_OWNER || scope.Role == authpb.Role_ROLE_EDITOR || scope.Role == authpb.Role_ROLE_UPLOADER
ishank011 marked this conversation as resolved.
Show resolved Hide resolved
}
5 changes: 5 additions & 0 deletions pkg/cbox/storage/eoshomewrapper/eoshomewrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"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"
Expand Down Expand Up @@ -112,6 +113,10 @@ func (w *wrapper) ListFolder(ctx context.Context, ref *provider.Reference, mdKey
return res, nil
}

func (w *wrapper) DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) error {
return errtypes.NotSupported("eos: deny grant is only enabled for project spaces")
}

func (w *wrapper) getMountID(ctx context.Context, r *provider.ResourceInfo) string {
u := ctxpkg.ContextMustGetUser(ctx)
b := bytes.Buffer{}
Expand Down
13 changes: 13 additions & 0 deletions pkg/cbox/storage/eoswrapper/eoswrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,18 @@ func (w *wrapper) RestoreRevision(ctx context.Context, ref *provider.Reference,
return w.FS.RestoreRevision(ctx, ref, revisionKey)
}

func (w *wrapper) DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) error {
// This is only allowed for project space admins
if strings.HasPrefix(w.conf.Namespace, eosProjectsNamespace) {
if err := w.userIsProjectAdmin(ctx, ref); err != nil {
return err
}
return w.FS.DenyGrant(ctx, ref, g)
}

return errtypes.NotSupported("eos: deny grant is only enabled for project spaces")
}

func (w *wrapper) getMountID(ctx context.Context, r *provider.ResourceInfo) string {
if r == nil {
return ""
Expand Down Expand Up @@ -194,6 +206,7 @@ func (w *wrapper) setProjectSharingPermissions(ctx context.Context, r *provider.
r.PermissionSet.UpdateGrant = true
r.PermissionSet.ListGrants = true
r.PermissionSet.GetQuota = true
r.PermissionSet.DenyGrant = true
return nil
}
}
Expand Down
41 changes: 5 additions & 36 deletions pkg/cbox/utils/conversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
)

// DBShare stores information about user and public shares.
Expand Down Expand Up @@ -129,46 +130,14 @@ func SharePermToInt(p *provider.ResourcePermissions) int {
func IntTosharePerm(p int, itemType string) *provider.ResourcePermissions {
switch p {
case 1:
return &provider.ResourcePermissions{
ListContainer: true,
ListGrants: true,
ListFileVersions: true,
ListRecycle: true,
Stat: true,
GetPath: true,
GetQuota: true,
InitiateFileDownload: true,
}
return conversions.NewViewerRole().CS3ResourcePermissions()
case 15:
perm := &provider.ResourcePermissions{
ListContainer: true,
ListGrants: true,
ListFileVersions: true,
ListRecycle: true,
Stat: true,
GetPath: true,
GetQuota: true,
InitiateFileDownload: true,

InitiateFileUpload: true,
RestoreFileVersion: true,
RestoreRecycleItem: true,
}
if itemType == "folder" {
perm.CreateContainer = true
perm.Delete = true
perm.Move = true
perm.PurgeRecycle = true
return conversions.NewEditorRole().CS3ResourcePermissions()
}
return perm
return conversions.NewFileEditorRole().CS3ResourcePermissions()
case 4:
return &provider.ResourcePermissions{
Stat: true,
ListContainer: true,
GetPath: true,
CreateContainer: true,
InitiateFileUpload: true,
}
return conversions.NewUploaderRole().CS3ResourcePermissions()
default:
// TODO we may have other options, for now this is a denial
return &provider.ResourcePermissions{}
Expand Down
Loading