Skip to content

Commit

Permalink
add sufficient permissions check
Browse files Browse the repository at this point in the history
  • Loading branch information
micbar committed Nov 13, 2023
1 parent 7a0869a commit 95fb82b
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,15 @@ import (

rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/conversions"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/publicshare"
"github.com/cs3org/reva/v2/pkg/publicshare/manager/registry"
"github.com/cs3org/reva/v2/pkg/rgrpc"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/mitchellh/mapstructure"
graph "github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
"github.com/pkg/errors"
"google.golang.org/grpc"
)
Expand Down Expand Up @@ -140,6 +138,12 @@ func (s *service) CreatePublicShare(ctx context.Context, req *link.CreatePublicS
log := appctx.GetLogger(ctx)
log.Info().Str("publicshareprovider", "create").Msg("create public share")

if !conversions.SufficientCS3Permissions(req.GetResourceInfo().GetPermissionSet(), req.GetGrant().GetPermissions().GetPermissions()) {
return &link.CreatePublicShareResponse{
Status: status.NewInvalid(ctx, "insufficient permissions to create that kind of share"),
}, nil
}

if !s.isPathAllowed(req.ResourceInfo.Path) {
return &link.CreatePublicShareResponse{
Status: status.NewInvalid(ctx, "share creation is not allowed for the specified path"),
Expand All @@ -163,12 +167,10 @@ func (s *service) CreatePublicShare(ctx context.Context, req *link.CreatePublicS
if err != nil {
log.Debug().Err(err).Str("createShare", "shares").Msg("error connecting to storage provider")
}
opaque := &typesv1beta1.Opaque{Map: map[string]*typesv1beta1.OpaqueEntry{}}
opaque = utils.AppendJSONToOpaque(opaque, "errorcode", graph.New(graph.InvalidAuthenticationToken, "test"))

res := &link.CreatePublicShareResponse{
Status: status.NewOK(ctx),
Share: share,
Opaque: opaque,
}
return res, nil
}
Expand Down
28 changes: 28 additions & 0 deletions pkg/conversions/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package conversions

import (
"fmt"
"reflect"
"strings"

provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
Expand Down Expand Up @@ -508,3 +509,30 @@ func RoleFromResourcePermissions(rp *provider.ResourcePermissions, islink bool)
// TODO what about even more granular cs3 permissions?, eg. only stat
return r
}

// SufficientCS3Permissions returns true if the `existing` permissions contain the `requested` permissions
func SufficientCS3Permissions(existing, requested *provider.ResourcePermissions) bool {
// empty permissions represent a denial
if grants.PermissionsEqual(requested, &provider.ResourcePermissions{}) {
return existing.DenyGrant
}
requestedPermissionsType := reflect.TypeOf(provider.ResourcePermissions{})
numFields := requestedPermissionsType.NumField()
requestedPermissionsValues := reflect.ValueOf(requested)
existingPermissionsValues := reflect.ValueOf(existing)

for i := 0; i < numFields; i++ {
permissionName := requestedPermissionsType.Field(i).Name
// filter out irrelevant fields
if strings.Contains(permissionName, "XXX") {
continue
}
existingPermission := reflect.Indirect(existingPermissionsValues).FieldByName(permissionName).Bool()
requestedPermission := requestedPermissionsValues.Elem().Field(i).Bool()
// every requested permission needs to exist for the creator
if requestedPermission == true && existingPermission == false {

Check failure on line 533 in pkg/conversions/role.go

View workflow job for this annotation

GitHub Actions / lint

S1002: should omit comparison to bool constant, can be simplified to `requestedPermission` (gosimple)
return false
}
}
return true
}
92 changes: 92 additions & 0 deletions pkg/conversions/role_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package conversions

import (
"testing"

providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/stretchr/testify/assert"
)

func TestSufficientPermissions(t *testing.T) {
type testData struct {
Existing *providerv1beta1.ResourcePermissions
Requested *providerv1beta1.ResourcePermissions
Sufficient bool
}
table := []testData{
{
Existing: RoleFromName("editor", true).CS3ResourcePermissions(),
Requested: RoleFromName("viewer", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("viewer", true).CS3ResourcePermissions(),
Requested: RoleFromName("editor", true).CS3ResourcePermissions(),
Sufficient: false,
},
{
Existing: RoleFromName("spaceviewer", true).CS3ResourcePermissions(),
Requested: RoleFromName("spaceeditor", true).CS3ResourcePermissions(),
Sufficient: false,
},
{
Existing: RoleFromName("manager", true).CS3ResourcePermissions(),
Requested: RoleFromName("spaceeditor", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("manager", true).CS3ResourcePermissions(),
Requested: RoleFromName("spaceviewer", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("manager", true).CS3ResourcePermissions(),
Requested: RoleFromName("manager", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("manager", true).CS3ResourcePermissions(),
Requested: RoleFromName("denied", true).CS3ResourcePermissions(),
Sufficient: true,
},
{
Existing: RoleFromName("spaceeditor", true).CS3ResourcePermissions(),
Requested: RoleFromName("denied", true).CS3ResourcePermissions(),
Sufficient: false,
},
{
Existing: RoleFromName("editor", true).CS3ResourcePermissions(),
Requested: RoleFromName("denied", true).CS3ResourcePermissions(),
Sufficient: false,
},
{
Existing: &providerv1beta1.ResourcePermissions{
// all permissions, used for personal space owners
AddGrant: true,
CreateContainer: true,
Delete: true,
GetPath: true,
GetQuota: true,
InitiateFileDownload: true,
InitiateFileUpload: true,
ListContainer: true,
ListFileVersions: true,
ListGrants: true,
ListRecycle: true,
Move: true,
PurgeRecycle: true,
RemoveGrant: true,
RestoreFileVersion: true,
RestoreRecycleItem: true,
Stat: true,
UpdateGrant: true,
DenyGrant: true,
},
Requested: RoleFromName("denied", true).CS3ResourcePermissions(),
Sufficient: true,
},
}
for _, test := range table {
assert.Equal(t, test.Sufficient, SufficientCS3Permissions(test.Existing, test.Requested))
}
}

0 comments on commit 95fb82b

Please sign in to comment.