From 7f7a938c3f716430f8a6369f272f9064d27b34ea Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Mon, 7 Sep 2026 12:06:18 +0200 Subject: [PATCH] fix(proxy): restrict JWT signed urls to the allowed HTTP methods The legacy OC-Signature path already rejects methods outside PRE_SIGNED_URL_ALLOWED_HTTP_METHODS, the JWT path did not. A leaked signed download url could be used for PUT, DELETE, MOVE or PROPFIND as the signing user for the lifetime of the signature. --- .../proxy/pkg/middleware/signed_url_auth.go | 10 ++++++++ .../pkg/middleware/signed_url_auth_test.go | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/services/proxy/pkg/middleware/signed_url_auth.go b/services/proxy/pkg/middleware/signed_url_auth.go index 4381027e95..1c62202360 100644 --- a/services/proxy/pkg/middleware/signed_url_auth.go +++ b/services/proxy/pkg/middleware/signed_url_auth.go @@ -236,6 +236,16 @@ func (m SignedURLAuthenticator) Authenticate(r *http.Request) (*http.Request, bo } func (m SignedURLAuthenticator) authenticate(r *http.Request) (*http.Request, bool) { + if err := m.requestMethodIsAllowed(r.Method); err != nil { + m.Logger.Error(). + Err(err). + Str("authenticator", "signed_url_jwt"). + Str("path", r.URL.Path). + Str("method", r.Method). + Msg("Request method not allowed for signed urls") + return nil, false + } + u := r.URL.String() if !r.URL.IsAbs() { u = "https://" + r.Host + u diff --git a/services/proxy/pkg/middleware/signed_url_auth_test.go b/services/proxy/pkg/middleware/signed_url_auth_test.go index c507fa787c..bdaecd8072 100644 --- a/services/proxy/pkg/middleware/signed_url_auth_test.go +++ b/services/proxy/pkg/middleware/signed_url_auth_test.go @@ -2,11 +2,13 @@ package middleware import ( "context" + "net/http" "net/http/httptest" "testing" "time" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + "github.com/opencloud-eu/opencloud/pkg/log" "github.com/opencloud-eu/opencloud/services/proxy/pkg/config" revactx "github.com/opencloud-eu/reva/v2/pkg/ctx" "github.com/opencloud-eu/reva/v2/pkg/signedurl" @@ -71,6 +73,27 @@ func TestSignedURLAuth_shouldServe(t *testing.T) { } } +func TestSignedURLAuth_authenticateRejectsDisallowedMethods(t *testing.T) { + signer, err := signedurl.NewJWTSignedURL(signedurl.WithSecret("secret")) + if err != nil { + t.Fatalf("failed to create signer: %v", err) + } + signed, err := signer.Sign("https://example.com/dav/spaces/file.txt", "userid", time.Minute) + if err != nil { + t.Fatalf("failed to sign url: %v", err) + } + + pua := SignedURLAuthenticator{Logger: log.NewLogger(), URLVerifier: signer} + pua.PreSignedURLConfig.AllowedHTTPMethods = []string{"GET"} + + for _, method := range []string{http.MethodPost, http.MethodPut, http.MethodDelete, "PROPFIND", "MOVE"} { + r := httptest.NewRequest(method, signed, nil) + if _, ok := pua.authenticate(r); ok { + t.Errorf("expected %s with a signed url to be rejected", method) + } + } +} + func TestSignedURLAuth_allRequiredParametersPresent(t *testing.T) { pua := SignedURLAuthenticator{} baseURL := "https://example.com/example.jpg?"