diff --git a/pkg/service/v0/permissions.go b/pkg/service/v0/permissions.go new file mode 100644 index 0000000000..d9c67b026b --- /dev/null +++ b/pkg/service/v0/permissions.go @@ -0,0 +1,52 @@ +package svc + +import "github.com/owncloud/ocis-settings/pkg/proto/v0" + +func (g Service) hasPermission( + assignments []*proto.UserRoleAssignment, + resource *proto.Resource, + operation proto.Permission_Operation, + constraint proto.Permission_Constraint, +) bool { + for index := range assignments { + if g.isAllowedByRole(assignments[index], resource, operation, constraint) { + return true + } + } + return false +} + +func (g Service) isAllowedByRole( + assignment *proto.UserRoleAssignment, + resource *proto.Resource, + operation proto.Permission_Operation, + constraint proto.Permission_Constraint, +) bool { + role, err := g.manager.ReadBundle(assignment.RoleId) + if err != nil { + g.logger.Err(err).Str("bundle", assignment.RoleId).Msg("Failed to fetch role") + return false + } + for _, setting := range role.Settings { + if _, ok := setting.Value.(*proto.Setting_PermissionValue); ok { + value := setting.Value.(*proto.Setting_PermissionValue).PermissionValue + if resource.Type == setting.Resource.Type && + resource.Id == setting.Resource.Id && + operation == value.Operation && + isConstraintMatch(constraint, value.Constraint) { + return true + } + } + } + return false +} + +// isConstraintMatch checks if the `given` constraint is the same or a superset of the `required` constraint. +// this is only a comparison on ENUM level. this is not a check about the appropriate constraint for a resource. +func isConstraintMatch(given, required proto.Permission_Constraint) bool { + // comparing enum by order is not a feasible solution, because `SHARED` is not a superset of `OWN`. + if given == proto.Permission_CONSTRAINT_ALL { + return true + } + return given != proto.Permission_CONSTRAINT_UNKNOWN && given == required +} diff --git a/pkg/service/v0/service.go b/pkg/service/v0/service.go index c46138a73e..71fa434f5e 100644 --- a/pkg/service/v0/service.go +++ b/pkg/service/v0/service.go @@ -86,7 +86,39 @@ func (g Service) ListBundles(c context.Context, req *proto.ListBundlesRequest, r if err != nil { return merrors.NotFound("ocis-settings", "%s", err) } - res.Bundles = bundles + + // fetch roles of the user + rolesResponse := &proto.ListRoleAssignmentsResponse{} + err = g.ListRoleAssignments(c, &proto.ListRoleAssignmentsRequest{AccountUuid: req.AccountUuid}, rolesResponse) + if err != nil { + return err + } + + // filter settings in bundles that are allowed according to roles + var filteredBundles []*proto.Bundle + for _, bundle := range bundles { + var filteredSettings []*proto.Setting + for _, setting := range bundle.Settings { + settingResource := &proto.Resource{ + Type: proto.Resource_TYPE_SETTING, + Id: setting.Id, + } + if g.hasPermission( + rolesResponse.Assignments, + settingResource, + proto.Permission_OPERATION_UPDATE, + proto.Permission_CONSTRAINT_OWN, + ) { + filteredSettings = append(filteredSettings, setting) + } + } + bundle.Settings = filteredSettings + if len(filteredSettings) > 0 { + filteredBundles = append(filteredBundles, bundle) + } + } + + res.Bundles = filteredBundles return nil }