From b9689882e2ca18fb3ef48d589367913800f5ccc1 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Wed, 7 Oct 2026 10:03:42 -0700 Subject: [PATCH] security: reject negative filer token lifetimes A negative expires_after_seconds reached GenJwtForFilerServer and produced a token with no expiration claim. Also synchronize the Authorization-header capture in the proxy test and restore the prior viper key on cleanup. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- weed/filer/filechunk_manifest_test.go | 6 +++--- weed/security/jwt.go | 3 +++ weed/security/jwt_filer_provider_test.go | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/weed/filer/filechunk_manifest_test.go b/weed/filer/filechunk_manifest_test.go index a66c251b96..2d5d9f412a 100644 --- a/weed/filer/filechunk_manifest_test.go +++ b/weed/filer/filechunk_manifest_test.go @@ -742,9 +742,9 @@ func TestFetchWholeChunkUsesProvidedFilerJwt(t *testing.T) { }) assert.NoError(t, err) - var gotAuth string + gotAuth := make(chan string, 1) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - gotAuth = r.Header.Get("Authorization") + gotAuth <- r.Header.Get("Authorization") w.Header().Set("Content-Length", strconv.Itoa(len(manifestBytes))) w.Write(manifestBytes) })) @@ -759,7 +759,7 @@ func TestFetchWholeChunkUsesProvidedFilerJwt(t *testing.T) { } bytesBuffer := fetchManifestBuffer(t) assert.NoError(t, fetchWholeChunk(context.Background(), bytesBuffer, lookup, "5,abc", nil, false, nil, jwtFn)) - assert.Equal(t, security.BearerPrefix+"side-read-jwt", gotAuth) + assert.Equal(t, security.BearerPrefix+"side-read-jwt", <-gotAuth) // non-proxy URLs keep the volume-server credential and never call the provider volumeURL := manifestServer(t, manifestBytes).URL + "/5,abc" diff --git a/weed/security/jwt.go b/weed/security/jwt.go index 9a1445158a..30b02db3e1 100644 --- a/weed/security/jwt.go +++ b/weed/security/jwt.go @@ -191,6 +191,9 @@ func LoadFilerJwtFromFile(configFile string) (FilerJwtProvider, error) { readSigningKeyExpires = gv.GetInt("jwt.filer_signing.read.expires_after_seconds") } } + if signingKeyExpires < 0 || readSigningKeyExpires < 0 { + return nil, fmt.Errorf("jwt.filer_signing lifetimes must not be negative") + } if signingKeyExpires == 0 { signingKeyExpires = 10 } diff --git a/weed/security/jwt_filer_provider_test.go b/weed/security/jwt_filer_provider_test.go index f2c4c598c9..8a4a6067b5 100644 --- a/weed/security/jwt_filer_provider_test.go +++ b/weed/security/jwt_filer_provider_test.go @@ -96,8 +96,9 @@ key = "side-read-key" } gv := util.GetViper() + priorKey := gv.GetString("jwt.filer_signing.key") gv.Set("jwt.filer_signing.key", "global-write-key") - t.Cleanup(func() { gv.Set("jwt.filer_signing.key", "") }) + t.Cleanup(func() { gv.Set("jwt.filer_signing.key", priorKey) }) provider, err := LoadFilerJwtFromFile(configFile) if err != nil {