authorize,proxy: allow traefik forward auth without uri query (#1103)

In #1030, the fix was done without aware of the context that traefik
forward auth mode did allow request without the "?uri=". Previosuly,
this is done in proxy, and by converting the forward auth request to
actual request. The fix is #1030 prevent this conversion, to makre
authorize service aware of which is forward auth request.

But that causes traefik forward auth without "?uri" stop working. Fixing
it by making the authorize service also honor the forwarded uri header,
too.

Fixes #1096
This commit is contained in:
Cuong Manh Le 2020-07-21 00:58:14 +07:00 committed by GitHub
parent e85226b609
commit e8d3ce1a2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 18 deletions

View file

@ -192,6 +192,14 @@ func (a *Authorize) handleForwardAuth(req *envoy_service_auth_v2.CheckRequest) b
}
uriQuery := checkURL.Query().Get("uri")
if headers := req.GetAttributes().GetRequest().GetHttp().GetHeaders(); uriQuery == "" && headers != nil {
uriQuery = headers[http.CanonicalHeaderKey(httputil.HeaderForwardedProto)] + "://" +
headers[http.CanonicalHeaderKey(httputil.HeaderForwardedHost)]
if xfu := headers[http.CanonicalHeaderKey(httputil.HeaderForwardedURI)]; xfu != "/" {
uriQuery += xfu
}
}
if (checkURL.Path != "/" && checkURL.Path != "/verify") || uriQuery == "" {
return false
}
@ -204,11 +212,7 @@ func (a *Authorize) handleForwardAuth(req *envoy_service_auth_v2.CheckRequest) b
req.Attributes.Request.Http.Scheme = verifyURL.Scheme
req.Attributes.Request.Http.Host = verifyURL.Host
req.Attributes.Request.Http.Path = verifyURL.Path
if headers := req.GetAttributes().GetRequest().GetHttp().GetHeaders(); headers != nil {
if xfu := headers[http.CanonicalHeaderKey(httputil.HeaderForwardedURI)]; xfu != "" {
req.Attributes.Request.Http.Path += xfu
}
}
// envoy sends the query string as part of the path
if verifyURL.RawQuery != "" {
req.Attributes.Request.Http.Path += "?" + verifyURL.RawQuery

View file

@ -10,6 +10,7 @@ import (
"github.com/pomerium/pomerium/authorize/evaluator"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/encoding/jws"
"github.com/pomerium/pomerium/internal/httputil"
)
const certPEM = `
@ -127,21 +128,29 @@ func Test_handleForwardAuth(t *testing.T) {
},
Request: &envoy_service_auth_v2.AttributeContext_Request{
Http: &envoy_service_auth_v2.AttributeContext_HttpRequest{
Method: "GET",
Path: "/verify?uri=" + url.QueryEscape("https://example.com?q=foo"),
Host: "forward-auth.example.com",
Scheme: "https",
Headers: map[string]string{"X-Forwarded-Uri": "/foo/bar"},
Method: "GET",
Path: "/",
Host: "forward-auth.example.com",
Scheme: "https",
Headers: map[string]string{
httputil.HeaderForwardedURI: "/foo/bar",
httputil.HeaderForwardedProto: "https",
httputil.HeaderForwardedHost: "example.com",
},
},
},
},
},
attrCtxHTTPReq: &envoy_service_auth_v2.AttributeContext_HttpRequest{
Method: "GET",
Path: "/foo/bar?q=foo",
Host: "example.com",
Scheme: "https",
Headers: map[string]string{"X-Forwarded-Uri": "/foo/bar"},
Method: "GET",
Path: "/foo/bar",
Host: "example.com",
Scheme: "https",
Headers: map[string]string{
httputil.HeaderForwardedURI: "/foo/bar",
httputil.HeaderForwardedProto: "https",
httputil.HeaderForwardedHost: "example.com",
},
},
forwardAuthURL: "https://forward-auth.example.com",
isForwardAuth: true,

View file

@ -141,10 +141,10 @@ func (p *Proxy) Verify(verifyOnly bool) http.Handler {
// forwardAuthRedirectToSignInWithURI redirects request to authenticate signin url,
// with all necessary information extracted from given input uri.
func (p *Proxy) forwardAuthRedirectToSignInWithURI(w http.ResponseWriter, r *http.Request, uri *url.URL) {
// Traefik set the uri in the header, we must add it to redirect uri if present. Otherwise, request like
// Traefik set the uri in the header, we must set it in redirect uri if present. Otherwise, request like
// https://example.com/foo will be redirected to https://example.com after authentication.
if xfu := r.Header.Get(httputil.HeaderForwardedURI); xfu != "" {
uri.Path += xfu
if xfu := r.Header.Get(httputil.HeaderForwardedURI); xfu != "/" {
uri.Path = xfu
}
// redirect to authenticate