mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-07 04:40:05 -06:00
graph: Set roles/actions in sharedByMe response (#7703)
* unifiedrole: Add CS3ResourcePermissionsToLibregraphActions Add function to convert CS3ResourcePermsissions to libregraph actions * unifiedrole: Fix strings for the UnifiedRoleConditionSelf The "Self/Owner/Grantee" string are not part the the constraint value * graph: Move getRoleDefinitionList to unifiedrole module rename it to GetBuiltinRoleDefinitionList and make it public * graph: turn libregraph resource actions into string constants * graph/sharedbyme: Set the correct roles (or actions) on permissions Try to map CS3 resource permissions on a share to one of the default libregraph UnifiedRoleDefinitions. If a match if found return the roleid in 'permissions.roles' attribute of the response. If no match if found convert the ResourcePermissions in to `libre.graph.permissions.actions` and return those in the response.
This commit is contained in:
@@ -15,7 +15,7 @@ import (
|
||||
// GetRoleDefinitions a list of permission roles than can be used when sharing with users or groups
|
||||
func (g Graph) GetRoleDefinitions(w http.ResponseWriter, r *http.Request) {
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(w, r, getRoleDefinitionList(g.config.FilesSharing.EnableResharing))
|
||||
render.JSON(w, r, unifiedrole.GetBuiltinRoleDefinitionList(g.config.FilesSharing.EnableResharing))
|
||||
}
|
||||
|
||||
// GetRoleDefinition a permission role than can be used when sharing with users or groups
|
||||
@@ -37,21 +37,8 @@ func (g Graph) GetRoleDefinition(w http.ResponseWriter, r *http.Request) {
|
||||
render.JSON(w, r, role)
|
||||
}
|
||||
|
||||
func getRoleDefinitionList(resharing bool) []*libregraph.UnifiedRoleDefinition {
|
||||
return []*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewViewerUnifiedRole(resharing),
|
||||
unifiedrole.NewSpaceViewerUnifiedRole(),
|
||||
unifiedrole.NewEditorUnifiedRole(resharing),
|
||||
unifiedrole.NewSpaceEditorUnifiedRole(),
|
||||
unifiedrole.NewFileEditorUnifiedRole(resharing),
|
||||
unifiedrole.NewCoownerUnifiedRole(),
|
||||
unifiedrole.NewUploaderUnifiedRole(),
|
||||
unifiedrole.NewManagerUnifiedRole(),
|
||||
}
|
||||
}
|
||||
|
||||
func getRoleDefinition(roleID string, resharing bool) (*libregraph.UnifiedRoleDefinition, error) {
|
||||
roleList := getRoleDefinitionList(resharing)
|
||||
roleList := unifiedrole.GetBuiltinRoleDefinitionList(resharing)
|
||||
for _, role := range roleList {
|
||||
if role != nil && role.Id != nil && *role.Id == roleID {
|
||||
return role, nil
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/identity"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/unifiedrole"
|
||||
)
|
||||
|
||||
type driveItemsByResourceID map[string]libregraph.DriveItem
|
||||
@@ -160,7 +161,18 @@ func (g Graph) cs3UserSharesToDriveItems(ctx context.Context, shares []*collabor
|
||||
if s.GetExpiration() != nil {
|
||||
perm.SetExpirationDateTime(cs3TimestampToTime(s.GetExpiration()))
|
||||
}
|
||||
|
||||
role := unifiedrole.CS3ResourcePermissionsToUnifiedRole(
|
||||
*s.GetPermissions().GetPermissions(),
|
||||
unifiedrole.UnifiedRoleConditionGrantee,
|
||||
g.config.FilesSharing.EnableResharing,
|
||||
)
|
||||
if role != nil {
|
||||
perm.SetRoles([]string{role.GetId()})
|
||||
} else {
|
||||
actions := unifiedrole.CS3ResourcePermissionsToLibregraphActions(*s.GetPermissions().GetPermissions())
|
||||
perm.SetLibreGraphPermissionsActions(actions)
|
||||
perm.SetRoles(nil)
|
||||
}
|
||||
perm.SetGrantedToV2(grantedTo)
|
||||
item.Permissions = append(item.Permissions, perm)
|
||||
driveItems[resIDStr] = item
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/conversions"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
@@ -28,6 +29,7 @@ import (
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/config/defaults"
|
||||
identitymocks "github.com/owncloud/ocis/v2/services/graph/pkg/identity/mocks"
|
||||
service "github.com/owncloud/ocis/v2/services/graph/pkg/service/v0"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/unifiedrole"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
@@ -45,6 +47,8 @@ var _ = Describe("sharedbyme", func() {
|
||||
rr *httptest.ResponseRecorder
|
||||
)
|
||||
expiration := time.Now()
|
||||
|
||||
editorResourcePermissions := conversions.NewEditorRole(true).CS3ResourcePermissions()
|
||||
userShare := collaboration.Share{
|
||||
Id: &collaboration.ShareId{
|
||||
OpaqueId: "share-id",
|
||||
@@ -62,6 +66,9 @@ var _ = Describe("sharedbyme", func() {
|
||||
},
|
||||
},
|
||||
},
|
||||
Permissions: &collaboration.SharePermissions{
|
||||
Permissions: editorResourcePermissions,
|
||||
},
|
||||
}
|
||||
groupShare := collaboration.Share{
|
||||
Id: &collaboration.ShareId{
|
||||
@@ -80,6 +87,9 @@ var _ = Describe("sharedbyme", func() {
|
||||
},
|
||||
},
|
||||
},
|
||||
Permissions: &collaboration.SharePermissions{
|
||||
Permissions: editorResourcePermissions,
|
||||
},
|
||||
}
|
||||
userShareWithExpiration := collaboration.Share{
|
||||
Id: &collaboration.ShareId{
|
||||
@@ -98,6 +108,9 @@ var _ = Describe("sharedbyme", func() {
|
||||
},
|
||||
},
|
||||
},
|
||||
Permissions: &collaboration.SharePermissions{
|
||||
Permissions: editorResourcePermissions,
|
||||
},
|
||||
Expiration: utils.TimeToTS(expiration),
|
||||
}
|
||||
|
||||
@@ -218,6 +231,7 @@ var _ = Describe("sharedbyme", func() {
|
||||
cfg.TokenManager.JWTSecret = "loremipsum"
|
||||
cfg.Commons = &shared.Commons{}
|
||||
cfg.GRPCClientTLS = &shared.GRPCClientTLS{}
|
||||
cfg.FilesSharing.EnableResharing = true
|
||||
|
||||
svc, _ = service.NewService(
|
||||
service.Config(cfg),
|
||||
@@ -323,6 +337,10 @@ var _ = Describe("sharedbyme", func() {
|
||||
Expect(user.GetId()).To(Equal(userShare.GetGrantee().GetUserId().GetOpaqueId()))
|
||||
_, ok = perm[0].GetLinkOk()
|
||||
Expect(ok).To(BeFalse())
|
||||
roles, ok := perm[0].GetRolesOk()
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(len(roles)).To(Equal(1))
|
||||
Expect(roles[0]).To(Equal(unifiedrole.UnifiedRoleEditorID))
|
||||
})
|
||||
|
||||
It("returns a proper driveItem, when a single group share is returned", func() {
|
||||
@@ -363,6 +381,10 @@ var _ = Describe("sharedbyme", func() {
|
||||
Expect(group.GetId()).To(Equal(groupShare.GetGrantee().GetGroupId().GetOpaqueId()))
|
||||
_, ok = perm[0].GetLinkOk()
|
||||
Expect(ok).To(BeFalse())
|
||||
roles, ok := perm[0].GetRolesOk()
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(len(roles)).To(Equal(1))
|
||||
Expect(roles[0]).To(Equal(unifiedrole.UnifiedRoleEditorID))
|
||||
})
|
||||
|
||||
It("returns a single driveItem, when a mulitple shares for the same resource are returned", func() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package unifiedrole
|
||||
|
||||
import (
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/conversions"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -24,12 +25,32 @@ const (
|
||||
// UnifiedRoleManagerID Unified role manager id.
|
||||
UnifiedRoleManagerID = "312c0871-5ef7-4b3a-85b6-0e4074c64049"
|
||||
|
||||
// UnifiedRoleConditionSelf TODO defines constraints
|
||||
UnifiedRoleConditionSelf = "Self: @Subject.objectId == @Resource.objectId"
|
||||
// UnifiedRoleConditionSelf defines constraint where the principal matches the target resource
|
||||
UnifiedRoleConditionSelf = "@Subject.objectId == @Resource.objectId"
|
||||
// UnifiedRoleConditionOwner defines constraints when the principal is the owner of the target resource
|
||||
UnifiedRoleConditionOwner = "Owner: @Subject.objectId Any_of @Resource.owners"
|
||||
UnifiedRoleConditionOwner = "@Subject.objectId Any_of @Resource.owners"
|
||||
// UnifiedRoleConditionGrantee does not exist in MS Graph, but we use it to express permissions on shared resources
|
||||
UnifiedRoleConditionGrantee = "Grantee: @Subject.objectId Any_of @Resource.grantee"
|
||||
UnifiedRoleConditionGrantee = "@Subject.objectId Any_of @Resource.grantee"
|
||||
|
||||
DriveItemPermissionsCreate = "libre.graph/driveItem/permissions/create"
|
||||
DriveItemChildrenCreate = "libre.graph/driveItem/children/create"
|
||||
DriveItemStandardDelete = "libre.graph/driveItem/standard/delete"
|
||||
DriveItemPathRead = "libre.graph/driveItem/path/read"
|
||||
DriveItemQuotaRead = "libre.graph/driveItem/quota/read"
|
||||
DriveItemContentRead = "libre.graph/driveItem/content/read"
|
||||
DriveItemUploadCreate = "libre.graph/driveItem/upload/create"
|
||||
DriveItemPermissionsRead = "libre.graph/driveItem/permissions/read"
|
||||
DriveItemChildrenRead = "libre.graph/driveItem/children/read"
|
||||
DriveItemVersionsRead = "libre.graph/driveItem/versions/read"
|
||||
DriveItemDeletedRead = "libre.graph/driveItem/deleted/read"
|
||||
DriveItemPathUpdate = "libre.graph/driveItem/path/update"
|
||||
DriveItemPermissionsDelete = "libre.graph/driveItem/permissions/delete"
|
||||
DriveItemDeletedDelete = "libre.graph/driveItem/deleted/delete"
|
||||
DriveItemVersionsUpdate = "libre.graph/driveItem/versions/update"
|
||||
DriveItemDeletedUpdate = "libre.graph/driveItem/deleted/update"
|
||||
DriveItemBasicRead = "libre.graph/driveItem/basic/read"
|
||||
DriveItemPermissionsUpdate = "libre.graph/driveItem/permissions/update"
|
||||
DriveItemPermissionsDeny = "libre.graph/driveItem/permissions/deny"
|
||||
)
|
||||
|
||||
// NewViewerUnifiedRole creates a viewer role. `sharing` indicates if sharing permission should be added
|
||||
@@ -168,6 +189,126 @@ func NewManagerUnifiedRole() *libregraph.UnifiedRoleDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
func GetBuiltinRoleDefinitionList(resharing bool) []*libregraph.UnifiedRoleDefinition {
|
||||
return []*libregraph.UnifiedRoleDefinition{
|
||||
NewViewerUnifiedRole(resharing),
|
||||
NewSpaceViewerUnifiedRole(),
|
||||
NewEditorUnifiedRole(resharing),
|
||||
NewSpaceEditorUnifiedRole(),
|
||||
NewFileEditorUnifiedRole(resharing),
|
||||
NewCoownerUnifiedRole(),
|
||||
NewUploaderUnifiedRole(),
|
||||
NewManagerUnifiedRole(),
|
||||
}
|
||||
}
|
||||
|
||||
// CS3ResourcePermissionsToLibregraphActions converts the provided cs3 ResourcePermissions to a list of
|
||||
// libregraph actions
|
||||
func CS3ResourcePermissionsToLibregraphActions(p provider.ResourcePermissions) (actions []string) {
|
||||
if p.AddGrant {
|
||||
actions = append(actions, DriveItemPermissionsCreate)
|
||||
}
|
||||
if p.CreateContainer {
|
||||
actions = append(actions, DriveItemChildrenCreate)
|
||||
}
|
||||
if p.Delete {
|
||||
actions = append(actions, DriveItemStandardDelete)
|
||||
}
|
||||
if p.GetPath {
|
||||
actions = append(actions, DriveItemPathRead)
|
||||
}
|
||||
if p.GetQuota {
|
||||
actions = append(actions, DriveItemQuotaRead)
|
||||
}
|
||||
if p.InitiateFileDownload {
|
||||
actions = append(actions, DriveItemContentRead)
|
||||
}
|
||||
if p.InitiateFileUpload {
|
||||
actions = append(actions, DriveItemUploadCreate)
|
||||
}
|
||||
if p.ListGrants {
|
||||
actions = append(actions, DriveItemPermissionsRead)
|
||||
}
|
||||
if p.ListContainer {
|
||||
actions = append(actions, DriveItemChildrenRead)
|
||||
}
|
||||
if p.ListFileVersions {
|
||||
actions = append(actions, DriveItemVersionsRead)
|
||||
}
|
||||
if p.ListRecycle {
|
||||
actions = append(actions, DriveItemDeletedRead)
|
||||
}
|
||||
if p.Move {
|
||||
actions = append(actions, DriveItemPathUpdate)
|
||||
}
|
||||
if p.RemoveGrant {
|
||||
actions = append(actions, DriveItemPermissionsDelete)
|
||||
}
|
||||
if p.PurgeRecycle {
|
||||
actions = append(actions, DriveItemDeletedDelete)
|
||||
}
|
||||
if p.RestoreFileVersion {
|
||||
actions = append(actions, DriveItemVersionsUpdate)
|
||||
}
|
||||
if p.RestoreRecycleItem {
|
||||
actions = append(actions, DriveItemDeletedUpdate)
|
||||
}
|
||||
if p.Stat {
|
||||
actions = append(actions, DriveItemBasicRead)
|
||||
}
|
||||
if p.UpdateGrant {
|
||||
actions = append(actions, DriveItemPermissionsUpdate)
|
||||
}
|
||||
if p.DenyGrant {
|
||||
actions = append(actions, DriveItemPermissionsDeny)
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
// CS3ResourcePermissionsToUnifiedRole tries to find the UnifiedRoleDefinition that matches the supplied
|
||||
// CS3 ResourcePermissions and constraints.
|
||||
func CS3ResourcePermissionsToUnifiedRole(p provider.ResourcePermissions, constraints string, resharing bool) *libregraph.UnifiedRoleDefinition {
|
||||
actionSet := map[string]struct{}{}
|
||||
for _, action := range CS3ResourcePermissionsToLibregraphActions(p) {
|
||||
actionSet[action] = struct{}{}
|
||||
}
|
||||
|
||||
var res *libregraph.UnifiedRoleDefinition
|
||||
for _, uRole := range GetBuiltinRoleDefinitionList(resharing) {
|
||||
matchFound := false
|
||||
for _, uPerm := range uRole.GetRolePermissions() {
|
||||
if uPerm.GetCondition() != constraints {
|
||||
// the requested constraints don't match, this isn't our role
|
||||
continue
|
||||
}
|
||||
|
||||
// if the actions converted from the ResourcePermissions equal the action the defined for the role, we have match
|
||||
if resourceActionsEqual(actionSet, uPerm.GetAllowedResourceActions()) {
|
||||
matchFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if matchFound {
|
||||
res = uRole
|
||||
break
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func resourceActionsEqual(targetActionSet map[string]struct{}, actions []string) bool {
|
||||
if len(targetActionSet) != len(actions) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, action := range actions {
|
||||
if _, ok := targetActionSet[action]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func displayName(role *conversions.Role) *string {
|
||||
if role == nil {
|
||||
return nil
|
||||
@@ -201,63 +342,5 @@ func convert(role *conversions.Role) []string {
|
||||
if role == nil && role.CS3ResourcePermissions() == nil {
|
||||
return actions
|
||||
}
|
||||
p := role.CS3ResourcePermissions()
|
||||
if p.AddGrant {
|
||||
actions = append(actions, "libre.graph/driveItem/permissions/create")
|
||||
}
|
||||
if p.CreateContainer {
|
||||
actions = append(actions, "libre.graph/driveItem/children/create")
|
||||
}
|
||||
if p.Delete {
|
||||
actions = append(actions, "libre.graph/driveItem/standard/delete")
|
||||
}
|
||||
if p.GetPath {
|
||||
actions = append(actions, "libre.graph/driveItem/path/read")
|
||||
}
|
||||
if p.GetQuota {
|
||||
actions = append(actions, "libre.graph/driveItem/quota/read")
|
||||
}
|
||||
if p.InitiateFileDownload {
|
||||
actions = append(actions, "libre.graph/driveItem/content/read")
|
||||
}
|
||||
if p.InitiateFileUpload {
|
||||
actions = append(actions, "libre.graph/driveItem/upload/create")
|
||||
}
|
||||
if p.ListGrants {
|
||||
actions = append(actions, "libre.graph/driveItem/permissions/read")
|
||||
}
|
||||
if p.ListContainer {
|
||||
actions = append(actions, "libre.graph/driveItem/children/read")
|
||||
}
|
||||
if p.ListFileVersions {
|
||||
actions = append(actions, "libre.graph/driveItem/versions/read")
|
||||
}
|
||||
if p.ListRecycle {
|
||||
actions = append(actions, "libre.graph/driveItem/deleted/read")
|
||||
}
|
||||
if p.Move {
|
||||
actions = append(actions, "libre.graph/driveItem/path/update")
|
||||
}
|
||||
if p.RemoveGrant {
|
||||
actions = append(actions, "libre.graph/driveItem/permissions/delete")
|
||||
}
|
||||
if p.PurgeRecycle {
|
||||
actions = append(actions, "libre.graph/driveItem/deleted/delete")
|
||||
}
|
||||
if p.RestoreFileVersion {
|
||||
actions = append(actions, "libre.graph/driveItem/versions/update")
|
||||
}
|
||||
if p.RestoreRecycleItem {
|
||||
actions = append(actions, "libre.graph/driveItem/deleted/update")
|
||||
}
|
||||
if p.Stat {
|
||||
actions = append(actions, "libre.graph/driveItem/basic/read")
|
||||
}
|
||||
if p.UpdateGrant {
|
||||
actions = append(actions, "libre.graph/driveItem/permissions/update")
|
||||
}
|
||||
if p.DenyGrant {
|
||||
actions = append(actions, "libre.graph/driveItem/permissions/deny")
|
||||
}
|
||||
return actions
|
||||
return CS3ResourcePermissionsToLibregraphActions(*role.CS3ResourcePermissions())
|
||||
}
|
||||
|
||||
13
services/graph/pkg/unifiedrole/unifiedrole_suite_test.go
Normal file
13
services/graph/pkg/unifiedrole/unifiedrole_suite_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package unifiedrole_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestUnifiedrole(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Unifiedrole Suite")
|
||||
}
|
||||
26
services/graph/pkg/unifiedrole/unifiedrole_test.go
Normal file
26
services/graph/pkg/unifiedrole/unifiedrole_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package unifiedrole_test
|
||||
|
||||
import (
|
||||
"github.com/cs3org/reva/v2/pkg/conversions"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
"github.com/owncloud/ocis/v2/services/graph/pkg/unifiedrole"
|
||||
)
|
||||
|
||||
var _ = Describe("unifiedroles", func() {
|
||||
DescribeTable("CS3ResourcePermissionsToUnifiedRole",
|
||||
func(legacyRole *conversions.Role, unifiedRole *libregraph.UnifiedRoleDefinition) {
|
||||
cs3perm := legacyRole.CS3ResourcePermissions()
|
||||
|
||||
r := unifiedrole.CS3ResourcePermissionsToUnifiedRole(*cs3perm, unifiedrole.UnifiedRoleConditionGrantee, true)
|
||||
Expect(r.GetId()).To(Equal(unifiedRole.GetId()))
|
||||
|
||||
},
|
||||
Entry(conversions.RoleViewer, conversions.NewViewerRole(true), unifiedrole.NewViewerUnifiedRole(true)),
|
||||
Entry(conversions.RoleEditor, conversions.NewEditorRole(true), unifiedrole.NewEditorUnifiedRole(true)),
|
||||
Entry(conversions.RoleFileEditor, conversions.NewFileEditorRole(true), unifiedrole.NewFileEditorUnifiedRole(true)),
|
||||
Entry(conversions.RoleCoowner, conversions.NewCoownerRole(), unifiedrole.NewCoownerUnifiedRole()),
|
||||
Entry(conversions.RoleManager, conversions.NewManagerRole(), unifiedrole.NewManagerUnifiedRole()),
|
||||
)
|
||||
})
|
||||
Reference in New Issue
Block a user