Middlewares: add forwardAuth.authResponseHeadersRegex
This commit is contained in:
parent
b5198e63c4
commit
49cdb67ddc
12 changed files with 116 additions and 24 deletions
|
@ -164,7 +164,7 @@ http:
|
|||
|
||||
### `authResponseHeaders`
|
||||
|
||||
The `authResponseHeaders` option is the list of the headers to copy from the authentication server to the request.
|
||||
The `authResponseHeaders` option is the list of the headers to copy from the authentication server to the request. All incoming request's headers in this list are deleted from the request before any copy happens.
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
|
@ -217,6 +217,59 @@ http:
|
|||
- "X-Secret"
|
||||
```
|
||||
|
||||
### `authResponseHeadersRegex`
|
||||
|
||||
The `authResponseHeadersRegex` option is the regex to match the headers that should be copied from the authentication server to the request. All incoming request's headers matching this regex are deleted from the request before any copy happens.
|
||||
It allows partial matching of the regular expression against the header's key.
|
||||
You should use start of string (`^`) and end of string (`$`) anchors to ensure a full match against the header's key.
|
||||
|
||||
```yaml tab="Docker"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex=^X-"
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: test-auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: https://example.com/auth
|
||||
authResponseHeadersRegex: ^X-
|
||||
```
|
||||
|
||||
```yaml tab="Consul Catalog"
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex=^X-"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex": "^X-"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex=^X-"
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-auth.forwardAuth]
|
||||
address = "https://example.com/auth"
|
||||
authResponseHeadersRegex = "^X-"
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
http:
|
||||
middlewares:
|
||||
test-auth:
|
||||
forwardAuth:
|
||||
address: "https://example.com/auth"
|
||||
authResponseHeadersRegex: "^X-"
|
||||
```
|
||||
|
||||
### `authRequestHeaders`
|
||||
|
||||
The `authRequestHeaders` option is the list of the headers to copy from the request to the authentication server.
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
- "traefik.http.middlewares.middleware08.errors.status=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware09.forwardauth.address=foobar"
|
||||
- "traefik.http.middlewares.middleware09.forwardauth.authresponseheaders=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware09.forwardauth.authresponseheadersregex=foobar"
|
||||
- "traefik.http.middlewares.middleware09.forwardauth.authrequestheaders=foobar, foobar"
|
||||
- "traefik.http.middlewares.middleware09.forwardauth.tls.ca=foobar"
|
||||
- "traefik.http.middlewares.middleware09.forwardauth.tls.caoptional=true"
|
||||
|
|
|
@ -139,6 +139,7 @@
|
|||
address = "foobar"
|
||||
trustForwardHeader = true
|
||||
authResponseHeaders = ["foobar", "foobar"]
|
||||
authResponseHeadersRegex = "foobar"
|
||||
authRequestHeaders = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware09.forwardAuth.tls]
|
||||
ca = "foobar"
|
||||
|
|
|
@ -158,6 +158,7 @@ http:
|
|||
authResponseHeaders:
|
||||
- foobar
|
||||
- foobar
|
||||
authResponseHeadersRegex: foobar
|
||||
authRequestHeaders:
|
||||
- foobar
|
||||
- foobar
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
| `traefik/http/middlewares/Middleware09/forwardAuth/authRequestHeaders/1` | `foobar` |
|
||||
| `traefik/http/middlewares/Middleware09/forwardAuth/authResponseHeaders/0` | `foobar` |
|
||||
| `traefik/http/middlewares/Middleware09/forwardAuth/authResponseHeaders/1` | `foobar` |
|
||||
| `traefik/http/middlewares/Middleware09/forwardAuth/authResponseHeadersRegex` | `foobar` |
|
||||
| `traefik/http/middlewares/Middleware09/forwardAuth/tls/ca` | `foobar` |
|
||||
| `traefik/http/middlewares/Middleware09/forwardAuth/tls/caOptional` | `true` |
|
||||
| `traefik/http/middlewares/Middleware09/forwardAuth/tls/cert` | `foobar` |
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
"traefik.http.middlewares.middleware08.errors.status": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware09.forwardauth.address": "foobar",
|
||||
"traefik.http.middlewares.middleware09.forwardauth.authresponseheaders": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware09.forwardauth.authresponseheadersregex": "foobar",
|
||||
"traefik.http.middlewares.middleware09.forwardauth.authrequestheaders": "foobar, foobar",
|
||||
"traefik.http.middlewares.middleware09.forwardauth.tls.ca": "foobar",
|
||||
"traefik.http.middlewares.middleware09.forwardauth.tls.caoptional": "true",
|
||||
|
|
|
@ -288,6 +288,7 @@
|
|||
address = "foobar"
|
||||
trustForwardHeader = true
|
||||
authResponseHeaders = ["foobar", "foobar"]
|
||||
authResponseHeadersRegex = "foobar"
|
||||
authRequestHeaders = ["foobar", "foobar"]
|
||||
[http.middlewares.Middleware15.forwardAuth.tls]
|
||||
ca = "foobar"
|
||||
|
|
|
@ -140,11 +140,12 @@ type ErrorPage struct {
|
|||
|
||||
// ForwardAuth holds the http forward authentication configuration.
|
||||
type ForwardAuth struct {
|
||||
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
|
||||
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"`
|
||||
Address string `json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
|
||||
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"`
|
||||
AuthResponseHeadersRegex string `json:"authResponseHeadersRegex,omitempty" toml:"authResponseHeadersRegex,omitempty" yaml:"authResponseHeadersRegex,omitempty"`
|
||||
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty" toml:"authRequestHeaders,omitempty" yaml:"authRequestHeaders,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -25,13 +26,14 @@ const (
|
|||
)
|
||||
|
||||
type forwardAuth struct {
|
||||
address string
|
||||
authResponseHeaders []string
|
||||
next http.Handler
|
||||
name string
|
||||
client http.Client
|
||||
trustForwardHeader bool
|
||||
authRequestHeaders []string
|
||||
address string
|
||||
authResponseHeaders []string
|
||||
authResponseHeadersRegex *regexp.Regexp
|
||||
next http.Handler
|
||||
name string
|
||||
client http.Client
|
||||
trustForwardHeader bool
|
||||
authRequestHeaders []string
|
||||
}
|
||||
|
||||
// NewForward creates a forward auth middleware.
|
||||
|
@ -66,6 +68,14 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu
|
|||
fa.client.Transport = tr
|
||||
}
|
||||
|
||||
if config.AuthResponseHeadersRegex != "" {
|
||||
re, err := regexp.Compile(config.AuthResponseHeadersRegex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error compiling regular expression %s: %w", config.AuthResponseHeadersRegex, err)
|
||||
}
|
||||
fa.authResponseHeadersRegex = re
|
||||
}
|
||||
|
||||
return fa, nil
|
||||
}
|
||||
|
||||
|
@ -156,6 +166,20 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
if fa.authResponseHeadersRegex != nil {
|
||||
for headerKey := range req.Header {
|
||||
if fa.authResponseHeadersRegex.MatchString(headerKey) {
|
||||
req.Header.Del(headerKey)
|
||||
}
|
||||
}
|
||||
|
||||
for headerKey, headerValues := range forwardResponse.Header {
|
||||
if fa.authResponseHeadersRegex.MatchString(headerKey) {
|
||||
req.Header[headerKey] = append([]string(nil), headerValues...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req.RequestURI = req.URL.RequestURI()
|
||||
fa.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ func TestForwardAuthSuccess(t *testing.T) {
|
|||
w.Header().Set("X-Auth-Secret", "secret")
|
||||
w.Header().Add("X-Auth-Group", "group1")
|
||||
w.Header().Add("X-Auth-Group", "group2")
|
||||
w.Header().Add("Foo-Bar", "auth-value")
|
||||
fmt.Fprintln(w, "Success")
|
||||
}))
|
||||
t.Cleanup(server.Close)
|
||||
|
@ -65,12 +66,15 @@ func TestForwardAuthSuccess(t *testing.T) {
|
|||
assert.Equal(t, "user@example.com", r.Header.Get("X-Auth-User"))
|
||||
assert.Empty(t, r.Header.Get("X-Auth-Secret"))
|
||||
assert.Equal(t, []string{"group1", "group2"}, r.Header["X-Auth-Group"])
|
||||
assert.Equal(t, "auth-value", r.Header.Get("Foo-Bar"))
|
||||
assert.Empty(t, r.Header.Get("Foo-Baz"))
|
||||
fmt.Fprintln(w, "traefik")
|
||||
})
|
||||
|
||||
auth := dynamic.ForwardAuth{
|
||||
Address: server.URL,
|
||||
AuthResponseHeaders: []string{"X-Auth-User", "X-Auth-Group"},
|
||||
Address: server.URL,
|
||||
AuthResponseHeaders: []string{"X-Auth-User", "X-Auth-Group"},
|
||||
AuthResponseHeadersRegex: "^Foo-",
|
||||
}
|
||||
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
@ -80,6 +84,8 @@ func TestForwardAuthSuccess(t *testing.T) {
|
|||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
|
||||
req.Header.Set("X-Auth-Group", "admin_group")
|
||||
req.Header.Set("Foo-Bar", "client-value")
|
||||
req.Header.Set("Foo-Baz", "client-value")
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode)
|
||||
|
|
|
@ -373,10 +373,11 @@ func createForwardAuthMiddleware(k8sClient Client, namespace string, auth *v1alp
|
|||
}
|
||||
|
||||
forwardAuth := &dynamic.ForwardAuth{
|
||||
Address: auth.Address,
|
||||
TrustForwardHeader: auth.TrustForwardHeader,
|
||||
AuthResponseHeaders: auth.AuthResponseHeaders,
|
||||
AuthRequestHeaders: auth.AuthRequestHeaders,
|
||||
Address: auth.Address,
|
||||
TrustForwardHeader: auth.TrustForwardHeader,
|
||||
AuthResponseHeaders: auth.AuthResponseHeaders,
|
||||
AuthResponseHeadersRegex: auth.AuthResponseHeadersRegex,
|
||||
AuthRequestHeaders: auth.AuthRequestHeaders,
|
||||
}
|
||||
|
||||
if auth.TLS == nil {
|
||||
|
|
|
@ -85,11 +85,12 @@ type DigestAuth struct {
|
|||
|
||||
// ForwardAuth holds the http forward authentication configuration.
|
||||
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"`
|
||||
Address string `json:"address,omitempty"`
|
||||
TrustForwardHeader bool `json:"trustForwardHeader,omitempty"`
|
||||
AuthResponseHeaders []string `json:"authResponseHeaders,omitempty"`
|
||||
AuthResponseHeadersRegex string `json:"authResponseHeadersRegex,omitempty"`
|
||||
AuthRequestHeaders []string `json:"authRequestHeaders,omitempty"`
|
||||
TLS *ClientTLS `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClientTLS holds TLS specific configurations as client.
|
||||
|
|
Loading…
Reference in a new issue