From 6bd8c1e838c348d7e75d1fb478d8b94a95da0075 Mon Sep 17 00:00:00 2001 From: jamesread Date: Thu, 21 May 2026 23:12:49 +0100 Subject: [PATCH] chore: allow case insensitive bearer --- service/internal/auth/local_bearer.go | 20 ++++++++++++++++---- service/internal/auth/local_bearer_test.go | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/service/internal/auth/local_bearer.go b/service/internal/auth/local_bearer.go index d9b752f..05a1979 100644 --- a/service/internal/auth/local_bearer.go +++ b/service/internal/auth/local_bearer.go @@ -9,7 +9,7 @@ import ( log "github.com/sirupsen/logrus" ) -const localBearerPrefix = "Bearer " +const localBearerScheme = "Bearer" func constantTimeEqualString(a, b string) bool { if len(a) != len(b) { @@ -20,11 +20,16 @@ func constantTimeEqualString(a, b string) bool { } func bearerTokenFromAuthorizationHeader(authz string) (string, bool) { - if !strings.HasPrefix(authz, localBearerPrefix) { + idx := strings.IndexByte(authz, ' ') + if idx <= 0 { return "", false } - token := strings.TrimSpace(strings.TrimPrefix(authz, localBearerPrefix)) + if !strings.EqualFold(authz[:idx], localBearerScheme) { + return "", false + } + + token := strings.TrimSpace(authz[idx+1:]) if token == "" { return "", false } @@ -50,12 +55,19 @@ func findLocalUserByAPIKey(cfg *config.Config, token string) *config.LocalUser { return nil } +func localBearerAuthorizationHasEmptyCredential(authz string) bool { + idx := strings.IndexByte(authz, ' ') + return idx > 0 && + strings.EqualFold(authz[:idx], localBearerScheme) && + strings.TrimSpace(authz[idx+1:]) == "" +} + func logLocalBearerAPIKeyParseFailure(authz string) { if strings.TrimSpace(authz) == "" { return } - if strings.HasPrefix(authz, localBearerPrefix) { + if localBearerAuthorizationHasEmptyCredential(authz) { log.Debugf("Local bearer API key: rejected (empty credential after Bearer prefix)") return } diff --git a/service/internal/auth/local_bearer_test.go b/service/internal/auth/local_bearer_test.go index 1f6fba6..65ce8c5 100644 --- a/service/internal/auth/local_bearer_test.go +++ b/service/internal/auth/local_bearer_test.go @@ -10,6 +10,28 @@ import ( "github.com/stretchr/testify/require" ) +func TestCheckUserFromLocalBearerApiKey_Match_LowercaseBearerScheme(t *testing.T) { + t.Parallel() + + cfg := config.DefaultConfig() + cfg.AuthLocalUsers.Enabled = true + cfg.AuthLocalUsers.Users = []*config.LocalUser{{ + Username: "bot", + Usergroup: "bots", + ApiKey: "secret-api-key", + }} + + req := httptest.NewRequest("POST", "/", nil) + req.Header.Set("Authorization", "bearer secret-api-key") + + ctx := &authpublic.AuthCheckingContext{Request: req, Config: cfg} + user := checkUserFromLocalBearerApiKey(ctx) + require.NotNil(t, user) + assert.Equal(t, "bot", user.Username) + assert.Equal(t, "bots", user.UsergroupLine) + assert.Equal(t, "local", user.Provider) +} + func TestCheckUserFromLocalBearerApiKey_Match(t *testing.T) { t.Parallel()