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

[full-ci] disable DEPTH infinity in PROPFIND #4278

Merged
merged 3 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .drone.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# The test runner source for API tests
APITESTS_COMMITID=dc3ed28696c6823ad181627a6ac92bbeccf06565
APITESTS_COMMITID=c4d3ec7e5b07abe00ce3d9c322387eba80224ecf
APITESTS_BRANCH=master
APITESTS_REPO_GIT_URL=https://github.com/owncloud/ocis.git
9 changes: 9 additions & 0 deletions changelog/unreleased/disable-depth-infinity.md
Original file line number Diff line number Diff line change
@@ -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/<token>
Trashbin /remote.php/dav/spaces/trash-bin/<personal-space-id>

https://github.com/cs3org/reva/pull/4278
https://github.com/owncloud/ocis/issues/7359
43 changes: 30 additions & 13 deletions internal/http/services/owncloud/ocdav/propfind/propfind.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
})
})

Expand Down
24 changes: 23 additions & 1 deletion internal/http/services/owncloud/ocdav/publicfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down
26 changes: 24 additions & 2 deletions internal/http/services/owncloud/ocdav/trashbin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
}

Expand Down Expand Up @@ -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
}

Expand Down