From 21e154ff659799311c233f2fe0bee1825cdb3499 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Fri, 9 Jul 2021 08:09:44 +0200 Subject: [PATCH] add readonly interceptor (#1849) --- .../read-only-storageprovider-interceptor.md | 5 + internal/grpc/interceptors/loader/loader.go | 6 +- .../grpc/interceptors/readonly/readonly.go | 146 ++++++++++++++++++ internal/http/services/owncloud/ocdav/copy.go | 64 +++++++- .../http/services/owncloud/ocdav/delete.go | 27 ++++ .../http/services/owncloud/ocdav/error.go | 23 ++- .../http/services/owncloud/ocdav/mkcol.go | 9 ++ internal/http/services/owncloud/ocdav/move.go | 19 +++ .../http/services/owncloud/ocdav/proppatch.go | 35 +++++ internal/http/services/owncloud/ocdav/put.go | 19 ++- .../expected-failures-on-OCIS-storage.md | 10 -- .../expected-failures-on-OWNCLOUD-storage.md | 11 -- .../expected-failures-on-S3NG-storage.md | 10 -- 13 files changed, 335 insertions(+), 49 deletions(-) create mode 100644 changelog/unreleased/read-only-storageprovider-interceptor.md create mode 100644 internal/grpc/interceptors/readonly/readonly.go diff --git a/changelog/unreleased/read-only-storageprovider-interceptor.md b/changelog/unreleased/read-only-storageprovider-interceptor.md new file mode 100644 index 0000000000..bd728f7ac3 --- /dev/null +++ b/changelog/unreleased/read-only-storageprovider-interceptor.md @@ -0,0 +1,5 @@ +Enhancement: Add readonly interceptor + +The readonly interceptor could be used to configure a storageprovider in readonly mode. This could be handy in some migration scenarios. + +https://github.com/cs3org/reva/pull/1849 diff --git a/internal/grpc/interceptors/loader/loader.go b/internal/grpc/interceptors/loader/loader.go index b739eab64e..c5f252e397 100644 --- a/internal/grpc/interceptors/loader/loader.go +++ b/internal/grpc/interceptors/loader/loader.go @@ -18,4 +18,8 @@ package loader -// Add your own. +import ( + // Load core GRPC services + _ "github.com/cs3org/reva/internal/grpc/interceptors/readonly" + // Add your own service here +) diff --git a/internal/grpc/interceptors/readonly/readonly.go b/internal/grpc/interceptors/readonly/readonly.go new file mode 100644 index 0000000000..f82a7ab46b --- /dev/null +++ b/internal/grpc/interceptors/readonly/readonly.go @@ -0,0 +1,146 @@ +// Copyright 2018-2021 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package readonly + +import ( + "context" + + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1" + "github.com/cs3org/reva/pkg/appctx" + "github.com/cs3org/reva/pkg/rgrpc" + rstatus "github.com/cs3org/reva/pkg/rgrpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const ( + defaultPriority = 200 +) + +func init() { + rgrpc.RegisterUnaryInterceptor("readonly", NewUnary) +} + +// NewUnary returns a new unary interceptor +// that checks grpc calls and blocks write requests. +func NewUnary(map[string]interface{}) (grpc.UnaryServerInterceptor, int, error) { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + log := appctx.GetLogger(ctx) + + switch req.(type) { + // handle known non-write request types + case *provider.GetHomeRequest, + *provider.GetPathRequest, + *provider.GetQuotaRequest, + *registry.GetStorageProvidersRequest, + *provider.InitiateFileDownloadRequest, + *provider.ListFileVersionsRequest, + *provider.ListGrantsRequest, + *provider.ListRecycleRequest: + return handler(ctx, req) + case *provider.ListContainerRequest: + resp, err := handler(ctx, req) + if listResp, ok := resp.(*provider.ListContainerResponse); ok && listResp.Infos != nil { + for _, info := range listResp.Infos { + // use the existing PermissionsSet and change the writes to false + if info.PermissionSet != nil { + info.PermissionSet.AddGrant = false + info.PermissionSet.CreateContainer = false + info.PermissionSet.Delete = false + info.PermissionSet.InitiateFileUpload = false + info.PermissionSet.Move = false + info.PermissionSet.RemoveGrant = false + info.PermissionSet.PurgeRecycle = false + info.PermissionSet.RestoreFileVersion = false + info.PermissionSet.RestoreRecycleItem = false + info.PermissionSet.UpdateGrant = false + } + } + } + return resp, err + case *provider.StatRequest: + resp, err := handler(ctx, req) + if statResp, ok := resp.(*provider.StatResponse); ok && statResp.Info != nil && statResp.Info.PermissionSet != nil { + // use the existing PermissionsSet and change the writes to false + statResp.Info.PermissionSet.AddGrant = false + statResp.Info.PermissionSet.CreateContainer = false + statResp.Info.PermissionSet.Delete = false + statResp.Info.PermissionSet.InitiateFileUpload = false + statResp.Info.PermissionSet.Move = false + statResp.Info.PermissionSet.RemoveGrant = false + statResp.Info.PermissionSet.PurgeRecycle = false + statResp.Info.PermissionSet.RestoreFileVersion = false + statResp.Info.PermissionSet.RestoreRecycleItem = false + statResp.Info.PermissionSet.UpdateGrant = false + } + return resp, err + // Don't allow the following requests types + case *provider.AddGrantRequest: + return &provider.AddGrantResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to add grant on readonly storage"), + }, nil + case *provider.CreateContainerRequest: + return &provider.CreateContainerResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to create resoure on readonly storage"), + }, nil + case *provider.CreateHomeRequest: + return &provider.CreateHomeResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to create home on readonly storage"), + }, nil + case *provider.DeleteRequest: + return &provider.DeleteResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to delete resource on readonly storage"), + }, nil + case *provider.InitiateFileUploadRequest: + return &provider.InitiateFileUploadResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to upload resource on readonly storage"), + }, nil + case *provider.MoveRequest: + return &provider.MoveResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to move resource on readonly storage"), + }, nil + case *provider.PurgeRecycleRequest: + return &provider.PurgeRecycleResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to purge recycle on readonly storage"), + }, nil + case *provider.RemoveGrantRequest: + return &provider.RemoveGrantResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to remove grant on readonly storage"), + }, nil + case *provider.RestoreRecycleItemRequest: + return &provider.RestoreRecycleItemResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to restore recycle item on readonly storage"), + }, nil + case *provider.SetArbitraryMetadataRequest: + return &provider.SetArbitraryMetadataResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to set arbitrary metadata on readonly storage"), + }, nil + case *provider.UnsetArbitraryMetadataRequest: + return &provider.UnsetArbitraryMetadataResponse{ + Status: rstatus.NewPermissionDenied(ctx, nil, "permission denied: tried to unset arbitrary metadata on readonly storage"), + }, nil + // block unknown request types and return error + default: + log.Debug().Msg("storage is readonly") + return nil, status.Errorf(codes.PermissionDenied, "permission denied: tried to execute an unknown operation: %T!", req) + } + }, defaultPriority, nil +} diff --git a/internal/http/services/owncloud/ocdav/copy.go b/internal/http/services/owncloud/ocdav/copy.go index a3cbee49ec..67c1455fc3 100644 --- a/internal/http/services/owncloud/ocdav/copy.go +++ b/internal/http/services/owncloud/ocdav/copy.go @@ -65,11 +65,23 @@ func (s *svc) handleCopy(w http.ResponseWriter, r *http.Request, ns string) { if overwrite != "T" && overwrite != "F" { w.WriteHeader(http.StatusBadRequest) + m := fmt.Sprintf("Overwrite header is set to incorrect value %v", overwrite) + b, err := Marshal(exception{ + code: SabredavBadRequest, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) return } if depth != "infinity" && depth != "0" { w.WriteHeader(http.StatusBadRequest) + m := fmt.Sprintf("Depth header is set to incorrect value %v", depth) + b, err := Marshal(exception{ + code: SabredavBadRequest, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) return } @@ -91,6 +103,15 @@ func (s *svc) handleCopy(w http.ResponseWriter, r *http.Request, ns string) { } if srcStatRes.Status.Code != rpc.Code_CODE_OK { + if srcStatRes.Status.Code == rpc.Code_CODE_NOT_FOUND { + w.WriteHeader(http.StatusNotFound) + m := fmt.Sprintf("Resource %v not found", srcStatReq.Ref.Path) + b, err := Marshal(exception{ + code: SabredavNotFound, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) + } HandleErrorStatus(&sublog, w, srcStatRes.Status) return } @@ -115,7 +136,13 @@ func (s *svc) handleCopy(w http.ResponseWriter, r *http.Request, ns string) { if overwrite == "F" { sublog.Warn().Str("overwrite", overwrite).Msg("dst already exists") - w.WriteHeader(http.StatusPreconditionFailed) // 412, see https://tools.ietf.org/html/rfc4918#section-9.8.5 + w.WriteHeader(http.StatusPreconditionFailed) + m := fmt.Sprintf("Could not overwrite Resource %v", dst) + b, err := Marshal(exception{ + code: SabredavPreconditionFailed, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) // 412, see https://tools.ietf.org/html/rfc4918#section-9.8.5 return } @@ -143,7 +170,7 @@ func (s *svc) handleCopy(w http.ResponseWriter, r *http.Request, ns string) { // TODO what if intermediate is a file? } - err = s.descend(ctx, client, srcStatRes.Info, dst, depth == "infinity") + err = s.descend(ctx, w, client, srcStatRes.Info, dst, depth == "infinity") if err != nil { sublog.Error().Err(err).Str("depth", depth).Msg("error descending directory") w.WriteHeader(http.StatusInternalServerError) @@ -152,7 +179,7 @@ func (s *svc) handleCopy(w http.ResponseWriter, r *http.Request, ns string) { w.WriteHeader(successCode) } -func (s *svc) descend(ctx context.Context, client gateway.GatewayAPIClient, src *provider.ResourceInfo, dst string, recurse bool) error { +func (s *svc) descend(ctx context.Context, w http.ResponseWriter, client gateway.GatewayAPIClient, src *provider.ResourceInfo, dst string, recurse bool) error { log := appctx.GetLogger(ctx) log.Debug().Str("src", src.Path).Str("dst", dst).Msg("descending") if src.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER { @@ -161,10 +188,25 @@ func (s *svc) descend(ctx context.Context, client gateway.GatewayAPIClient, src Ref: &provider.Reference{Path: dst}, } createRes, err := client.CreateContainer(ctx, createReq) - if err != nil || createRes.Status.Code != rpc.Code_CODE_OK { + if err != nil { + log.Error().Err(err).Msg("error performing create container grpc request") + w.WriteHeader(http.StatusInternalServerError) return err } + if createRes.Status.Code != rpc.Code_CODE_OK { + if createRes.Status.Code == rpc.Code_CODE_PERMISSION_DENIED { + w.WriteHeader(http.StatusForbidden) + m := fmt.Sprintf("Permission denied to create %v", createReq.Ref.Path) + b, err := Marshal(exception{ + code: SabredavPermissionDenied, + message: m, + }) + HandleWebdavError(log, w, b, err) + } + return nil + } + // TODO: also copy properties: https://tools.ietf.org/html/rfc4918#section-9.8.2 if !recurse { @@ -185,7 +227,7 @@ func (s *svc) descend(ctx context.Context, client gateway.GatewayAPIClient, src for i := range res.Infos { childDst := path.Join(dst, path.Base(res.Infos[i].Path)) - err := s.descend(ctx, client, res.Infos[i], childDst, recurse) + err := s.descend(ctx, w, client, res.Infos[i], childDst, recurse) if err != nil { return err } @@ -237,7 +279,17 @@ func (s *svc) descend(ctx context.Context, client gateway.GatewayAPIClient, src } if uRes.Status.Code != rpc.Code_CODE_OK { - return fmt.Errorf("status code %d", uRes.Status.Code) + if uRes.Status.Code == rpc.Code_CODE_PERMISSION_DENIED { + w.WriteHeader(http.StatusForbidden) + m := fmt.Sprintf("Permission denied to create %v", uReq.Ref.Path) + b, err := Marshal(exception{ + code: SabredavPermissionDenied, + message: m, + }) + HandleWebdavError(log, w, b, err) + } + HandleErrorStatus(log, w, uRes.Status) + return nil } var uploadEP, uploadToken string diff --git a/internal/http/services/owncloud/ocdav/delete.go b/internal/http/services/owncloud/ocdav/delete.go index 8898a95d1a..29ff9de84d 100644 --- a/internal/http/services/owncloud/ocdav/delete.go +++ b/internal/http/services/owncloud/ocdav/delete.go @@ -19,6 +19,7 @@ package ocdav import ( + "fmt" "net/http" "path" @@ -54,6 +55,32 @@ func (s *svc) handleDelete(w http.ResponseWriter, r *http.Request, ns string) { } if res.Status.Code != rpc.Code_CODE_OK { + if res.Status.Code == rpc.Code_CODE_NOT_FOUND { + w.WriteHeader(http.StatusNotFound) + m := fmt.Sprintf("Resource %v not found", fn) + b, err := Marshal(exception{ + code: SabredavNotFound, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) + } + if res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED { + w.WriteHeader(http.StatusForbidden) + m := fmt.Sprintf("Permission denied to delete %v", fn) + b, err := Marshal(exception{ + code: SabredavPermissionDenied, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) + } + if res.Status.Code == rpc.Code_CODE_INTERNAL && res.Status.Message == "can't delete mount path" { + w.WriteHeader(http.StatusForbidden) + b, err := Marshal(exception{ + code: SabredavPermissionDenied, + message: res.Status.Message, + }) + HandleWebdavError(&sublog, w, b, err) + } HandleErrorStatus(&sublog, w, res.Status) return } diff --git a/internal/http/services/owncloud/ocdav/error.go b/internal/http/services/owncloud/ocdav/error.go index db1ada8446..725be4fb1e 100644 --- a/internal/http/services/owncloud/ocdav/error.go +++ b/internal/http/services/owncloud/ocdav/error.go @@ -39,6 +39,10 @@ const ( SabredavNotAuthenticated // SabredavPreconditionFailed maps to HTTP 412 SabredavPreconditionFailed + // SabredavPermissionDenied maps to HTTP 403 + SabredavPermissionDenied + // SabredavNotFound maps to HTTP 404 + SabredavNotFound ) var ( @@ -47,6 +51,8 @@ var ( "Sabre\\DAV\\Exception\\MethodNotAllowed", "Sabre\\DAV\\Exception\\NotAuthenticated", "Sabre\\DAV\\Exception\\PreconditionFailed", + "Sabre\\DAV\\Exception\\PermissionDenied", + "Sabre\\DAV\\Exception\\NotFound", } ) @@ -79,7 +85,8 @@ type errorXML struct { Exception string `xml:"s:exception"` Message string `xml:"s:message"` InnerXML []byte `xml:",innerxml"` - Header string `xml:"s:header"` + // Header is used to indicate the conflicting request header + Header string `xml:"s:header,omitempty"` } var errInvalidPropfind = errors.New("webdav: invalid propfind") @@ -111,3 +118,17 @@ func HandleErrorStatus(log *zerolog.Logger, w http.ResponseWriter, s *rpc.Status w.WriteHeader(http.StatusInternalServerError) } } + +// HandleWebdavError checks the status code, logs an error and creates a webdav response body +// if needed +func HandleWebdavError(log *zerolog.Logger, w http.ResponseWriter, b []byte, err error) { + if err != nil { + log.Error().Msgf("error marshaling xml response: %s", b) + w.WriteHeader(http.StatusInternalServerError) + return + } + _, err = w.Write(b) + if err != nil { + log.Err(err).Msg("error writing response") + } +} diff --git a/internal/http/services/owncloud/ocdav/mkcol.go b/internal/http/services/owncloud/ocdav/mkcol.go index 889598a43b..573da3b26f 100644 --- a/internal/http/services/owncloud/ocdav/mkcol.go +++ b/internal/http/services/owncloud/ocdav/mkcol.go @@ -19,6 +19,7 @@ package ocdav import ( + "fmt" "io" "net/http" "path" @@ -85,6 +86,14 @@ func (s *svc) handleMkcol(w http.ResponseWriter, r *http.Request, ns string) { case rpc.Code_CODE_NOT_FOUND: sublog.Debug().Str("path", fn).Interface("status", statRes.Status).Msg("conflict") w.WriteHeader(http.StatusConflict) + case rpc.Code_CODE_PERMISSION_DENIED: + w.WriteHeader(http.StatusForbidden) + m := fmt.Sprintf("Permission denied to create %v", fn) + b, err := Marshal(exception{ + code: SabredavPermissionDenied, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) default: HandleErrorStatus(&sublog, w, res.Status) } diff --git a/internal/http/services/owncloud/ocdav/move.go b/internal/http/services/owncloud/ocdav/move.go index e92bc1bede..0cb677dfc7 100644 --- a/internal/http/services/owncloud/ocdav/move.go +++ b/internal/http/services/owncloud/ocdav/move.go @@ -19,6 +19,7 @@ package ocdav import ( + "fmt" "net/http" "path" "strings" @@ -76,6 +77,15 @@ func (s *svc) handleMove(w http.ResponseWriter, r *http.Request, ns string) { return } if srcStatRes.Status.Code != rpc.Code_CODE_OK { + if srcStatRes.Status.Code == rpc.Code_CODE_NOT_FOUND { + w.WriteHeader(http.StatusNotFound) + m := fmt.Sprintf("Resource %v not found", srcStatReq.Ref.Path) + b, err := Marshal(exception{ + code: SabredavNotFound, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) + } HandleErrorStatus(&sublog, w, srcStatRes.Status) return } @@ -152,6 +162,15 @@ func (s *svc) handleMove(w http.ResponseWriter, r *http.Request, ns string) { } if mRes.Status.Code != rpc.Code_CODE_OK { + if mRes.Status.Code == rpc.Code_CODE_PERMISSION_DENIED { + w.WriteHeader(http.StatusForbidden) + m := fmt.Sprintf("Permission denied to move %v", sourceRef.Path) + b, err := Marshal(exception{ + code: SabredavPermissionDenied, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) + } HandleErrorStatus(&sublog, w, mRes.Status) return } diff --git a/internal/http/services/owncloud/ocdav/proppatch.go b/internal/http/services/owncloud/ocdav/proppatch.go index f7dd927743..0123aa7634 100644 --- a/internal/http/services/owncloud/ocdav/proppatch.go +++ b/internal/http/services/owncloud/ocdav/proppatch.go @@ -51,6 +51,12 @@ func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string) if err != nil { sublog.Debug().Err(err).Msg("error reading proppatch") w.WriteHeader(status) + m := fmt.Sprintf("Error reading proppatch: %v", err) + b, err := Marshal(exception{ + code: SabredavBadRequest, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) return } @@ -73,6 +79,15 @@ func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string) } if statRes.Status.Code != rpc.Code_CODE_OK { + if statRes.Status.Code == rpc.Code_CODE_NOT_FOUND { + w.WriteHeader(http.StatusNotFound) + m := fmt.Sprintf("Resource %v not found", fn) + b, err := Marshal(exception{ + code: SabredavNotFound, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) + } HandleErrorStatus(&sublog, w, statRes.Status) return } @@ -119,6 +134,16 @@ func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string) } if res.Status.Code != rpc.Code_CODE_OK { + if res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED { + w.WriteHeader(http.StatusForbidden) + m := fmt.Sprintf("Permission denied to remove properties on resource %v", fn) + b, err := Marshal(exception{ + code: SabredavPermissionDenied, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) + return + } HandleErrorStatus(&sublog, w, res.Status) return } @@ -133,6 +158,16 @@ func (s *svc) handleProppatch(w http.ResponseWriter, r *http.Request, ns string) } if res.Status.Code != rpc.Code_CODE_OK { + if res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED { + w.WriteHeader(http.StatusForbidden) + m := fmt.Sprintf("Permission denied to set properties on resource %v", fn) + b, err := Marshal(exception{ + code: SabredavPermissionDenied, + message: m, + }) + HandleWebdavError(&sublog, w, b, err) + return + } HandleErrorStatus(&sublog, w, res.Status) return } diff --git a/internal/http/services/owncloud/ocdav/put.go b/internal/http/services/owncloud/ocdav/put.go index 18706b4519..f767adfa8e 100644 --- a/internal/http/services/owncloud/ocdav/put.go +++ b/internal/http/services/owncloud/ocdav/put.go @@ -248,6 +248,14 @@ func (s *svc) handlePutHelper(w http.ResponseWriter, r *http.Request, content io } if uRes.Status.Code != rpc.Code_CODE_OK { + if uRes.Status.Code == rpc.Code_CODE_PERMISSION_DENIED { + w.WriteHeader(http.StatusForbidden) + b, err := Marshal(exception{ + code: SabredavPermissionDenied, + message: "permission denied: you have no permission to upload content", + }) + HandleWebdavError(&sublog, w, b, err) + } HandleErrorStatus(&sublog, w, uRes.Status) return } @@ -285,16 +293,7 @@ func (s *svc) handlePutHelper(w http.ResponseWriter, r *http.Request, content io code: SabredavBadRequest, message: "The computed checksum does not match the one received from the client.", }) - if err != nil { - sublog.Error().Msgf("error marshaling xml response: %s", b) - w.WriteHeader(http.StatusInternalServerError) - return - } - _, err = w.Write(b) - if err != nil { - sublog.Err(err).Msg("error writing response") - } - return + HandleWebdavError(&sublog, w, b, err) } sublog.Error().Err(err).Msg("PUT request to data server failed") w.WriteHeader(httpRes.StatusCode) diff --git a/tests/acceptance/expected-failures-on-OCIS-storage.md b/tests/acceptance/expected-failures-on-OCIS-storage.md index b0cbbc33f8..0e51a30a78 100644 --- a/tests/acceptance/expected-failures-on-OCIS-storage.md +++ b/tests/acceptance/expected-failures-on-OCIS-storage.md @@ -953,14 +953,6 @@ _requires a [CS3 user provisioning api that can update the quota for a user](htt #### [remote.php/dav/uploads endpoint does not exist](https://github.com/owncloud/ocis/issues/1321) - [apiShareOperationsToShares2/uploadToShare.feature:256](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/uploadToShare.feature#L256) -#### Copying into a shared folder -Scenario Outline: Copying a file to a folder with no permissions -- [apiWebdavProperties1/copyFile.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L68) -- [apiWebdavProperties1/copyFile.feature:69](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L69) -Scenario Outline: Copying a file to overwrite a file into a folder with no permissions -- [apiWebdavProperties1/copyFile.feature:90](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L90) -- [apiWebdavProperties1/copyFile.feature:91](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L91) - #### Share jail related Scenario Outline: delete a folder when there is a default folder for received shares - [apiWebdavOperations/deleteFolder.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavOperations/deleteFolder.feature#L67) @@ -1932,8 +1924,6 @@ _ocs: api compatibility, return correct status code_ - [apiShareManagementBasicToShares/createShareToSharesFolder.feature:445](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L445) #### [Trying to copy a file into a readonly share gives HTTP 500 error](https://github.com/owncloud/ocis/issues/2166) -- [apiWebdavProperties1/copyFile.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L68) -- [apiWebdavProperties1/copyFile.feature:69](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L69) - [apiWebdavProperties1/copyFile.feature:362](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L362) - [apiWebdavProperties1/copyFile.feature:363](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L363) - [apiWebdavProperties1/copyFile.feature:383](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L483) diff --git a/tests/acceptance/expected-failures-on-OWNCLOUD-storage.md b/tests/acceptance/expected-failures-on-OWNCLOUD-storage.md index 33feee13b8..376b19e1f1 100644 --- a/tests/acceptance/expected-failures-on-OWNCLOUD-storage.md +++ b/tests/acceptance/expected-failures-on-OWNCLOUD-storage.md @@ -1081,15 +1081,6 @@ The following scenarios fail on OWNCLOUD storage but not on OCIS storage: #### [remote.php/dav/uploads endpoint does not exist](https://github.com/owncloud/ocis/issues/1321) - [apiShareOperationsToShares2/uploadToShare.feature:256](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/uploadToShare.feature#L256) -#### Copying into a shared folder -Scenario Outline: Copying a file to a folder with no permissions -- [apiWebdavProperties1/copyFile.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L68) -- [apiWebdavProperties1/copyFile.feature:69](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L69) -Scenario Outline: Copying a file to overwrite a file into a folder with no permissions -- [apiWebdavProperties1/copyFile.feature:90](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L90) -- [apiWebdavProperties1/copyFile.feature:91](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L91) - - #### Share jail related Scenario Outline: delete a folder when there is a default folder for received shares - [apiWebdavOperations/deleteFolder.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavOperations/deleteFolder.feature#L67) @@ -2070,8 +2061,6 @@ _ocs: api compatibility, return correct status code_ - [apiShareManagementBasicToShares/createShareToSharesFolder.feature:445](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L445) #### [Trying to copy a file into a readonly share gives HTTP 500 error](https://github.com/owncloud/ocis/issues/2166) -- [apiWebdavProperties1/copyFile.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L68) -- [apiWebdavProperties1/copyFile.feature:69](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L69) - [apiWebdavProperties1/copyFile.feature:362](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L362) - [apiWebdavProperties1/copyFile.feature:363](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L363) - [apiWebdavProperties1/copyFile.feature:383](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L483) diff --git a/tests/acceptance/expected-failures-on-S3NG-storage.md b/tests/acceptance/expected-failures-on-S3NG-storage.md index ed19eecec6..068f15206c 100644 --- a/tests/acceptance/expected-failures-on-S3NG-storage.md +++ b/tests/acceptance/expected-failures-on-S3NG-storage.md @@ -945,14 +945,6 @@ _requires a [CS3 user provisioning api that can update the quota for a user](htt #### [remote.php/dav/uploads endpoint does not exist](https://github.com/owncloud/ocis/issues/1321) - [apiShareOperationsToShares2/uploadToShare.feature:256](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/uploadToShare.feature#L256) -#### Copying into a shared folder -Scenario Outline: Copying a file to a folder with no permissions -- [apiWebdavProperties1/copyFile.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L68) -- [apiWebdavProperties1/copyFile.feature:69](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L69) -Scenario Outline: Copying a file to overwrite a file into a folder with no permissions -- [apiWebdavProperties1/copyFile.feature:90](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L90) -- [apiWebdavProperties1/copyFile.feature:91](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L91) - #### Share jail related Scenario Outline: delete a folder when there is a default folder for received shares - [apiWebdavOperations/deleteFolder.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavOperations/deleteFolder.feature#L67) @@ -1935,8 +1927,6 @@ _ocs: api compatibility, return correct status code_ - [apiShareManagementBasicToShares/createShareToSharesFolder.feature:445](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L445) #### [Trying to copy a file into a readonly share gives HTTP 500 error](https://github.com/owncloud/ocis/issues/2166) -- [apiWebdavProperties1/copyFile.feature:68](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L68) -- [apiWebdavProperties1/copyFile.feature:69](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L69) - [apiWebdavProperties1/copyFile.feature:362](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L362) - [apiWebdavProperties1/copyFile.feature:363](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L363) - [apiWebdavProperties1/copyFile.feature:383](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L483)