allow querying federated sharing roles
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"cmp"
|
||||
"errors"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
libregraph "github.com/owncloud/libre-graph-api-go"
|
||||
@@ -30,6 +31,18 @@ const (
|
||||
UnifiedRoleManagerID = "312c0871-5ef7-4b3a-85b6-0e4074c64049"
|
||||
// UnifiedRoleSecureViewerID Unified role secure viewer id.
|
||||
UnifiedRoleSecureViewerID = "aa97fe03-7980-45ac-9e50-b325749fd7e6"
|
||||
// UnifiedRoleFederatedViewerID Unified role federated viewer id.
|
||||
UnifiedRoleFederatedViewerID = "be531789-063c-48bf-a9fe-857e6fbee7da"
|
||||
// UnifiedRoleFederatedEditorID Unified role federated editor id.
|
||||
UnifiedRoleFederatedEditorID = "36279a93-e4e3-4bbb-8a23-53b05b560963"
|
||||
|
||||
// Wile the below conditions follow the SDDL syntax, they are not parsed anywhere. We use them as strings to
|
||||
// represent the constraints that a role definition applies to. Fer the actual syntax, see the SDDL documentation
|
||||
// at https://learn.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-definition-language-for-conditional-aces-#conditional-expressions
|
||||
|
||||
// Some roles apply to a specific type of resource, for example, a role that applies to a file or a folder.
|
||||
// @Resource is the placeholder for the resource that the role is applied to
|
||||
// .Root, .Folder and .File are facets of the driveItem resource that indicate the type of the resource if they are present.
|
||||
|
||||
// UnifiedRoleConditionDrive defines constraint that matches a Driveroot/Spaceroot
|
||||
UnifiedRoleConditionDrive = "exists @Resource.Root"
|
||||
@@ -38,6 +51,19 @@ const (
|
||||
// UnifiedRoleConditionFile defines a constraint that matches a DriveItem representing a File
|
||||
UnifiedRoleConditionFile = "exists @Resource.File"
|
||||
|
||||
// Some roles apply to a specific type of user, for example, a role that applies to a federated user.
|
||||
// @Subject is the placeholder for the subject that the role is applied to. For sharing roles this is the user that the resource is shared with.
|
||||
// .UserType is the type of the user: 'Member' for a member of the organization, 'Guest' for a guest user, 'Federated' for a federated user.
|
||||
|
||||
// UnifiedRoleConditionFederatedUser defines a constraint that matches a federated user
|
||||
UnifiedRoleConditionFederatedUser = "@Subject.UserType==\"Federated\""
|
||||
|
||||
// For federated sharing we need roles that combine the constraints for the resource and the user.
|
||||
// UnifiedRoleConditionFileFederatedUser defines a constraint that matches a File and a federated user
|
||||
UnifiedRoleConditionFileFederatedUser = UnifiedRoleConditionFile + " && " + UnifiedRoleConditionFederatedUser
|
||||
// UnifiedRoleConditionFolderFederatedUser defines a constraint that matches a Folder and a federated user
|
||||
UnifiedRoleConditionFolderFederatedUser = UnifiedRoleConditionFolder + " && " + UnifiedRoleConditionFederatedUser
|
||||
|
||||
DriveItemPermissionsCreate = "libre.graph/driveItem/permissions/create"
|
||||
DriveItemChildrenCreate = "libre.graph/driveItem/children/create"
|
||||
DriveItemStandardDelete = "libre.graph/driveItem/standard/delete"
|
||||
@@ -258,6 +284,48 @@ func NewSecureViewerUnifiedRole() *libregraph.UnifiedRoleDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
// NewFederatedViewerUnifiedRole creates a federated viewer role
|
||||
func NewFederatedViewerUnifiedRole() *libregraph.UnifiedRoleDefinition {
|
||||
r := conversions.NewViewerRole()
|
||||
return &libregraph.UnifiedRoleDefinition{
|
||||
Id: proto.String(UnifiedRoleFederatedViewerID),
|
||||
Description: proto.String("View and download."),
|
||||
DisplayName: displayName(r),
|
||||
RolePermissions: []libregraph.UnifiedRolePermission{
|
||||
{
|
||||
AllowedResourceActions: convert(r),
|
||||
Condition: proto.String(UnifiedRoleConditionFileFederatedUser),
|
||||
},
|
||||
{
|
||||
AllowedResourceActions: convert(r),
|
||||
Condition: proto.String(UnifiedRoleConditionFolderFederatedUser),
|
||||
},
|
||||
},
|
||||
LibreGraphWeight: proto.Int32(0),
|
||||
}
|
||||
}
|
||||
|
||||
// NewFederatedEditorUnifiedRole creates a federated editor role
|
||||
func NewFederatedEditorUnifiedRole() *libregraph.UnifiedRoleDefinition {
|
||||
r := conversions.NewEditorRole()
|
||||
return &libregraph.UnifiedRoleDefinition{
|
||||
Id: proto.String(UnifiedRoleFederatedEditorID),
|
||||
Description: proto.String("View, download and edit."),
|
||||
DisplayName: displayName(r),
|
||||
RolePermissions: []libregraph.UnifiedRolePermission{
|
||||
{
|
||||
AllowedResourceActions: convert(r),
|
||||
Condition: proto.String(UnifiedRoleConditionFileFederatedUser),
|
||||
},
|
||||
{
|
||||
AllowedResourceActions: convert(r),
|
||||
Condition: proto.String(UnifiedRoleConditionFolderFederatedUser),
|
||||
},
|
||||
},
|
||||
LibreGraphWeight: proto.Int32(0),
|
||||
}
|
||||
}
|
||||
|
||||
// NewUnifiedRoleFromID returns a unified role definition from the provided id
|
||||
func NewUnifiedRoleFromID(id string) (*libregraph.UnifiedRoleDefinition, error) {
|
||||
for _, definition := range GetBuiltinRoleDefinitionList() {
|
||||
@@ -281,12 +349,14 @@ func GetBuiltinRoleDefinitionList() []*libregraph.UnifiedRoleDefinition {
|
||||
NewEditorLiteUnifiedRole(),
|
||||
NewManagerUnifiedRole(),
|
||||
NewSecureViewerUnifiedRole(),
|
||||
NewFederatedViewerUnifiedRole(),
|
||||
NewFederatedEditorUnifiedRole(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetApplicableRoleDefinitionsForActions returns a list of role definitions
|
||||
// that match the provided actions and constraints
|
||||
func GetApplicableRoleDefinitionsForActions(actions []string, constraints string, descending bool) []*libregraph.UnifiedRoleDefinition {
|
||||
func GetApplicableRoleDefinitionsForActions(actions []string, constraints string, listFederatedRoles, descending bool) []*libregraph.UnifiedRoleDefinition {
|
||||
builtin := GetBuiltinRoleDefinitionList()
|
||||
definitions := make([]*libregraph.UnifiedRoleDefinition, 0, len(builtin))
|
||||
|
||||
@@ -294,7 +364,14 @@ func GetApplicableRoleDefinitionsForActions(actions []string, constraints string
|
||||
var definitionMatch bool
|
||||
|
||||
for _, permission := range definition.GetRolePermissions() {
|
||||
if permission.GetCondition() != constraints {
|
||||
// this is a dirty comparison because we are not really parsing the SDDL, but as long as we && the conditions we are good
|
||||
isFederatedRole := strings.Contains(permission.GetCondition(), UnifiedRoleConditionFederatedUser)
|
||||
switch {
|
||||
case !strings.Contains(permission.GetCondition(), constraints):
|
||||
continue
|
||||
case listFederatedRoles && !isFederatedRole:
|
||||
continue
|
||||
case !listFederatedRoles && isFederatedRole:
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package unifiedrole_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
rConversions "github.com/cs3org/reva/v2/pkg/conversions"
|
||||
@@ -114,9 +113,9 @@ var _ = Describe("unifiedroles", func() {
|
||||
}
|
||||
|
||||
DescribeTable("GetApplicableRoleDefinitionsForActions",
|
||||
func(givenActions []string, constraints string, expectedDefinitions []*libregraph.UnifiedRoleDefinition) {
|
||||
func(givenActions []string, constraints string, listFederatedRoles bool, expectedDefinitions []*libregraph.UnifiedRoleDefinition) {
|
||||
|
||||
generatedDefinitions := unifiedrole.GetApplicableRoleDefinitionsForActions(givenActions, constraints, false)
|
||||
generatedDefinitions := unifiedrole.GetApplicableRoleDefinitionsForActions(givenActions, constraints, listFederatedRoles, false)
|
||||
|
||||
Expect(len(generatedDefinitions)).To(Equal(len(expectedDefinitions)))
|
||||
|
||||
@@ -137,6 +136,7 @@ var _ = Describe("unifiedroles", func() {
|
||||
"ViewerUnifiedRole",
|
||||
rolesToAction(unifiedrole.NewViewerUnifiedRole()),
|
||||
unifiedrole.UnifiedRoleConditionFolder,
|
||||
false,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewSecureViewerUnifiedRole(),
|
||||
unifiedrole.NewViewerUnifiedRole(),
|
||||
@@ -147,16 +147,38 @@ var _ = Describe("unifiedroles", func() {
|
||||
"ViewerUnifiedRole | share",
|
||||
rolesToAction(unifiedrole.NewViewerUnifiedRole()),
|
||||
unifiedrole.UnifiedRoleConditionFile,
|
||||
false,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewSecureViewerUnifiedRole(),
|
||||
unifiedrole.NewViewerUnifiedRole(),
|
||||
},
|
||||
),
|
||||
|
||||
Entry(
|
||||
"FederatedViewerUnifiedRole | share",
|
||||
rolesToAction(unifiedrole.NewFederatedViewerUnifiedRole()),
|
||||
unifiedrole.UnifiedRoleConditionFile,
|
||||
true,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewFederatedViewerUnifiedRole(),
|
||||
},
|
||||
),
|
||||
Entry(
|
||||
"FederatedEditorUnifiedRole | share",
|
||||
rolesToAction(unifiedrole.NewFederatedEditorUnifiedRole()),
|
||||
unifiedrole.UnifiedRoleConditionFile,
|
||||
true,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewFederatedViewerUnifiedRole(),
|
||||
unifiedrole.NewFederatedEditorUnifiedRole(),
|
||||
},
|
||||
),
|
||||
|
||||
Entry(
|
||||
"NewFileEditorUnifiedRole",
|
||||
rolesToAction(unifiedrole.NewFileEditorUnifiedRole()),
|
||||
unifiedrole.UnifiedRoleConditionFile,
|
||||
false,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewSecureViewerUnifiedRole(),
|
||||
unifiedrole.NewViewerUnifiedRole(),
|
||||
@@ -168,6 +190,7 @@ var _ = Describe("unifiedroles", func() {
|
||||
"NewEditorUnifiedRole",
|
||||
rolesToAction(unifiedrole.NewEditorUnifiedRole()),
|
||||
unifiedrole.UnifiedRoleConditionFolder,
|
||||
false,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewSecureViewerUnifiedRole(),
|
||||
unifiedrole.NewViewerUnifiedRole(),
|
||||
@@ -180,6 +203,7 @@ var _ = Describe("unifiedroles", func() {
|
||||
"GetBuiltinRoleDefinitionList",
|
||||
rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...),
|
||||
unifiedrole.UnifiedRoleConditionFile,
|
||||
false,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewSecureViewerUnifiedRole(),
|
||||
unifiedrole.NewViewerUnifiedRole(),
|
||||
@@ -191,6 +215,7 @@ var _ = Describe("unifiedroles", func() {
|
||||
"GetBuiltinRoleDefinitionList",
|
||||
rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...),
|
||||
unifiedrole.UnifiedRoleConditionFolder,
|
||||
false,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewSecureViewerUnifiedRole(),
|
||||
unifiedrole.NewViewerUnifiedRole(),
|
||||
@@ -203,6 +228,7 @@ var _ = Describe("unifiedroles", func() {
|
||||
"GetBuiltinRoleDefinitionList",
|
||||
rolesToAction(unifiedrole.GetBuiltinRoleDefinitionList()...),
|
||||
unifiedrole.UnifiedRoleConditionDrive,
|
||||
false,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewSpaceViewerUnifiedRole(),
|
||||
unifiedrole.NewSpaceEditorUnifiedRole(),
|
||||
@@ -214,6 +240,7 @@ var _ = Describe("unifiedroles", func() {
|
||||
"single",
|
||||
[]string{unifiedrole.DriveItemQuotaRead},
|
||||
unifiedrole.UnifiedRoleConditionFile,
|
||||
false,
|
||||
[]*libregraph.UnifiedRoleDefinition{},
|
||||
),
|
||||
|
||||
@@ -221,6 +248,7 @@ var _ = Describe("unifiedroles", func() {
|
||||
"mixed",
|
||||
append(rolesToAction(unifiedrole.NewEditorLiteUnifiedRole()), unifiedrole.DriveItemQuotaRead),
|
||||
unifiedrole.UnifiedRoleConditionFolder,
|
||||
false,
|
||||
[]*libregraph.UnifiedRoleDefinition{
|
||||
unifiedrole.NewSecureViewerUnifiedRole(),
|
||||
unifiedrole.NewEditorLiteUnifiedRole(),
|
||||
@@ -233,7 +261,7 @@ var _ = Describe("unifiedroles", func() {
|
||||
var newUnifiedRoleFromIDEntries []TableEntry
|
||||
attachEntry := func(name, id string, definition *libregraph.UnifiedRoleDefinition, errors bool) {
|
||||
e := Entry(
|
||||
fmt.Sprintf("%s", name),
|
||||
name,
|
||||
id,
|
||||
definition,
|
||||
errors,
|
||||
|
||||
Reference in New Issue
Block a user