RedirectScheme redirects based on X-Forwarded-Proto header

This commit is contained in:
Maxence Moutoussamy 2022-06-24 12:04:09 +02:00 committed by GitHub
parent 55ba4356f2
commit ff17ac53df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 5 deletions

View file

@ -12,7 +12,17 @@ Redirecting the Client to a Different Scheme/Port
TODO: add schema
-->
RedirectScheme redirects requests from a scheme/port to another.
The RedirectScheme middleware redirects the request if the request scheme is different from the configured scheme.
The middleware does not work for websocket requests.
!!! warning "When behind another reverse-proxy"
When there is at least one other reverse-proxy between the client and Traefik,
the other reverse-proxy (i.e. the last hop) needs to be a [trusted](../../routing/entrypoints.md#forwarded-headers) one.
Otherwise, Traefik would clean up the X-Forwarded headers coming from this last hop,
and as the RedirectScheme middleware relies on them to determine the scheme used,
it would not function as intended.
## Configuration Examples

View file

@ -13,8 +13,9 @@ import (
)
const (
typeSchemeName = "RedirectScheme"
uriPattern = `^(https?:\/\/)?(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
typeSchemeName = "RedirectScheme"
uriPattern = `^(https?:\/\/)?(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`
xForwardedProto = "X-Forwarded-Proto"
)
// NewRedirectScheme creates a new RedirectScheme middleware.
@ -63,7 +64,11 @@ func rawURLScheme(req *http.Request) string {
scheme = schemeHTTPS
}
if scheme == schemeHTTP && port == ":80" || scheme == schemeHTTPS && port == ":443" || port == "" {
if value := req.Header.Get(xForwardedProto); value != "" {
scheme = value
}
if scheme == schemeHTTP && port == ":80" || scheme == schemeHTTPS && port == ":443" {
port = ""
}

View file

@ -47,11 +47,22 @@ func TestRedirectSchemeHandler(t *testing.T) {
},
url: "http://foo",
headers: map[string]string{
"X-Forwarded-Proto": "https",
"X-Forwarded-Proto": "http",
},
expectedURL: "https://foo",
expectedStatus: http.StatusFound,
},
{
desc: "HTTP to HTTPS, with X-Forwarded-Proto to HTTPS",
config: dynamic.RedirectScheme{
Scheme: "https",
},
url: "http://foo",
headers: map[string]string{
"X-Forwarded-Proto": "https",
},
expectedStatus: http.StatusOK,
},
{
desc: "HTTP with port to HTTPS without port",
config: dynamic.RedirectScheme{