From 626d28adaa30f96836a531cf79a9b216f0f21caa Mon Sep 17 00:00:00 2001 From: kobergj Date: Wed, 12 Jan 2022 16:57:28 +0100 Subject: [PATCH] [tests-only] Merge master into edge (#2435) * [Build-deps] Additional rules for CODEOWNERS (#2323) * Remove share refs from trashbin (#2298) * Public link propfind (#2315) * fix public share type in propfinds (#2316) * Bump core commit id for tests (#2331) * Revert "Fix content disposition (#2303)" (#2332) This reverts commit 3cba22371b78213f2e49197c2783220331a264bd. * [Build-deps]: Bump github.com/gomodule/redigo from 1.8.5 to 1.8.6 (#2326) * [Build-deps]: Bump github.com/mitchellh/mapstructure from 1.4.2 to 1.4.3 (#2324) * [Build-deps]: Bump github.com/aws/aws-sdk-go from 1.42.9 to 1.42.19 (#2325) * fix app provider new file action and improve app provider error codes (#2210) * Parse URL path to determine file name (#2346) * v1.17.0 * handle non existent spaces gracefully (#2354) * Bump core commit id for tests (#2365) * [Build-deps]: Bump github.com/minio/minio-go/v7 from 7.0.16 to 7.0.18 (#2363) * [Build-deps]: Bump github.com/ReneKroon/ttlcache/v2 from 2.9.0 to 2.10.0 (#2358) * [Build-deps]: Bump go.opentelemetry.io/otel/exporters/jaeger (#2362) * fix tests by pointing to the right owncloud/core commit id for tests (#2375) * add new file capabilties to ocs for the app provider (#2379) * Remove test from expected to fail and bump commit id (#2380) * add .drone.env to CODEOWNERS as it is part of the test files (#2378) * fix webdav copy for zero byte files (#2374) * Implement touch file (#2369) * implement cs3org/cs3apis#154 * use TouchFile for the app provider * add changelog and comments * revert use TouchFile in app provider * fix resource typo Co-authored-by: Giuseppe Lo Presti Co-authored-by: Giuseppe Lo Presti * Dummy implementation of the Lock CS3APIs (#2350) * allow new file create with app provider on public links (#2385) * Bump core commit id and use core master for tests (#2391) * Add product to ocs Version struct (#2397) The web ui will announce the backend version in the javascript console and is supposed to include the product name as well. The version seems to be a good location for the product field as it already includes the software edition as well. * bump core commit id for tests (#2404) * [Build-deps]: Bump github.com/mattn/go-sqlite3 from 1.14.9 to 1.14.10 (#2409) * [Build-deps]: Bump github.com/minio/minio-go/v7 from 7.0.18 to 7.0.20 (#2408) * [Build-deps]: Bump github.com/rs/cors from 1.8.0 to 1.8.2 (#2399) * [Build-deps]: Bump github.com/ReneKroon/ttlcache/v2 (#2387) * [Build-deps]: Bump go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc (#2359) * [tests-only] format .drone.star (#2411) * update tus/tusd to version 1.8.0 (#2393) * Fixes for apps in public shares, project spaces for EOS driver (#2371) * [Build-deps]: Bump github.com/aws/aws-sdk-go from 1.42.19 to 1.42.27 (#2414) * [Build-deps]: Bump github.com/rs/zerolog from 1.26.0 to 1.26.1 (#2388) * update owncloud core commit id (#2418) * [Build-deps]: Bump github.com/mattn/go-sqlite3 (#2425) * [Build-deps]: Bump github.com/gomodule/redigo from 1.8.6 to 1.8.8 (#2426) * OIDC and WOPI changes for lightweight users (#2278) * don't create references in gateway Signed-off-by: jkoberg * don't run virtual views testsuite Signed-off-by: jkoberg * bring back token scope expanding Signed-off-by: jkoberg Co-authored-by: Giuseppe Lo Presti Co-authored-by: Gianmaria Del Monte <39946305+gmgigi96@users.noreply.github.com> Co-authored-by: David Christofas Co-authored-by: Swikriti Tripathi <41103328+SwikritiT@users.noreply.github.com> Co-authored-by: Ishank Arora Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Willy Kloucek <34452982+wkloucek@users.noreply.github.com> Co-authored-by: Michael Barz Co-authored-by: Phil Davis Co-authored-by: Benedikt Kulmann Co-authored-by: Saw-jan Gurung Co-authored-by: PKiran <39373750+kiranparajuli589@users.noreply.github.com> --- changelog/unreleased/oidc-lw-users.md | 3 + go.mod | 4 +- go.sum | 10 +-- internal/grpc/interceptors/auth/scope.go | 3 + .../grpc/services/gateway/authprovider.go | 2 + .../grpc/services/gateway/storageprovider.go | 74 ++++++++++--------- .../services/gateway/usershareprovider.go | 55 +++++++++++++- pkg/app/provider/wopi/wopi.go | 6 ++ pkg/auth/manager/oidc/oidc.go | 23 +++++- pkg/auth/scope/lightweight.go | 32 +++++++- pkg/auth/scope/receivedshare.go | 5 +- pkg/auth/scope/share.go | 5 +- pkg/cbox/user/rest/rest.go | 47 ++++++++++-- pkg/eosclient/eosbinary/eosbinary.go | 2 +- pkg/storage/utils/acl/acl.go | 26 ++++++- pkg/storage/utils/eosfs/eosfs.go | 15 +++- 16 files changed, 250 insertions(+), 62 deletions(-) create mode 100644 changelog/unreleased/oidc-lw-users.md diff --git a/changelog/unreleased/oidc-lw-users.md b/changelog/unreleased/oidc-lw-users.md new file mode 100644 index 00000000000..2053f695513 --- /dev/null +++ b/changelog/unreleased/oidc-lw-users.md @@ -0,0 +1,3 @@ +Enhancement: OIDC driver changes for lightweight users + +https://github.com/cs3org/reva/pull/2278 \ No newline at end of file diff --git a/go.mod b/go.mod index 38b1fae6b9e..02be6ef2f59 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/go-sql-driver/mysql v1.6.0 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang/protobuf v1.5.2 - github.com/gomodule/redigo v1.8.6 + github.com/gomodule/redigo v1.8.8 github.com/google/go-cmp v0.5.6 github.com/google/go-github v17.0.0+incompatible github.com/google/go-querystring v1.1.0 // indirect @@ -39,7 +39,7 @@ require ( github.com/imdario/mergo v0.3.12 // indirect github.com/jedib0t/go-pretty v4.3.0+incompatible github.com/juliangruber/go-intersect v1.1.0 - github.com/mattn/go-sqlite3 v1.14.10 + github.com/mattn/go-sqlite3 v2.0.3+incompatible github.com/mileusna/useragent v1.0.2 github.com/minio/minio-go/v7 v7.0.20 github.com/mitchellh/copystructure v1.2.0 // indirect diff --git a/go.sum b/go.sum index 4307249b7a3..85d13001aad 100644 --- a/go.sum +++ b/go.sum @@ -345,8 +345,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v1.8.6 h1:h7kHSqUl2kxeaQtVslsfUCPJ1oz2pxcyzLy4zezIzPw= -github.com/gomodule/redigo v1.8.6/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/gomodule/redigo v1.8.8 h1:f6cXq6RRfiyrOJEV7p3JhLDlmawGBVBBP1MggY8Mo4E= +github.com/gomodule/redigo v1.8.8/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -504,8 +504,8 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk= -github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= +github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI= github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -664,8 +664,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/studio-b12/gowebdav v0.0.0-20210917133250-a3a86976a1df h1:C+J/LwTqP8gRPt1MdSzBNZP0OYuDm5wsmDKgwpLjYzo= -github.com/studio-b12/gowebdav v0.0.0-20210917133250-a3a86976a1df/go.mod h1:gCcfDlA1Y7GqOaeEKw5l9dOGx1VLdc/HuQSlQAaZ30s= github.com/studio-b12/gowebdav v0.0.0-20211109083228-3f8721cd4b6f h1:L2NE7BXnSlSLoNYZ0lCwZDjdnYjCNYC71k9ClZUTFTs= github.com/studio-b12/gowebdav v0.0.0-20211109083228-3f8721cd4b6f/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= diff --git a/internal/grpc/interceptors/auth/scope.go b/internal/grpc/interceptors/auth/scope.go index be4da102fc8..8eec835ea19 100644 --- a/internal/grpc/interceptors/auth/scope.go +++ b/internal/grpc/interceptors/auth/scope.go @@ -120,6 +120,9 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s if utils.ResourceIDEqual(share.Share.ResourceId, ref.GetResourceId()) { return nil } + if ok, err := checkIfNestedResource(ctx, ref, share.Share.ResourceId, client, mgr); err == nil && ok { + return nil + } } } else if strings.HasPrefix(k, "publicshare") { var share link.PublicShare diff --git a/internal/grpc/services/gateway/authprovider.go b/internal/grpc/services/gateway/authprovider.go index 35960709704..2f066797ddc 100644 --- a/internal/grpc/services/gateway/authprovider.go +++ b/internal/grpc/services/gateway/authprovider.go @@ -118,6 +118,8 @@ func (s *svc) Authenticate(ctx context.Context, req *gateway.AuthenticateRequest ctx = ctxpkg.ContextSetToken(ctx, token) ctx = ctxpkg.ContextSetUser(ctx, res.User) ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, token) + + // TODO(ishank011): Add a cache for these scope, err := s.expandScopes(ctx, res.TokenScope) if err != nil { err = errors.Wrap(err, "authsvc: error expanding token scope") diff --git a/internal/grpc/services/gateway/storageprovider.go b/internal/grpc/services/gateway/storageprovider.go index 02a412fc848..397faa64c9f 100644 --- a/internal/grpc/services/gateway/storageprovider.go +++ b/internal/grpc/services/gateway/storageprovider.go @@ -35,6 +35,7 @@ import ( provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1" typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + "google.golang.org/grpc/codes" "github.com/cs3org/reva/pkg/appctx" ctxpkg "github.com/cs3org/reva/pkg/ctx" @@ -46,6 +47,8 @@ import ( "github.com/cs3org/reva/pkg/utils" "github.com/golang-jwt/jwt" "github.com/pkg/errors" + + gstatus "google.golang.org/grpc/status" ) /* About caching @@ -558,15 +561,16 @@ func (s *svc) TouchFile(ctx context.Context, req *provider.TouchFileRequest) (*p c, _, err := s.find(ctx, req.Ref) if err != nil { return &provider.TouchFileResponse{ - Status: status.NewStatusFromErrType(ctx, fmt.Sprintf("gateway could not find reference %+v", req.Ref), err), + Status: status.NewStatusFromErrType(ctx, "TouchFile ref="+req.Ref.String(), err), }, nil } res, err := c.TouchFile(ctx, req) if err != nil { - return &provider.TouchFileResponse{ - Status: status.NewStatusFromErrType(ctx, "gateway could not call TouchFile", err), - }, nil + if gstatus.Code(err) == codes.PermissionDenied { + return &provider.TouchFileResponse{Status: &rpc.Status{Code: rpc.Code_CODE_PERMISSION_DENIED}}, nil + } + return nil, errors.Wrap(err, "gateway: error calling TouchFile") } return res, nil @@ -651,9 +655,10 @@ func (s *svc) SetArbitraryMetadata(ctx context.Context, req *provider.SetArbitra res, err := c.SetArbitraryMetadata(ctx, req) if err != nil { - return &provider.SetArbitraryMetadataResponse{ - Status: status.NewStatusFromErrType(ctx, "gateway could not call SetArbitraryMetadata", err), - }, nil + if gstatus.Code(err) == codes.PermissionDenied { + return &provider.SetArbitraryMetadataResponse{Status: &rpc.Status{Code: rpc.Code_CODE_PERMISSION_DENIED}}, nil + } + return nil, errors.Wrap(err, "gateway: error calling SetArbitraryMetadata") } s.cache.RemoveStat(ctxpkg.ContextMustGetUser(ctx), req.Ref.ResourceId) @@ -673,12 +678,13 @@ func (s *svc) UnsetArbitraryMetadata(ctx context.Context, req *provider.UnsetArb res, err := c.UnsetArbitraryMetadata(ctx, req) if err != nil { - return &provider.UnsetArbitraryMetadataResponse{ - Status: status.NewStatusFromErrType(ctx, "gateway could not call UnsetArbitraryMetadata", err), - }, nil + if gstatus.Code(err) == codes.PermissionDenied { + return &provider.UnsetArbitraryMetadataResponse{Status: &rpc.Status{Code: rpc.Code_CODE_PERMISSION_DENIED}}, nil + } + return nil, errors.Wrap(err, "gateway: error calling UnsetArbitraryMetadata") } - s.cache.RemoveStat(ctxpkg.ContextMustGetUser(ctx), req.Ref.ResourceId) + return res, nil } @@ -695,9 +701,10 @@ func (s *svc) SetLock(ctx context.Context, req *provider.SetLockRequest) (*provi res, err := c.SetLock(ctx, req) if err != nil { - return &provider.SetLockResponse{ - Status: status.NewStatusFromErrType(ctx, "gateway could not call SetLock", err), - }, nil + if gstatus.Code(err) == codes.PermissionDenied { + return &provider.SetLockResponse{Status: &rpc.Status{Code: rpc.Code_CODE_PERMISSION_DENIED}}, nil + } + return nil, errors.Wrap(err, "gateway: error calling SetLock") } return res, nil @@ -705,20 +712,19 @@ func (s *svc) SetLock(ctx context.Context, req *provider.SetLockRequest) (*provi // GetLock returns an existing lock on the given reference func (s *svc) GetLock(ctx context.Context, req *provider.GetLockRequest) (*provider.GetLockResponse, error) { - var c provider.ProviderAPIClient - var err error - c, _, req.Ref, err = s.findAndUnwrap(ctx, req.Ref) + c, _, err := s.find(ctx, req.Ref) if err != nil { return &provider.GetLockResponse{ - Status: status.NewStatusFromErrType(ctx, fmt.Sprintf("gateway could not find space for ref=%+v", req.Ref), err), + Status: status.NewStatusFromErrType(ctx, "GetLock ref="+req.Ref.String(), err), }, nil } res, err := c.GetLock(ctx, req) if err != nil { - return &provider.GetLockResponse{ - Status: status.NewStatusFromErrType(ctx, "gateway could not call GetLock", err), - }, nil + if gstatus.Code(err) == codes.PermissionDenied { + return &provider.GetLockResponse{Status: &rpc.Status{Code: rpc.Code_CODE_PERMISSION_DENIED}}, nil + } + return nil, errors.Wrap(err, "gateway: error calling GetLock") } return res, nil @@ -726,20 +732,19 @@ func (s *svc) GetLock(ctx context.Context, req *provider.GetLockRequest) (*provi // RefreshLock refreshes an existing lock on the given reference func (s *svc) RefreshLock(ctx context.Context, req *provider.RefreshLockRequest) (*provider.RefreshLockResponse, error) { - var c provider.ProviderAPIClient - var err error - c, _, req.Ref, err = s.findAndUnwrap(ctx, req.Ref) + c, _, err := s.find(ctx, req.Ref) if err != nil { return &provider.RefreshLockResponse{ - Status: status.NewStatusFromErrType(ctx, fmt.Sprintf("gateway could not find space for ref=%+v", req.Ref), err), + Status: status.NewStatusFromErrType(ctx, "RefreshLock ref="+req.Ref.String(), err), }, nil } res, err := c.RefreshLock(ctx, req) if err != nil { - return &provider.RefreshLockResponse{ - Status: status.NewStatusFromErrType(ctx, "gateway could not call RefreshLock", err), - }, nil + if gstatus.Code(err) == codes.PermissionDenied { + return &provider.RefreshLockResponse{Status: &rpc.Status{Code: rpc.Code_CODE_PERMISSION_DENIED}}, nil + } + return nil, errors.Wrap(err, "gateway: error calling RefreshLock") } return res, nil @@ -747,20 +752,19 @@ func (s *svc) RefreshLock(ctx context.Context, req *provider.RefreshLockRequest) // Unlock removes an existing lock from the given reference func (s *svc) Unlock(ctx context.Context, req *provider.UnlockRequest) (*provider.UnlockResponse, error) { - var c provider.ProviderAPIClient - var err error - c, _, req.Ref, err = s.findAndUnwrap(ctx, req.Ref) + c, _, err := s.find(ctx, req.Ref) if err != nil { return &provider.UnlockResponse{ - Status: status.NewStatusFromErrType(ctx, fmt.Sprintf("gateway could not find space for ref=%+v", req.Ref), err), + Status: status.NewStatusFromErrType(ctx, "Unlock ref="+req.Ref.String(), err), }, nil } res, err := c.Unlock(ctx, req) if err != nil { - return &provider.UnlockResponse{ - Status: status.NewStatusFromErrType(ctx, "gateway could not call Unlock", err), - }, nil + if gstatus.Code(err) == codes.PermissionDenied { + return &provider.UnlockResponse{Status: &rpc.Status{Code: rpc.Code_CODE_PERMISSION_DENIED}}, nil + } + return nil, errors.Wrap(err, "gateway: error calling Unlock") } return res, nil diff --git a/internal/grpc/services/gateway/usershareprovider.go b/internal/grpc/services/gateway/usershareprovider.go index 8fac9cf8dbb..c3e88d16d1a 100644 --- a/internal/grpc/services/gateway/usershareprovider.go +++ b/internal/grpc/services/gateway/usershareprovider.go @@ -22,18 +22,17 @@ import ( "context" "path" - ctxpkg "github.com/cs3org/reva/pkg/ctx" - rtrace "github.com/cs3org/reva/pkg/trace" - rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" "github.com/cs3org/reva/pkg/appctx" + ctxpkg "github.com/cs3org/reva/pkg/ctx" "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/rgrpc/status" "github.com/cs3org/reva/pkg/rgrpc/todo/pool" "github.com/cs3org/reva/pkg/storage/utils/grants" + rtrace "github.com/cs3org/reva/pkg/trace" "github.com/pkg/errors" ) @@ -327,8 +326,56 @@ func (s *svc) UpdateReceivedShare(ctx context.Context, req *collaboration.Update s.cache.RemoveStat(ctxpkg.ContextMustGetUser(ctx), req.Share.Share.ResourceId) return c.UpdateReceivedShare(ctx, req) -} + /* + TODO: Leftover from master merge. Do we need this? + if err != nil { + appctx.GetLogger(ctx). + Err(err). + Msg("UpdateReceivedShare: failed to get user share provider") + return &collaboration.UpdateReceivedShareResponse{ + Status: status.NewInternal(ctx, "error getting share provider client"), + }, nil + } + // check if we have a resource id in the update response that we can use to update references + if res.GetShare().GetShare().GetResourceId() == nil { + log.Err(err).Msg("gateway: UpdateReceivedShare must return a ResourceId") + return &collaboration.UpdateReceivedShareResponse{ + Status: &rpc.Status{ + Code: rpc.Code_CODE_INTERNAL, + }, + }, nil + } + // properties are updated in the order they appear in the field mask + // when an error occurs the request ends and no further fields are updated + for i := range req.UpdateMask.Paths { + switch req.UpdateMask.Paths[i] { + case "state": + switch req.GetShare().GetState() { + case collaboration.ShareState_SHARE_STATE_ACCEPTED: + rpcStatus := s.createReference(ctx, res.GetShare().GetShare().GetResourceId()) + if rpcStatus.Code != rpc.Code_CODE_OK { + return &collaboration.UpdateReceivedShareResponse{Status: rpcStatus}, nil + } + case collaboration.ShareState_SHARE_STATE_REJECTED: + rpcStatus := s.removeReference(ctx, res.GetShare().GetShare().ResourceId) + if rpcStatus.Code != rpc.Code_CODE_OK && rpcStatus.Code != rpc.Code_CODE_NOT_FOUND { + return &collaboration.UpdateReceivedShareResponse{Status: rpcStatus}, nil + } + } + case "mount_point": + // TODO(labkode): implementing updating mount point + err = errtypes.NotSupported("gateway: update of mount point is not yet implemented") + return &collaboration.UpdateReceivedShareResponse{ + Status: status.NewUnimplemented(ctx, err, "error updating received share"), + }, nil + default: + return nil, errtypes.NotSupported("updating " + req.UpdateMask.Paths[i] + " is not supported") + } + } + return res, nil + */ +} func (s *svc) removeReference(ctx context.Context, resourceID *provider.ResourceId) *rpc.Status { log := appctx.GetLogger(ctx) diff --git a/pkg/app/provider/wopi/wopi.go b/pkg/app/provider/wopi/wopi.go index 5f2a38add15..cca32227132 100644 --- a/pkg/app/provider/wopi/wopi.go +++ b/pkg/app/provider/wopi/wopi.go @@ -36,6 +36,7 @@ import ( "github.com/beevik/etree" appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1" + userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/pkg/app" "github.com/cs3org/reva/pkg/app/provider/registry" @@ -139,6 +140,11 @@ func (p *wopiProvider) GetAppURL(ctx context.Context, resource *provider.Resourc u, ok := ctxpkg.ContextGetUser(ctx) if ok { // else defaults to "Guest xyz" + if u.Id.Type == userpb.UserType_USER_TYPE_LIGHTWEIGHT { + q.Add("userid", resource.Owner.OpaqueId+"@"+resource.Owner.Idp) + } else { + q.Add("userid", u.Id.OpaqueId+"@"+u.Id.Idp) + } var isPublicShare bool if u.Opaque != nil { if _, ok := u.Opaque.Map["public-share-role"]; ok { diff --git a/pkg/auth/manager/oidc/oidc.go b/pkg/auth/manager/oidc/oidc.go index 2ed67a26986..e882b399ba5 100644 --- a/pkg/auth/manager/oidc/oidc.go +++ b/pkg/auth/manager/oidc/oidc.go @@ -23,6 +23,7 @@ package oidc import ( "context" "fmt" + "strings" "time" oidc "github.com/coreos/go-oidc" @@ -130,6 +131,12 @@ func (am *mgr) Authenticate(ctx context.Context, clientID, clientSecret string) if claims["email_verified"] == nil { // This is not set in simplesamlphp claims["email_verified"] = false } + if claims["preferred_username"] == nil { + claims["preferred_username"] = claims[am.c.IDClaim] + } + if claims["name"] == nil { + claims["name"] = claims[am.c.IDClaim] + } if claims["email"] == nil { return nil, nil, fmt.Errorf("no \"email\" attribute found in userinfo: maybe the client did not request the oidc \"email\"-scope") @@ -158,7 +165,7 @@ func (am *mgr) Authenticate(ctx context.Context, clientID, clientSecret string) userID := &user.UserId{ OpaqueId: claims[am.c.IDClaim].(string), // a stable non reassignable id Idp: claims["issuer"].(string), // in the scope of this issuer - Type: user.UserType_USER_TYPE_PRIMARY, + Type: getUserType(claims[am.c.IDClaim].(string)), } gwc, err := pool.GetGatewayServiceClient(am.c.GatewaySvc) if err != nil { @@ -236,3 +243,17 @@ func (am *mgr) getOIDCProvider(ctx context.Context) (*oidc.Provider, error) { am.provider = provider return am.provider, nil } + +func getUserType(upn string) user.UserType { + var t user.UserType + switch { + case strings.HasPrefix(upn, "guest"): + t = user.UserType_USER_TYPE_LIGHTWEIGHT + case strings.Contains(upn, "@"): + t = user.UserType_USER_TYPE_FEDERATED + default: + t = user.UserType_USER_TYPE_PRIMARY + } + return t + +} diff --git a/pkg/auth/scope/lightweight.go b/pkg/auth/scope/lightweight.go index 8256f3f09be..5ebc8d22252 100644 --- a/pkg/auth/scope/lightweight.go +++ b/pkg/auth/scope/lightweight.go @@ -20,6 +20,7 @@ package scope import ( "context" + "strings" authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" @@ -34,12 +35,41 @@ func lightweightAccountScope(_ context.Context, scope *authpb.Scope, resource in // These cannot be resolved from here, but need to be added to the scope from // where the call to mint tokens is made. // From here, we only allow ListReceivedShares calls - if _, ok := resource.(*collaboration.ListReceivedSharesRequest); ok { + switch v := resource.(type) { + case *collaboration.ListReceivedSharesRequest: return true, nil + case string: + return checkLightweightPath(v), nil } return false, nil } +func checkLightweightPath(path string) bool { + paths := []string{ + "/ocs/v2.php/apps/files_sharing/api/v1/shares", + "/ocs/v1.php/apps/files_sharing/api/v1/shares", + "/ocs/v2.php/apps/files_sharing//api/v1/shares", + "/ocs/v1.php/apps/files_sharing//api/v1/shares", + "/ocs/v2.php/cloud/capabilities", + "/ocs/v1.php/cloud/capabilities", + "/ocs/v2.php/cloud/user", + "/ocs/v1.php/cloud/user", + "/remote.php/webdav", + "/remote.php/dav/files", + "/app/open", + "/app/new", + "/archiver", + "/dataprovider", + "/data", + } + for _, p := range paths { + if strings.HasPrefix(path, p) { + return true + } + } + return false +} + // AddLightweightAccountScope adds the scope to allow access to lightweight user. func AddLightweightAccountScope(role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) { ref := &provider.Reference{Path: "/"} diff --git a/pkg/auth/scope/receivedshare.go b/pkg/auth/scope/receivedshare.go index 2974b0ca2a7..81236a3c358 100644 --- a/pkg/auth/scope/receivedshare.go +++ b/pkg/auth/scope/receivedshare.go @@ -54,7 +54,10 @@ func receivedShareScope(_ context.Context, scope *authpb.Scope, resource interfa // AddReceivedShareScope adds the scope to allow access to a received user/group share and // the shared resource. func AddReceivedShareScope(share *collaboration.ReceivedShare, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) { - val, err := utils.MarshalProtoV1ToJSON(share) + // Create a new "scope share" to only expose the required fields to the scope. + scopeShare := &collaboration.Share{Id: share.Share.Id, Owner: share.Share.Owner, Creator: share.Share.Creator, ResourceId: share.Share.ResourceId} + + val, err := utils.MarshalProtoV1ToJSON(&collaboration.ReceivedShare{Share: scopeShare}) if err != nil { return nil, err } diff --git a/pkg/auth/scope/share.go b/pkg/auth/scope/share.go index 48683dea17e..6284efd0076 100644 --- a/pkg/auth/scope/share.go +++ b/pkg/auth/scope/share.go @@ -121,7 +121,10 @@ func checkSharePath(path string) bool { // AddShareScope adds the scope to allow access to a user/group share and // the shared resource. func AddShareScope(share *collaboration.Share, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) { - val, err := utils.MarshalProtoV1ToJSON(share) + // Create a new "scope share" to only expose the required fields to the scope. + scopeShare := &collaboration.Share{Id: share.Id, Owner: share.Owner, Creator: share.Creator, ResourceId: share.ResourceId} + + val, err := utils.MarshalProtoV1ToJSON(scopeShare) if err != nil { return nil, err } diff --git a/pkg/cbox/user/rest/rest.go b/pkg/cbox/user/rest/rest.go index eeedaba59a7..fbd1b125b2e 100644 --- a/pkg/cbox/user/rest/rest.go +++ b/pkg/cbox/user/rest/rest.go @@ -128,9 +128,7 @@ func (m *manager) Configure(ml map[string]interface{}) error { return nil } -func (m *manager) getUserByParam(ctx context.Context, param, val string) (map[string]interface{}, error) { - url := fmt.Sprintf("%s/Identity?filter=%s:%s&field=upn&field=primaryAccountEmail&field=displayName&field=uid&field=gid&field=type", - m.conf.APIBaseURL, param, url.QueryEscape(val)) +func (m *manager) getUser(ctx context.Context, url string) (map[string]interface{}, error) { responseData, err := m.apiTokenManager.SendAPIGetRequest(ctx, url, false) if err != nil { return nil, err @@ -151,17 +149,38 @@ func (m *manager) getUserByParam(ctx context.Context, param, val string) (map[st } if len(users) != 1 { - return nil, errors.New("rest: user not found: " + param + ": " + val) + return nil, errors.New("rest: user not found for URL: " + url) } return users[0], nil } +func (m *manager) getUserByParam(ctx context.Context, param, val string) (map[string]interface{}, error) { + url := fmt.Sprintf("%s/Identity?filter=%s:%s&field=upn&field=primaryAccountEmail&field=displayName&field=uid&field=gid&field=type", + m.conf.APIBaseURL, param, url.QueryEscape(val)) + return m.getUser(ctx, url) +} + +func (m *manager) getLightweightUser(ctx context.Context, mail string) (map[string]interface{}, error) { + url := fmt.Sprintf("%s/Identity?filter=primaryAccountEmail:%s&filter=upn:contains:guest&field=upn&field=primaryAccountEmail&field=displayName&field=uid&field=gid&field=type", + m.conf.APIBaseURL, url.QueryEscape(mail)) + return m.getUser(ctx, url) +} + func (m *manager) getInternalUserID(ctx context.Context, uid *userpb.UserId) (string, error) { internalID, err := m.fetchCachedInternalID(uid) if err != nil { - userData, err := m.getUserByParam(ctx, "upn", uid.OpaqueId) + var ( + userData map[string]interface{} + err error + ) + if uid.Type == userpb.UserType_USER_TYPE_LIGHTWEIGHT { + // Lightweight accounts need to be fetched by email + userData, err = m.getLightweightUser(ctx, strings.TrimPrefix(uid.OpaqueId, "guest:")) + } else { + userData, err = m.getUserByParam(ctx, "upn", uid.OpaqueId) + } if err != nil { return "", err } @@ -217,7 +236,16 @@ func (m *manager) parseAndCacheUser(ctx context.Context, userData map[string]int func (m *manager) GetUser(ctx context.Context, uid *userpb.UserId) (*userpb.User, error) { u, err := m.fetchCachedUserDetails(uid) if err != nil { - userData, err := m.getUserByParam(ctx, "upn", uid.OpaqueId) + var ( + userData map[string]interface{} + err error + ) + if uid.Type == userpb.UserType_USER_TYPE_LIGHTWEIGHT { + // Lightweight accounts need to be fetched by email + userData, err = m.getLightweightUser(ctx, strings.TrimPrefix(uid.OpaqueId, "guest:")) + } else { + userData, err = m.getUserByParam(ctx, "upn", uid.OpaqueId) + } if err != nil { return nil, err } @@ -252,7 +280,12 @@ func (m *manager) GetUserByClaim(ctx context.Context, claim, value string) (*use userData, err := m.getUserByParam(ctx, claim, value) if err != nil { - return nil, err + // Lightweight accounts need to be fetched by email + if strings.HasPrefix(value, "guest:") { + if userData, err = m.getLightweightUser(ctx, strings.TrimPrefix(value, "guest:")); err != nil { + return nil, err + } + } } u := m.parseAndCacheUser(ctx, userData) diff --git a/pkg/eosclient/eosbinary/eosbinary.go b/pkg/eosclient/eosbinary/eosbinary.go index 91b45dd0371..0da98de2d67 100644 --- a/pkg/eosclient/eosbinary/eosbinary.go +++ b/pkg/eosclient/eosbinary/eosbinary.go @@ -1001,7 +1001,7 @@ func (c *Client) parseFileInfo(raw string) (*eosclient.FileInfo, error) { }) var previousXAttr = "" for _, p := range partsBySpace { - partsByEqual := strings.Split(p, "=") // we have kv pairs like [size 14] + partsByEqual := strings.SplitN(p, "=", 2) // we have kv pairs like [size 14] if len(partsByEqual) == 2 { // handle xattrn and xattrv special cases switch { diff --git a/pkg/storage/utils/acl/acl.go b/pkg/storage/utils/acl/acl.go index 1c493c7224d..311ee1a4545 100644 --- a/pkg/storage/utils/acl/acl.go +++ b/pkg/storage/utils/acl/acl.go @@ -57,7 +57,13 @@ func Parse(acls string, delimiter string) (*ACLs, error) { if t == "" || isComment(t) { continue } - entry, err := ParseEntry(t) + var err error + var entry *Entry + if strings.HasPrefix(t, TypeLightweight) { + entry, err = ParseLWEntry(t) + } else { + entry, err = ParseEntry(t) + } if err != nil { return nil, err } @@ -133,6 +139,24 @@ func ParseEntry(singleSysACL string) (*Entry, error) { }, nil } +// ParseLWEntry parses a single lightweight ACL +func ParseLWEntry(singleSysACL string) (*Entry, error) { + if !strings.HasPrefix(singleSysACL, TypeLightweight+":") { + return nil, errInvalidACL + } + singleSysACL = strings.TrimPrefix(singleSysACL, TypeLightweight+":") + + tokens := strings.Split(singleSysACL, "=") + if len(tokens) != 2 { + return nil, errInvalidACL + } + return &Entry{ + Type: TypeLightweight, + Qualifier: tokens[0], + Permissions: tokens[1], + }, nil +} + // CitrineSerialize serializes an ACL entry for citrine EOS ACLs func (a *Entry) CitrineSerialize() string { return fmt.Sprintf("%s:%s=%s", a.Type, a.Qualifier, a.Permissions) diff --git a/pkg/storage/utils/eosfs/eosfs.go b/pkg/storage/utils/eosfs/eosfs.go index 8fc6dafd1fc..33fd5d46aa4 100644 --- a/pkg/storage/utils/eosfs/eosfs.go +++ b/pkg/storage/utils/eosfs/eosfs.go @@ -811,7 +811,18 @@ func (fs *eosfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []st if err != nil { return nil, err } - auth, err := fs.getUserAuth(ctx, u, "") + + fn := "" + if u.Id.Type == userpb.UserType_USER_TYPE_LIGHTWEIGHT { + p, err := fs.resolve(ctx, ref) + if err != nil { + return nil, errors.Wrap(err, "eosfs: error resolving reference") + } + + fn = fs.wrap(ctx, p) + } + + auth, err := fs.getUserAuth(ctx, u, fn) if err != nil { return nil, err } @@ -838,7 +849,7 @@ func (fs *eosfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []st } } - fn := fs.wrap(ctx, p) + fn = fs.wrap(ctx, p) eosFileInfo, err := fs.c.GetFileInfoByPath(ctx, auth, fn) if err != nil { return nil, err