Prevent duplicate user headers in basic and digest auth middleware
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Build and Publish Documentation / Doc Process (push) Has been cancelled
Build experimental image on branch / build-webui (push) Has been cancelled
Build experimental image on branch / Build experimental image on branch (push) Has been cancelled

This commit is contained in:
Julien Salleyron 2026-03-20 16:24:05 +01:00 committed by GitHub
parent 70c45a6f9c
commit 51f6b0435f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 60 additions and 0 deletions

View file

@ -323,6 +323,11 @@ linters:
text: 'SA1019: cfg.(SSLRedirect|SSLTemporaryRedirect|SSLHost|SSLForceHost|FeaturePolicy) is deprecated'
- path: (.+)\.go$
text: 'SA1019: c.Providers.(ConsulCatalog|Consul|Nomad).Namespace is deprecated'
- path: pkg/middlewares/auth/basic_auth_test.go
text: 'SA1008: keys in http.Header are canonicalized, "x-user" is not canonical; fix the constant or use http.CanonicalHeaderKey'
- path: pkg/middlewares/auth/digest_auth_test.go
text: 'SA1008: keys in http.Header are canonicalized, "x-user" is not canonical; fix the constant or use http.CanonicalHeaderKey'
paths:
- pkg/provider/kubernetes/crd/generated/

View file

@ -100,6 +100,8 @@ func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
req.URL.User = url.User(user)
if b.headerField != "" {
// TODO Deprecated we should add the header with canonical key.
req.Header.Del(b.headerField)
req.Header[b.headerField] = []string{user}
}

View file

@ -103,6 +103,30 @@ func TestBasicAuthUserHeader(t *testing.T) {
assert.Equal(t, "traefik\n", string(body))
}
func TestBasicAuthUserHeaderCanonical(t *testing.T) {
var nextCalled bool
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
nextCalled = true
assert.Empty(t, req.Header.Get("X-User"))
assert.Equal(t, []string{"test"}, req.Header["x-user"])
})
auth := dynamic.BasicAuth{
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
HeaderField: "x-user",
}
m, err := NewBasic(t.Context(), next, auth, "test")
require.NoError(t, err)
req := httptest.NewRequest(http.MethodGet, "http://localhost/", nil)
req.SetBasicAuth("test", "test")
req.Header.Set("X-User", "admin")
rw := httptest.NewRecorder()
m.ServeHTTP(rw, req)
assert.Equal(t, http.StatusOK, rw.Result().StatusCode)
assert.True(t, nextCalled)
}
func TestBasicAuthHeaderRemoved(t *testing.T) {
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Empty(t, r.Header.Get(authorizationHeader))

View file

@ -98,6 +98,8 @@ func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
if d.headerField != "" {
// TODO Deprecated we should add the header with canonical key.
req.Header.Del(d.headerField)
req.Header[d.headerField] = []string{username}
}

View file

@ -151,3 +151,30 @@ func TestDigestAuthUsersFromFile(t *testing.T) {
})
}
}
func TestDigestAuthUserHeaderCanonical(t *testing.T) {
var nextCalled bool
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
nextCalled = true
assert.Empty(t, req.Header.Get("X-User"))
assert.Equal(t, []string{"test"}, req.Header["x-user"])
})
auth := dynamic.DigestAuth{
Users: []string{"test:traefik:a2688e031edb4be6a3797f3882655c05"},
HeaderField: "x-user",
}
m, err := NewDigest(t.Context(), next, auth, "test")
require.NoError(t, err)
srv := httptest.NewServer(m)
t.Cleanup(srv.Close)
req := testhelpers.MustNewRequest(http.MethodGet, srv.URL, nil)
req.Header.Set("X-User", "admin")
digestReq := newDigestRequest("test", "test", http.DefaultClient)
res, err := digestReq.Do(req)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
assert.True(t, nextCalled)
}