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

Implement support for deny ACLs #1798

Closed
wants to merge 56 commits into from
Closed
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
65877bc
Add PermissionNone as a full deny ACL. `PermissionInvalid` represents…
glpatcern Jun 14, 2021
55406d3
GetACLPerm provide a string of all permission set to deny with a "den…
gmgigi96 Jun 15, 2021
d9056ad
Add cmp package
gmgigi96 Jun 15, 2021
39724c8
Add methods to manage list of grants
gmgigi96 Jun 15, 2021
1cb02e6
Add SetACLs method to add (not) atomically a list of acls
gmgigi96 Jun 15, 2021
0e060dc
Modified behaviour of eosfs.AddGrant, to support denial permissions (…
gmgigi96 Jun 15, 2021
e6303ab
Add some tests for denial ACLs
gmgigi96 Jun 16, 2021
d97fe82
Add dependency for tests
gmgigi96 Jun 16, 2021
b585ecc
Add directory for tests in homecanary
gmgigi96 Jun 16, 2021
b412ab9
Add error check for AddGrant method and add user in context in ACLs t…
gmgigi96 Jun 16, 2021
53c477e
Added changelog
glpatcern Jun 16, 2021
2fc45ab
Fix for AddGrant when adding a grant for an existing grantee
gmgigi96 Jun 16, 2021
2183872
Add Grants tests
gmgigi96 Jun 16, 2021
1608328
Add deepcopy dependency for test
gmgigi96 Jun 16, 2021
0968c63
Fix eosfs with new changes in Grants
gmgigi96 Jun 16, 2021
d009742
Made private setACLs for eosfs
gmgigi96 Jun 21, 2021
79176d2
Add comments to grants.go
gmgigi96 Jun 21, 2021
e3aa890
Added method to storage FS interface
glpatcern Jun 23, 2021
67d520b
Implemented GetAttr for EOS package
gmgigi96 Jun 23, 2021
4fcd307
Implemented GetOwners in EOS
gmgigi96 Jun 23, 2021
f9ec91f
Fix in eosfs test
gmgigi96 Jun 24, 2021
ad66112
Add method to check if a grant is a denial
gmgigi96 Jun 24, 2021
367b2fd
Add functions to create and check an empty Group
gmgigi96 Jun 24, 2021
47c7d71
Check if the owner attr contains an egroup
gmgigi96 Jun 24, 2021
910cdec
Default GetOwners implementation of different storage.FS
gmgigi96 Jun 24, 2021
1ce9817
Check if the user is in the owner group before adding a denial grant
gmgigi96 Jun 24, 2021
1ed8ff4
Added license header and updated docs
glpatcern Jun 24, 2021
0949a40
Redefined PermissionNone to be more future-proof
glpatcern Jun 24, 2021
511df52
Skip test when /usr/bin/eos does not exist
gmgigi96 Jun 29, 2021
cf6d8c7
eosfs: run eostests explicitly
labkode Jun 29, 2021
01126f0
Merge remote-tracking branch 'up/master' into denyacl
labkode Jun 29, 2021
2e1890c
Add deny permission to CLI
gmgigi96 Jun 30, 2021
627c56a
Also added viewer and coowner roles
glpatcern Jun 30, 2021
80fe16c
eos: use correct sudo identity for privileged commands
labkode Jul 1, 2021
8adb70a
eos: do not hardcode eos binary location
labkode Jul 1, 2021
f9a2ddd
eos: revert me later: force eos set attr for acls
labkode Jul 1, 2021
e016d78
CI: fix the path for the reva Dockerfile on .drone.star (#1843)
SamuAlfageme Jun 29, 2021
eb6460e
CI: use golang:alpine3.13 as builder/base to prevent make errors (#1844)
SamuAlfageme Jun 30, 2021
dc58ab6
[tests-only] Bump core commit id for tests (#1840)
saw-jan Jun 30, 2021
6887833
[Build-deps]: Bump google.golang.org/grpc from 1.38.0 to 1.39.0 (#1845)
dependabot[bot] Jun 30, 2021
01e8b2a
adjust expectedfailues for remaining closed issues (#1823)
jasson99 Jun 30, 2021
68262a3
[Build-deps]: Bump google.golang.org/protobuf from 1.27.0 to 1.27.1 (…
dependabot[bot] Jun 30, 2021
924602b
Add API key to Mentix GOCDB connector (#1834)
Daniel-WWU-IT Jun 30, 2021
8a28d0b
Use golang:alpine3.13 for revad-eos docker image (#1847)
ishank011 Jun 30, 2021
8634a12
[docs-only] Some more details about the tests system, fix #1836 (#1837)
michielbdejong Jun 30, 2021
79694d1
LDAP: numeric uid/gid fallback to nobody(99) (#1848)
butonic Jul 1, 2021
cd34c57
[Build-deps]: Bump github.com/rs/cors from 1.7.0 to 1.8.0 (#1851)
dependabot[bot] Jul 1, 2021
91e6fcc
[Build-deps]: Bump github.com/minio/minio-go/v7 from 7.0.11 to 7.0.12…
dependabot[bot] Jul 1, 2021
0459330
Wrap ref to have full path
gmgigi96 Jul 5, 2021
a8d9d26
Add status check to group response
gmgigi96 Jul 5, 2021
37656bf
Fix EOS attr deserialization
gmgigi96 Jul 5, 2021
2187419
Renamed "coowner" to "collaborator". To be reviewed once the role def…
glpatcern Jul 6, 2021
efe1bfb
Add position to AddACL's EOSClient interface
gmgigi96 Jul 6, 2021
816dc57
Update method in EOSgrpc to accept a position parameter.
gmgigi96 Jul 6, 2021
7e1d80b
Implement position logic in EOS binary
gmgigi96 Jul 6, 2021
e41a558
Atomic implementation of denials
gmgigi96 Jul 6, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/unreleased/deny-acls.md
@@ -0,0 +1,4 @@
Enhancement: add support for a deny-all permission on references
and implement it on the EOS storage

http://github.com/cs3org/reva/pull/1798
1 change: 1 addition & 0 deletions cmd/reva/common.go
Expand Up @@ -32,6 +32,7 @@ import (
const (
viewerPermission string = "viewer"
editorPermission string = "editor"
denyPermission string = "deny"
)

type config struct {
Expand Down
10 changes: 7 additions & 3 deletions cmd/reva/share-create.go
Expand Up @@ -153,15 +153,16 @@ func getGrantType(t string) provider.GranteeType {
}

func getSharePerm(p string) (*provider.ResourcePermissions, error) {
if p == viewerPermission {
switch p {
case viewerPermission:
return &provider.ResourcePermissions{
GetPath: true,
InitiateFileDownload: true,
ListFileVersions: true,
ListContainer: true,
Stat: true,
}, nil
} else if p == editorPermission {
case editorPermission:
return &provider.ResourcePermissions{
GetPath: true,
InitiateFileDownload: true,
Expand All @@ -174,6 +175,9 @@ func getSharePerm(p string) (*provider.ResourcePermissions, error) {
RestoreFileVersion: true,
Move: true,
}, nil
case denyPermission:
return &provider.ResourcePermissions{}, nil
default:
return nil, errors.New("invalid rol: " + p)
}
return nil, errors.New("invalid rol: " + p)
}
Expand Up @@ -9,31 +9,31 @@ description: >
# _struct: config_

{{% dir name="mount_path" type="string" default="/" %}}
The path where the file system would be mounted. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L52)
The path where the file system would be mounted. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L59)
{{< highlight toml >}}
[grpc.services.storageprovider]
mount_path = "/"
{{< /highlight >}}
{{% /dir %}}

{{% dir name="mount_id" type="string" default="-" %}}
The ID of the mounted file system. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L53)
The ID of the mounted file system. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L60)
{{< highlight toml >}}
[grpc.services.storageprovider]
mount_id = "-"
{{< /highlight >}}
{{% /dir %}}

{{% dir name="driver" type="string" default="localhome" %}}
The storage driver to be used. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L54)
The storage driver to be used. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L61)
{{< highlight toml >}}
[grpc.services.storageprovider]
driver = "localhome"
{{< /highlight >}}
{{% /dir %}}

{{% dir name="drivers" type="map[string]map[string]interface{}" default="localhome" %}}
[[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L55)
[[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L62)
{{< highlight toml >}}
[grpc.services.storageprovider.drivers.localhome]
root = "/var/tmp/reva/"
Expand All @@ -44,42 +44,50 @@ user_layout = "{{.Username}}"
{{% /dir %}}

{{% dir name="tmp_folder" type="string" default="/var/tmp" %}}
Path to temporary folder. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L56)
Path to temporary folder. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L63)
{{< highlight toml >}}
[grpc.services.storageprovider]
tmp_folder = "/var/tmp"
{{< /highlight >}}
{{% /dir %}}

{{% dir name="data_server_url" type="string" default="http://localhost/data" %}}
The URL for the data server. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L57)
The URL for the data server. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L64)
{{< highlight toml >}}
[grpc.services.storageprovider]
data_server_url = "http://localhost/data"
{{< /highlight >}}
{{% /dir %}}

{{% dir name="expose_data_server" type="bool" default=false %}}
Whether to expose data server. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L58)
Whether to expose data server. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L65)
{{< highlight toml >}}
[grpc.services.storageprovider]
expose_data_server = false
{{< /highlight >}}
{{% /dir %}}

{{% dir name="available_checksums" type="map[string]uint32" default=nil %}}
List of available checksums. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L59)
List of available checksums. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L66)
{{< highlight toml >}}
[grpc.services.storageprovider]
available_checksums = nil
{{< /highlight >}}
{{% /dir %}}

{{% dir name="mimetypes" type="map[string]string" default=nil %}}
List of supported mime types and corresponding file extensions. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L60)
List of supported mime types and corresponding file extensions. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L67)
{{< highlight toml >}}
[grpc.services.storageprovider]
mimetypes = nil
{{< /highlight >}}
{{% /dir %}}

{{% dir name="gatewaysvc" type="string" default="/" %}}
Stores the endpoint at which the GRPC gateway is exposed. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L68)
{{< highlight toml >}}
[grpc.services.storageprovider]
gatewaysvc = "/"
{{< /highlight >}}
{{% /dir %}}

3 changes: 3 additions & 0 deletions go.mod
Expand Up @@ -23,6 +23,7 @@ require (
github.com/go-sql-driver/mysql v1.6.0
github.com/golang/protobuf v1.5.2
github.com/gomodule/redigo v1.8.5
github.com/google/go-cmp v0.5.5 // indirect
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-querystring v1.0.0 // indirect
github.com/google/uuid v1.2.0
Expand All @@ -34,6 +35,7 @@ require (
github.com/minio/minio-go/v7 v7.0.11
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.4.1
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.13.0
github.com/ory/fosite v0.40.2
Expand All @@ -46,6 +48,7 @@ require (
github.com/sethvargo/go-password v0.2.0
github.com/stretchr/testify v1.7.0
github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1
github.com/thanhpk/randstr v1.0.4
github.com/tus/tusd v1.1.1-0.20200416115059-9deabf9d80c2
go.opencensus.io v0.23.0
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -1171,6 +1171,8 @@ github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
github.com/tidwall/gjson v1.7.1/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
Expand Down
48 changes: 48 additions & 0 deletions internal/grpc/services/storageprovider/storageprovider.go
Expand Up @@ -28,16 +28,23 @@ import (
"strconv"
"strings"

groupv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/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/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
grouputils "github.com/cs3org/reva/pkg/group/utils"
"github.com/cs3org/reva/pkg/mime"
"github.com/cs3org/reva/pkg/rgrpc"
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/sharedconf"
"github.com/cs3org/reva/pkg/storage"
"github.com/cs3org/reva/pkg/storage/fs/registry"
"github.com/cs3org/reva/pkg/storage/utils/grants"
"github.com/cs3org/reva/pkg/user"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"go.opencensus.io/trace"
Expand All @@ -58,6 +65,7 @@ type config struct {
ExposeDataServer bool `mapstructure:"expose_data_server" docs:"false;Whether to expose data server."` // if true the client will be able to upload/download directly to it
AvailableXS map[string]uint32 `mapstructure:"available_checksums" docs:"nil;List of available checksums."`
MimeTypes map[string]string `mapstructure:"mimetypes" docs:"nil;List of supported mime types and corresponding file extensions."`
GatewaySvc string `mapstructure:"gatewaysvc" docs:"/;Stores the endpoint at which the GRPC gateway is exposed."`
}

func (c *config) init() {
Expand Down Expand Up @@ -90,6 +98,9 @@ func (c *config) init() {
if len(c.AvailableXS) == 0 {
c.AvailableXS = map[string]uint32{"md5": 100, "unset": 1000}
}

// get default GatewaySVC value if not set
c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
}

type service struct {
Expand Down Expand Up @@ -922,6 +933,43 @@ func (s *service) AddGrant(ctx context.Context, req *provider.AddGrantRequest) (
}, nil
}

// if the grant is a denial, check if the current user is an owner of the reference
if grants.IsDenial(req.Grant) {
user, ok := user.ContextGetUser(ctx)
if !ok {
return nil, errtypes.InternalError("user not found in context")
}

client, err := pool.GetGatewayServiceClient(s.conf.GatewaySvc)
if err != nil {
return nil, err
}

// get owner of the reference
owners, err := s.storage.GetOwners(ctx, req.Ref)
if err != nil {
return nil, err
}

// check if the group is empty
if grouputils.IsEmptyGroup(owners) {
return nil, errtypes.PermissionDenied("user is not an owner")
}

// check if the user is in the owner list
hasMemberResp, err := client.HasMember(ctx, &groupv1beta1.HasMemberRequest{
GroupId: owners.Id,
UserId: user.Id,
})
if err != nil {
return nil, err
}

if !hasMemberResp.Ok {
return nil, errtypes.PermissionDenied("user is not an owner")
}
}

err = s.storage.AddGrant(ctx, newRef, req.Grant)
if err != nil {
var st *rpc.Status
Expand Down
16 changes: 11 additions & 5 deletions internal/http/services/owncloud/ocs/conversions/permissions.go
Expand Up @@ -26,7 +26,7 @@ import (
type Permissions uint

const (
// PermissionInvalid grants no permissions on a resource
// PermissionInvalid represents an invalid permission
PermissionInvalid Permissions = 0
// PermissionRead grants read permissions on a resource
PermissionRead Permissions = 1 << (iota - 1)
Expand All @@ -38,21 +38,27 @@ const (
PermissionDelete
// PermissionShare grants share permissions on a resource
PermissionShare
// PermissionNone grants no permissions on a resource
PermissionNone
// PermissionMax is to be used within value range checks
PermissionMax Permissions = (1 << (iota - 1)) - 1
// PermissionAll grants all permissions on a resource
PermissionAll Permissions = (1 << (iota - 1)) - 1
PermissionAll = PermissionMax - PermissionNone
// PermissionMin is to be used within value range checks
PermissionMin = PermissionRead
)

var (
// ErrPermissionNotInRange defines a permission specific error.
ErrPermissionNotInRange = fmt.Errorf("The provided permission is not between %d and %d", PermissionInvalid, PermissionAll)
ErrPermissionNotInRange = fmt.Errorf("The provided permission is not between %d and %d", PermissionMin, PermissionMax)
)

// NewPermissions creates a new Permissions instance.
// The value must be in the valid range.
func NewPermissions(val int) (Permissions, error) {
if val == int(PermissionInvalid) {
return PermissionInvalid, fmt.Errorf("permissions %d out of range %d - %d", val, PermissionRead, PermissionAll)
} else if val < int(PermissionInvalid) || int(PermissionAll) < val {
return PermissionInvalid, fmt.Errorf("permissions %d out of range %d - %d", val, PermissionMin, PermissionMax)
} else if val < int(PermissionInvalid) || int(PermissionMax) < val {
return PermissionInvalid, ErrPermissionNotInRange
}
return Permissions(val), nil
Expand Down
Expand Up @@ -23,7 +23,7 @@ import (
)

func TestNewPermissions(t *testing.T) {
for val := int(PermissionRead); val <= int(PermissionAll); val++ {
for val := int(PermissionMin); val <= int(PermissionMax); val++ {
_, err := NewPermissions(val)
if err != nil {
t.Errorf("value %d should be a valid permissions", val)
Expand All @@ -35,7 +35,7 @@ func TestNewPermissionsWithInvalidValueShouldFail(t *testing.T) {
vals := []int{
int(PermissionInvalid),
-1,
int(PermissionAll) + 1,
int(PermissionMax) + 1,
}
for _, v := range vals {
_, err := NewPermissions(v)
Expand Down Expand Up @@ -149,6 +149,7 @@ func TestPermissions2Role(t *testing.T) {
PermissionWrite: RoleLegacy,
PermissionShare: RoleLegacy,
PermissionWrite | PermissionShare: RoleLegacy,
PermissionNone: RoleDenied,
}

for permissions, role := range table {
Expand Down
20 changes: 20 additions & 0 deletions internal/http/services/owncloud/ocs/conversions/role.go
Expand Up @@ -38,6 +38,8 @@ const (
RoleUnknown string = "unknown"
// RoleLegacy provides backwards compatibility
RoleLegacy string = "legacy"
// RoleDenied grants no permission at all on a resource
RoleDenied string = "denied"
// RoleViewer grants non-editor role on a resource
RoleViewer string = "viewer"
// RoleEditor grants editor permission on a resource, including folders
Expand Down Expand Up @@ -119,6 +121,8 @@ func (r *Role) WebDAVPermissions(isDir, isShared, isMountpoint, isPublic bool) s
// RoleFromName creates a role from the name
func RoleFromName(name string) *Role {
switch name {
case RoleDenied:
return NewDeniedRole()
case RoleViewer:
return NewViewerRole()
case RoleEditor:
Expand All @@ -142,6 +146,15 @@ func NewUnknownRole() *Role {
}
}

// NewDeniedRole creates a fully denied role
func NewDeniedRole() *Role {
return &Role{
Name: RoleDenied,
cS3ResourcePermissions: &provider.ResourcePermissions{},
ocsPermissions: PermissionNone,
}
}

// NewViewerRole creates a viewer role
func NewViewerRole() *Role {
return &Role{
Expand Down Expand Up @@ -294,6 +307,9 @@ func RoleFromOCSPermissions(p Permissions) *Role {
if p == PermissionCreate {
return NewUploaderRole()
}
if p == PermissionNone {
return NewDeniedRole()
}
// legacy
return NewLegacyRoleFromOCSPermissions(p)
}
Expand Down Expand Up @@ -401,6 +417,10 @@ func RoleFromResourcePermissions(rp *provider.ResourcePermissions) *Role {
r.Name = RoleUploader
return r
}
if r.ocsPermissions == PermissionNone {
r.Name = RoleDenied
return r
}
r.Name = RoleLegacy
// at this point other ocs permissions may have been mapped.
// TODO what about even more granular cs3 permissions?, eg. only stat
Expand Down