Filter ForwardAuth request headers
This commit is contained in:
parent
f2e53a3569
commit
326be29568
16 changed files with 171 additions and 3 deletions
|
@ -288,6 +288,7 @@
|
|||
address = "foobar"
|
||||
trustForwardHeader = true
|
||||
authResponseHeaders = ["foobar", "foobar"]
|
||||
authRequestHeaders = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware15.forwardAuth.tls]
|
||||
ca = "foobar"
|
||||
caOptional = true
|
||||
|
|
|
@ -144,6 +144,7 @@ type ForwardAuth struct {
|
|||
TLS *ClientTLS `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty"`
|
||||
TrustForwardHeader bool `json:"trustForwardHeader,omitempty" toml:"trustForwardHeader,omitempty" yaml:"trustForwardHeader,omitempty" export:"true"`
|
||||
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty" toml:"authResponseHeaders,omitempty" yaml:"authResponseHeaders,omitempty"`
|
||||
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
|
|
@ -344,6 +344,11 @@ func (in *ForwardAuth) DeepCopyInto(out *ForwardAuth) {
|
|||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.AuthRequestHeaders != nil {
|
||||
in, out := &in.AuthRequestHeaders, &out.AuthRequestHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"traefik.http.middlewares.Middleware6.errors.status": "foobar, fiibar",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.address": "foobar",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.authresponseheaders": "foobar, fiibar",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.authrequestheaders": "foobar, fiibar",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.tls.ca": "foobar",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.tls.caoptional": "true",
|
||||
"traefik.http.middlewares.Middleware7.forwardauth.tls.cert": "foobar",
|
||||
|
@ -496,6 +497,10 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"foobar",
|
||||
"fiibar",
|
||||
},
|
||||
AuthRequestHeaders: []string{
|
||||
"foobar",
|
||||
"fiibar",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Middleware8": {
|
||||
|
@ -964,6 +969,10 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"foobar",
|
||||
"fiibar",
|
||||
},
|
||||
AuthRequestHeaders: []string{
|
||||
"foobar",
|
||||
"fiibar",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Middleware8": {
|
||||
|
@ -1134,6 +1143,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"traefik.HTTP.Middlewares.Middleware6.Errors.Status": "foobar, fiibar",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.Address": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.AuthResponseHeaders": "foobar, fiibar",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.AuthRequestHeaders": "foobar, fiibar",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.TLS.CA": "foobar",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.TLS.CAOptional": "true",
|
||||
"traefik.HTTP.Middlewares.Middleware7.ForwardAuth.TLS.Cert": "foobar",
|
||||
|
|
|
@ -31,6 +31,7 @@ type forwardAuth struct {
|
|||
name string
|
||||
client http.Client
|
||||
trustForwardHeader bool
|
||||
authRequestHeaders []string
|
||||
}
|
||||
|
||||
// NewForward creates a forward auth middleware.
|
||||
|
@ -43,6 +44,7 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu
|
|||
next: next,
|
||||
name: name,
|
||||
trustForwardHeader: config.TrustForwardHeader,
|
||||
authRequestHeaders: config.AuthRequestHeaders,
|
||||
}
|
||||
|
||||
// Ensure our request client does not follow redirects
|
||||
|
@ -89,7 +91,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
// forwardReq.
|
||||
tracing.InjectRequestHeaders(req)
|
||||
|
||||
writeHeader(req, forwardReq, fa.trustForwardHeader)
|
||||
writeHeader(req, forwardReq, fa.trustForwardHeader, fa.authRequestHeaders)
|
||||
|
||||
forwardResponse, forwardErr := fa.client.Do(forwardReq)
|
||||
if forwardErr != nil {
|
||||
|
@ -158,10 +160,12 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
fa.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool) {
|
||||
func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool, allowedHeaders []string) {
|
||||
utils.CopyHeaders(forwardReq.Header, req.Header)
|
||||
utils.RemoveHeaders(forwardReq.Header, forward.HopHeaders...)
|
||||
|
||||
forwardReq.Header = filterForwardRequestHeaders(forwardReq.Header, allowedHeaders)
|
||||
|
||||
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
|
||||
if trustForwardHeader {
|
||||
if prior, ok := req.Header[forward.XForwardedFor]; ok {
|
||||
|
@ -215,3 +219,19 @@ func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool) {
|
|||
forwardReq.Header.Del(xForwardedURI)
|
||||
}
|
||||
}
|
||||
|
||||
func filterForwardRequestHeaders(forwardRequestHeaders http.Header, allowedHeaders []string) http.Header {
|
||||
if len(allowedHeaders) == 0 {
|
||||
return forwardRequestHeaders
|
||||
}
|
||||
|
||||
filteredHeaders := http.Header{}
|
||||
for _, headerName := range allowedHeaders {
|
||||
values := forwardRequestHeaders.Values(headerName)
|
||||
if len(values) > 0 {
|
||||
filteredHeaders[http.CanonicalHeaderKey(headerName)] = append([]string(nil), values...)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredHeaders
|
||||
}
|
||||
|
|
|
@ -242,6 +242,7 @@ func Test_writeHeader(t *testing.T) {
|
|||
testCases := []struct {
|
||||
name string
|
||||
headers map[string]string
|
||||
authRequestHeaders []string
|
||||
trustForwardHeader bool
|
||||
emptyHost bool
|
||||
expectedHeaders map[string]string
|
||||
|
@ -368,6 +369,45 @@ func Test_writeHeader(t *testing.T) {
|
|||
},
|
||||
checkForUnexpectedHeaders: true,
|
||||
},
|
||||
{
|
||||
name: "filter forward request headers",
|
||||
headers: map[string]string{
|
||||
"X-CustomHeader": "CustomHeader",
|
||||
"Content-Type": "multipart/form-data; boundary=---123456",
|
||||
},
|
||||
authRequestHeaders: []string{
|
||||
"X-CustomHeader",
|
||||
},
|
||||
trustForwardHeader: false,
|
||||
expectedHeaders: map[string]string{
|
||||
"x-customHeader": "CustomHeader",
|
||||
"X-Forwarded-Proto": "http",
|
||||
"X-Forwarded-Host": "foo.bar",
|
||||
"X-Forwarded-Uri": "/path?q=1",
|
||||
"X-Forwarded-Method": "GET",
|
||||
},
|
||||
checkForUnexpectedHeaders: true,
|
||||
},
|
||||
{
|
||||
name: "filter forward request headers doesn't add new headers",
|
||||
headers: map[string]string{
|
||||
"X-CustomHeader": "CustomHeader",
|
||||
"Content-Type": "multipart/form-data; boundary=---123456",
|
||||
},
|
||||
authRequestHeaders: []string{
|
||||
"X-CustomHeader",
|
||||
"X-Non-Exists-Header",
|
||||
},
|
||||
trustForwardHeader: false,
|
||||
expectedHeaders: map[string]string{
|
||||
"X-CustomHeader": "CustomHeader",
|
||||
"X-Forwarded-Proto": "http",
|
||||
"X-Forwarded-Host": "foo.bar",
|
||||
"X-Forwarded-Uri": "/path?q=1",
|
||||
"X-Forwarded-Method": "GET",
|
||||
},
|
||||
checkForUnexpectedHeaders: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
@ -383,9 +423,10 @@ func Test_writeHeader(t *testing.T) {
|
|||
|
||||
forwardReq := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/path?q=1", nil)
|
||||
|
||||
writeHeader(req, forwardReq, test.trustForwardHeader)
|
||||
writeHeader(req, forwardReq, test.trustForwardHeader, test.authRequestHeaders)
|
||||
|
||||
actualHeaders := forwardReq.Header
|
||||
|
||||
expectedHeaders := test.expectedHeaders
|
||||
for key, value := range expectedHeaders {
|
||||
assert.Equal(t, value, actualHeaders.Get(key))
|
||||
|
|
|
@ -376,6 +376,7 @@ func createForwardAuthMiddleware(k8sClient Client, namespace string, auth *v1alp
|
|||
Address: auth.Address,
|
||||
TrustForwardHeader: auth.TrustForwardHeader,
|
||||
AuthResponseHeaders: auth.AuthResponseHeaders,
|
||||
AuthRequestHeaders: auth.AuthRequestHeaders,
|
||||
}
|
||||
|
||||
if auth.TLS == nil {
|
||||
|
|
|
@ -88,6 +88,7 @@ type ForwardAuth struct {
|
|||
Address string `json:"address,omitempty"`
|
||||
TrustForwardHeader bool `json:"trustForwardHeader,omitempty"`
|
||||
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty"`
|
||||
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty"`
|
||||
TLS *ClientTLS `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
|
|
|
@ -171,6 +171,11 @@ func (in *ForwardAuth) DeepCopyInto(out *ForwardAuth) {
|
|||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.AuthRequestHeaders != nil {
|
||||
in, out := &in.AuthRequestHeaders, &out.AuthRequestHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(ClientTLS)
|
||||
|
|
|
@ -71,6 +71,8 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"traefik/http/services/Service03/weighted/services/1/weight": "42",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/authResponseHeaders/0": "foobar",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/authResponseHeaders/1": "foobar",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/authRequestHeaders/0": "foobar",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/authRequestHeaders/1": "foobar",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/tls/key": "foobar",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/tls/insecureSkipVerify": "true",
|
||||
"traefik/http/middlewares/Middleware08/forwardAuth/tls/ca": "foobar",
|
||||
|
@ -407,6 +409,10 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"foobar",
|
||||
"foobar",
|
||||
},
|
||||
AuthRequestHeaders: []string{
|
||||
"foobar",
|
||||
"foobar",
|
||||
},
|
||||
},
|
||||
},
|
||||
"Middleware06": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue