mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-06 10:21:05 +02:00
authorize: fix x-forwarded-uri
This commit is contained in:
parent
24a9d627cd
commit
36b819af82
3 changed files with 70 additions and 22 deletions
|
@ -11,7 +11,6 @@ import (
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/authorize/evaluator"
|
"github.com/pomerium/pomerium/authorize/evaluator"
|
||||||
"github.com/pomerium/pomerium/config"
|
"github.com/pomerium/pomerium/config"
|
||||||
"github.com/pomerium/pomerium/internal/httputil"
|
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/internal/sessions"
|
"github.com/pomerium/pomerium/internal/sessions"
|
||||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||||
|
@ -44,7 +43,7 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v3.CheckRe
|
||||||
isForwardAuth := a.isForwardAuth(in)
|
isForwardAuth := a.isForwardAuth(in)
|
||||||
if isForwardAuth {
|
if isForwardAuth {
|
||||||
// update the incoming http request's uri to match the forwarded URI
|
// update the incoming http request's uri to match the forwarded URI
|
||||||
fwdAuthURI := getForwardAuthURL(hreq)
|
fwdAuthURI := urlutil.GetForwardAuthURL(hreq)
|
||||||
in.Attributes.Request.Http.Scheme = fwdAuthURI.Scheme
|
in.Attributes.Request.Http.Scheme = fwdAuthURI.Scheme
|
||||||
in.Attributes.Request.Http.Host = fwdAuthURI.Host
|
in.Attributes.Request.Http.Host = fwdAuthURI.Host
|
||||||
in.Attributes.Request.Http.Path = fwdAuthURI.EscapedPath()
|
in.Attributes.Request.Http.Path = fwdAuthURI.EscapedPath()
|
||||||
|
@ -103,26 +102,6 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v3.CheckRe
|
||||||
return a.handleResultDenied(ctx, in, req, res, isForwardAuthVerify, res.Allow.Reasons)
|
return a.handleResultDenied(ctx, in, req, res, isForwardAuthVerify, res.Allow.Reasons)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getForwardAuthURL(r *http.Request) *url.URL {
|
|
||||||
urqQuery := r.URL.Query().Get("uri")
|
|
||||||
u, _ := urlutil.ParseAndValidateURL(urqQuery)
|
|
||||||
if u == nil {
|
|
||||||
u = &url.URL{
|
|
||||||
Scheme: r.Header.Get(httputil.HeaderForwardedProto),
|
|
||||||
Host: r.Header.Get(httputil.HeaderForwardedHost),
|
|
||||||
Path: r.Header.Get(httputil.HeaderForwardedURI),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
originalURL := r.Header.Get(httputil.HeaderOriginalURL)
|
|
||||||
if originalURL != "" {
|
|
||||||
k, _ := urlutil.ParseAndValidateURL(originalURL)
|
|
||||||
if k != nil {
|
|
||||||
u = k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
// isForwardAuth returns if the current request is a forward auth route.
|
// isForwardAuth returns if the current request is a forward auth route.
|
||||||
func (a *Authorize) isForwardAuth(req *envoy_service_auth_v3.CheckRequest) bool {
|
func (a *Authorize) isForwardAuth(req *envoy_service_auth_v3.CheckRequest) bool {
|
||||||
opts := a.currentOptions.Load()
|
opts := a.currentOptions.Load()
|
||||||
|
|
47
internal/urlutil/forward.go
Normal file
47
internal/urlutil/forward.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package urlutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Forward headers contains information from the client-facing side of proxy
|
||||||
|
// servers that is altered or lost when a proxy is involved in the path of the
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc7239
|
||||||
|
// https://en.wikipedia.org/wiki/X-Forwarded-For
|
||||||
|
const (
|
||||||
|
HeaderForwardedHost = "X-Forwarded-Host"
|
||||||
|
HeaderForwardedProto = "X-Forwarded-Proto"
|
||||||
|
HeaderForwardedURI = "X-Forwarded-Uri" // traefik
|
||||||
|
HeaderOriginalURL = "X-Original-Url" // nginx
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetForwardAuthURL gets the forward-auth URL for the given request.
|
||||||
|
func GetForwardAuthURL(r *http.Request) *url.URL {
|
||||||
|
urqQuery := r.URL.Query().Get("uri")
|
||||||
|
u, _ := ParseAndValidateURL(urqQuery)
|
||||||
|
if u == nil {
|
||||||
|
u = &url.URL{
|
||||||
|
Scheme: r.Header.Get(HeaderForwardedProto),
|
||||||
|
Host: r.Header.Get(HeaderForwardedHost),
|
||||||
|
}
|
||||||
|
rawPath := r.Header.Get(HeaderForwardedURI)
|
||||||
|
if idx := strings.Index(rawPath, "?"); idx >= 0 {
|
||||||
|
u.RawPath = rawPath[:idx]
|
||||||
|
u.RawQuery = rawPath[idx+1:]
|
||||||
|
} else {
|
||||||
|
u.RawPath = rawPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
originalURL := r.Header.Get(HeaderOriginalURL)
|
||||||
|
if originalURL != "" {
|
||||||
|
k, _ := ParseAndValidateURL(originalURL)
|
||||||
|
if k != nil {
|
||||||
|
u = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
22
internal/urlutil/forward_test.go
Normal file
22
internal/urlutil/forward_test.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package urlutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetForwardAuthURL(t *testing.T) {
|
||||||
|
t.Run("double-escaping", func(t *testing.T) {
|
||||||
|
req, err := http.NewRequest("GET", "https://example.com", nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
req.Header.Set("X-Forwarded-Proto", "https")
|
||||||
|
req.Header.Set("X-Forwarded-Host", "protected-host.tld")
|
||||||
|
req.Header.Set("X-Forwarded-Uri", "/example?a=b&c=d")
|
||||||
|
|
||||||
|
u := GetForwardAuthURL(req)
|
||||||
|
assert.Equal(t, "https://protected-host.tld?a=b&c=d", u.String())
|
||||||
|
})
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue