1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2025-06-15 00:15:00 +02:00

Use X-Forwarded-{Proto,Host,Uri} on redirect as last resort (#957)

This commit is contained in:
İlteriş Eroğlu
2021-01-02 02:23:11 +03:00
committed by GitHub
parent 91b3f5973e
commit 1d74a51cd7
6 changed files with 263 additions and 2 deletions

View File

@ -98,6 +98,7 @@ type OAuthProxy struct {
SetAuthorization bool
PassAuthorization bool
PreferEmailToUser bool
ReverseProxy bool
skipAuthPreflight bool
skipJwtBearerTokens bool
templates *template.Template
@ -200,6 +201,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
ProxyPrefix: opts.ProxyPrefix,
ReverseProxy: opts.ReverseProxy,
provider: opts.GetProvider(),
providerNameOverride: opts.ProviderName,
sessionStore: sessionStore,
@ -578,10 +580,18 @@ func (p *OAuthProxy) GetRedirect(req *http.Request) (redirect string, err error)
if req.Form.Get("rd") != "" {
redirect = req.Form.Get("rd")
}
// Quirk: On reverse proxies that doesn't have support for
// "X-Auth-Request-Redirect" header or dynamic header/query string
// manipulation (like Traefik v1 and v2), we can try if the header
// X-Forwarded-Host exists or not.
if redirect == "" && isForwardedRequest(req, p.ReverseProxy) {
redirect = p.getRedirectFromForwardHeaders(req)
}
if !p.IsValidRedirect(redirect) {
// Use RequestURI to preserve ?query
redirect = req.URL.RequestURI()
if strings.HasPrefix(redirect, p.ProxyPrefix) {
if strings.HasPrefix(redirect, fmt.Sprintf("%s/", p.ProxyPrefix)) {
redirect = "/"
}
}
@ -589,6 +599,17 @@ func (p *OAuthProxy) GetRedirect(req *http.Request) (redirect string, err error)
return
}
// getRedirectFromForwardHeaders returns the redirect URL based on X-Forwarded-{Proto,Host,Uri} headers
func (p *OAuthProxy) getRedirectFromForwardHeaders(req *http.Request) string {
uri := util.GetRequestURI(req)
if strings.HasPrefix(uri, fmt.Sprintf("%s/", p.ProxyPrefix)) {
uri = "/"
}
return fmt.Sprintf("%s://%s%s", util.GetRequestProto(req), util.GetRequestHost(req), uri)
}
// splitHostPort separates host and port. If the port is not valid, it returns
// the entire input as host, and it doesn't check the validity of the host.
// Unlike net.SplitHostPort, but per RFC 3986, it requires ports to be numeric.
@ -686,6 +707,12 @@ func (p *OAuthProxy) isAllowedRoute(req *http.Request) bool {
return false
}
// isForwardedRequest is used to check if X-Forwarded-Host header exists or not
func isForwardedRequest(req *http.Request, reverseProxy bool) bool {
isForwarded := req.Host != util.GetRequestHost(req)
return isForwarded && reverseProxy
}
// See https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=en
var noCacheHeaders = map[string]string{
"Expires": time.Unix(0, 0).Format(time.RFC1123),