From a5f1195341b9cb5bfcea05a2cc937901c11a1604 Mon Sep 17 00:00:00 2001 From: Roman Perekhod <2403905@gmail.com> Date: Thu, 16 Nov 2023 14:55:02 +0100 Subject: [PATCH] [full-ci] disable DEPTH infinity in PROPFIND (#4278) * disable DEPTH infinity in PROPFIND * [full-ci] use ocis * [full-ci use ocis master] --------- Co-authored-by: Roman Perekhod --- .../unreleased/disable-depth-infinity.md | 9 ++++ .../owncloud/ocdav/propfind/propfind.go | 43 +++++++++++++------ .../owncloud/ocdav/propfind/propfind_test.go | 22 +--------- .../services/owncloud/ocdav/publicfile.go | 24 ++++++++++- .../http/services/owncloud/ocdav/trashbin.go | 26 ++++++++++- 5 files changed, 87 insertions(+), 37 deletions(-) create mode 100644 changelog/unreleased/disable-depth-infinity.md diff --git a/changelog/unreleased/disable-depth-infinity.md b/changelog/unreleased/disable-depth-infinity.md new file mode 100644 index 0000000000..6ee97bc598 --- /dev/null +++ b/changelog/unreleased/disable-depth-infinity.md @@ -0,0 +1,9 @@ +Bugfix: Disable DEPTH infinity in PROPFIND + +Disabled DEPTH infinity in PROPFIND for +Personal /remote.php/dav/files/admin +Public link share /remote.php/dav/public-files/ +Trashbin /remote.php/dav/spaces/trash-bin/ + +https://github.com/cs3org/reva/pull/4278 +https://github.com/owncloud/ocis/issues/7359 diff --git a/internal/http/services/owncloud/ocdav/propfind/propfind.go b/internal/http/services/owncloud/ocdav/propfind/propfind.go index 0aa094f324..648ded6210 100644 --- a/internal/http/services/owncloud/ocdav/propfind/propfind.go +++ b/internal/http/services/owncloud/ocdav/propfind/propfind.go @@ -190,6 +190,33 @@ func (p *Handler) HandlePathPropfind(w http.ResponseWriter, r *http.Request, ns fn := path.Join(ns, r.URL.Path) // TODO do we still need to jail if we query the registry about the spaces? sublog := appctx.GetLogger(ctx).With().Str("path", fn).Logger() + dh := r.Header.Get(net.HeaderDepth) + + depth, err := net.ParseDepth(dh) + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "Invalid Depth header value") + span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest)) + sublog.Debug().Str("depth", dh).Msg(err.Error()) + w.WriteHeader(http.StatusBadRequest) + m := fmt.Sprintf("Invalid Depth header value: %v", dh) + b, err := errors.Marshal(http.StatusBadRequest, m, "") + errors.HandleWebdavError(&sublog, w, b, err) + return + } + + if depth == net.DepthInfinity && !p.c.AllowPropfindDepthInfinitiy { + span.RecordError(errors.ErrInvalidDepth) + span.SetStatus(codes.Error, "DEPTH: infinity is not supported") + span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest)) + sublog.Debug().Str("depth", dh).Msg(errors.ErrInvalidDepth.Error()) + w.WriteHeader(http.StatusBadRequest) + m := fmt.Sprintf("Invalid Depth header value: %v", dh) + b, err := errors.Marshal(http.StatusBadRequest, m, "") + errors.HandleWebdavError(&sublog, w, b, err) + return + } + pf, status, err := ReadPropfind(r.Body) if err != nil { sublog.Debug().Err(err).Msg("error reading propfind request") @@ -218,7 +245,7 @@ func (p *Handler) HandlePathPropfind(w http.ResponseWriter, r *http.Request, ns return } - resourceInfos, sendTusHeaders, ok := p.getResourceInfos(ctx, w, r, pf, spaces, fn, sublog) + resourceInfos, sendTusHeaders, ok := p.getResourceInfos(ctx, w, r, pf, spaces, fn, depth, sublog) if !ok { // getResourceInfos handles responses in case of an error so we can just return here. return @@ -462,21 +489,11 @@ func (p *Handler) statSpace(ctx context.Context, client gateway.GatewayAPIClient return res.GetInfo(), res.GetStatus(), nil } -func (p *Handler) getResourceInfos(ctx context.Context, w http.ResponseWriter, r *http.Request, pf XML, spaces []*provider.StorageSpace, requestPath string, log zerolog.Logger) ([]*provider.ResourceInfo, bool, bool) { +func (p *Handler) getResourceInfos(ctx context.Context, w http.ResponseWriter, r *http.Request, pf XML, spaces []*provider.StorageSpace, requestPath string, depth net.Depth, log zerolog.Logger) ([]*provider.ResourceInfo, bool, bool) { ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "get_resource_infos") span.SetAttributes(attribute.KeyValue{Key: "requestPath", Value: attribute.StringValue(requestPath)}) - defer span.End() - - dh := r.Header.Get(net.HeaderDepth) - depth, err := net.ParseDepth(dh) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - m := fmt.Sprintf("Invalid Depth header value: %v", dh) - b, err := errors.Marshal(http.StatusBadRequest, m, "") - errors.HandleWebdavError(&log, w, b, err) - return nil, false, false - } span.SetAttributes(attribute.KeyValue{Key: "depth", Value: attribute.StringValue(depth.String())}) + defer span.End() client, err := p.selector.Next() if err != nil { diff --git a/internal/http/services/owncloud/ocdav/propfind/propfind_test.go b/internal/http/services/owncloud/ocdav/propfind/propfind_test.go index a895273338..07692245f0 100644 --- a/internal/http/services/owncloud/ocdav/propfind/propfind_test.go +++ b/internal/http/services/owncloud/ocdav/propfind/propfind_test.go @@ -1460,27 +1460,7 @@ var _ = Describe("PropfindWithoutDepthInfinity", func() { req.Header.Add(net.HeaderDepth, "infinity") handler.HandlePathPropfind(rr, req, "/") - Expect(rr.Code).To(Equal(http.StatusMultiStatus)) - - res, _, err := readResponse(rr.Result().Body) - Expect(err).ToNot(HaveOccurred()) - Expect(len(res.Responses)).To(Equal(9)) - - paths := []string{} - for _, r := range res.Responses { - paths = append(paths, r.Href) - } - Expect(paths).To(ConsistOf( - "http:/127.0.0.1:3000/foo/", - "http:/127.0.0.1:3000/foo/bar", - "http:/127.0.0.1:3000/foo/baz", - "http:/127.0.0.1:3000/foo/dir/", - "http:/127.0.0.1:3000/foo/dir/entry", - "http:/127.0.0.1:3000/foo/Shares/sharedFile", - "http:/127.0.0.1:3000/foo/Shares/sharedFile2", - "http:/127.0.0.1:3000/foo/Shares/sharedDir/", - "http:/127.0.0.1:3000/foo/Shares/sharedDir/something", - )) + Expect(rr.Code).To(Equal(http.StatusBadRequest)) }) }) diff --git a/internal/http/services/owncloud/ocdav/publicfile.go b/internal/http/services/owncloud/ocdav/publicfile.go index 7b918268cd..31c92616b2 100644 --- a/internal/http/services/owncloud/ocdav/publicfile.go +++ b/internal/http/services/owncloud/ocdav/publicfile.go @@ -20,15 +20,19 @@ package ocdav import ( "context" + "fmt" "net/http" "path" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind" "github.com/cs3org/reva/v2/pkg/appctx" "github.com/cs3org/reva/v2/pkg/rhttp/router" + "go.opentelemetry.io/otel/codes" + semconv "go.opentelemetry.io/otel/semconv/v1.20.0" ) // PublicFileHandler handles requests on a shared file. it needs to be wrapped in a collection @@ -99,8 +103,26 @@ func (s *svc) handlePropfindOnToken(w http.ResponseWriter, r *http.Request, ns s dh := r.Header.Get(net.HeaderDepth) depth, err := net.ParseDepth(dh) if err != nil { - sublog.Debug().Msg(err.Error()) + span.RecordError(err) + span.SetStatus(codes.Error, "Invalid Depth header value") + span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest)) + sublog.Debug().Str("depth", dh).Msg(err.Error()) w.WriteHeader(http.StatusBadRequest) + m := fmt.Sprintf("Invalid Depth header value: %v", dh) + b, err := errors.Marshal(http.StatusBadRequest, m, "") + errors.HandleWebdavError(&sublog, w, b, err) + return + } + + if depth == net.DepthInfinity && !s.c.AllowPropfindDepthInfinitiy { + span.RecordError(errors.ErrInvalidDepth) + span.SetStatus(codes.Error, "DEPTH: infinity is not supported") + span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest)) + sublog.Debug().Str("depth", dh).Msg(errors.ErrInvalidDepth.Error()) + w.WriteHeader(http.StatusBadRequest) + m := fmt.Sprintf("Invalid Depth header value: %v", dh) + b, err := errors.Marshal(http.StatusBadRequest, m, "") + errors.HandleWebdavError(&sublog, w, b, err) return } diff --git a/internal/http/services/owncloud/ocdav/trashbin.go b/internal/http/services/owncloud/ocdav/trashbin.go index 6e7f19aef1..51205a3a05 100644 --- a/internal/http/services/owncloud/ocdav/trashbin.go +++ b/internal/http/services/owncloud/ocdav/trashbin.go @@ -36,6 +36,7 @@ import ( "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/spacelookup" "github.com/cs3org/reva/v2/pkg/storagespace" + "go.opentelemetry.io/otel/codes" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" @@ -44,17 +45,20 @@ import ( rstatus "github.com/cs3org/reva/v2/pkg/rgrpc/status" "github.com/cs3org/reva/v2/pkg/rhttp/router" "github.com/cs3org/reva/v2/pkg/utils" + semconv "go.opentelemetry.io/otel/semconv/v1.20.0" ) // TrashbinHandler handles trashbin requests type TrashbinHandler struct { - gatewaySvc string - namespace string + gatewaySvc string + namespace string + allowPropfindDepthInfinitiy bool } func (h *TrashbinHandler) init(c *config.Config) error { h.gatewaySvc = c.GatewaySvc h.namespace = path.Join("/", c.FilesNamespace) + h.allowPropfindDepthInfinitiy = c.AllowPropfindDepthInfinitiy return nil } @@ -186,8 +190,26 @@ func (h *TrashbinHandler) listTrashbin(w http.ResponseWriter, r *http.Request, s dh := r.Header.Get(net.HeaderDepth) depth, err := net.ParseDepth(dh) if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "Invalid Depth header value") + span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest)) sublog.Debug().Str("depth", dh).Msg(err.Error()) w.WriteHeader(http.StatusBadRequest) + m := fmt.Sprintf("Invalid Depth header value: %v", dh) + b, err := errors.Marshal(http.StatusBadRequest, m, "") + errors.HandleWebdavError(&sublog, w, b, err) + return + } + + if depth == net.DepthInfinity && !h.allowPropfindDepthInfinitiy { + span.RecordError(errors.ErrInvalidDepth) + span.SetStatus(codes.Error, "DEPTH: infinity is not supported") + span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest)) + sublog.Debug().Str("depth", dh).Msg(errors.ErrInvalidDepth.Error()) + w.WriteHeader(http.StatusBadRequest) + m := fmt.Sprintf("Invalid Depth header value: %v", dh) + b, err := errors.Marshal(http.StatusBadRequest, m, "") + errors.HandleWebdavError(&sublog, w, b, err) return }