Skip to content

Commit 3774782

Browse files
committed
allow using the X-Forwarded-Prefix header for path prefix
In most (all?) cases, traefik makes the forwardAuth request at the root of the server (/). This means that the user's requested path is lost. However, the prefix is sent along with the `X-Forwarded-Prefix` header, so we use that in addition to the requested path if the requested path is empty.
1 parent c4317b7 commit 3774782

File tree

2 files changed

+27
-2
lines changed

2 files changed

+27
-2
lines changed

internal/auth.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,17 @@ func redirectBase(r *http.Request) string {
128128
return fmt.Sprintf("%s://%s", r.Header.Get("X-Forwarded-Proto"), r.Host)
129129
}
130130

131-
// Return url
131+
// returnUrl is the URL that we will return to after authentication. Uses the `X-Forwarded-Prefix` header if provided,
132+
// since traefik just requests the root (i.e. r.URL.Path is almost always /)
132133
func returnUrl(r *http.Request) string {
133-
return fmt.Sprintf("%s%s", redirectBase(r), r.URL.Path)
134+
fwdUri := r.URL.Path
135+
if r.URL.Path == "" || r.URL.Path == "/" {
136+
headerPrefix := r.Header.Get("X-Forwarded-Prefix")
137+
if headerPrefix != "" && headerPrefix != "/" {
138+
fwdUri = headerPrefix
139+
}
140+
}
141+
return fmt.Sprintf("%s%s", redirectBase(r), fwdUri)
134142
}
135143

136144
// Get oauth redirect uri

internal/auth_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,23 @@ func TestMakeState(t *testing.T) {
392392
p3 := provider.GenericOAuth{}
393393
state = MakeState(r, &p3, "nonce")
394394
assert.Equal("nonce:generic-oauth:http://example.com/hello", state)
395+
396+
// Test at the root, but with a forwarded prefix
397+
// this is how traefik forwards the request path information
398+
r = httptest.NewRequest("GET", "http://example.com", nil)
399+
r.Header.Add("X-Forwarded-Proto", "https")
400+
r.Header.Add("X-Forwarded-Prefix", "/other/path")
401+
p4 := provider.GenericOAuth{}
402+
state = MakeState(r, &p4, "nonce")
403+
assert.Equal("nonce:generic-oauth:https://example.com/other/path", state)
404+
405+
// Path and a forwarded prefix should use the path
406+
r = httptest.NewRequest("GET", "http://example.com/multi/path", nil)
407+
r.Header.Add("X-Forwarded-Proto", "https")
408+
r.Header.Add("X-Forwarded-Prefix", "/something")
409+
p5 := provider.GenericOAuth{}
410+
state = MakeState(r, &p5, "nonce")
411+
assert.Equal("nonce:generic-oauth:https://example.com/multi/path", state)
395412
}
396413

397414
func TestAuthNonce(t *testing.T) {

0 commit comments

Comments
 (0)