From 04342602b5678fa0bbaa9f7fb5d5259b10bef279 Mon Sep 17 00:00:00 2001 From: Victor Boivie Date: Fri, 29 Sep 2017 11:41:10 +0200 Subject: [PATCH 1/2] Allow redirect URL to be provided as ?rd=XXX In addition to the X-Auth-Request-Redirect header, which still has precedence. Fixes #427 --- oauthproxy.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/oauthproxy.go b/oauthproxy.go index 91608acc3..8d3974ad2 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -367,6 +367,8 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code redirect_url := req.URL.RequestURI() if req.Header.Get("X-Auth-Request-Redirect") != "" { redirect_url = req.Header.Get("X-Auth-Request-Redirect") + } else if req.URL.Query().Get("rd") != "" { + redirect_url = req.URL.Query().Get("rd") } if redirect_url == p.SignInPath { redirect_url = "/" From 9333af98ff1a5959a682350e690b402e9531be29 Mon Sep 17 00:00:00 2001 From: Victor Boivie Date: Fri, 29 Sep 2017 12:58:48 +0200 Subject: [PATCH 2/2] Add whitelist of redirect domains Allows redirection to URLs on other domains. Specify one or several domains (including port number). You can also specify "*" if you want to allow all redirect domains. Fixes #399 --- main.go | 2 ++ oauthproxy.go | 23 +++++++++++++++++++---- options.go | 1 + 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index b9d9c96c1..cbaa4f4d9 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ func main() { upstreams := StringArray{} skipAuthRegex := StringArray{} googleGroups := StringArray{} + redirectDomains := StringArray{} config := flagSet.String("config", "", "path to config file") showVersion := flagSet.Bool("version", false, "print version string") @@ -30,6 +31,7 @@ func main() { flagSet.String("tls-cert", "", "path to certificate file") flagSet.String("tls-key", "", "path to private key file") flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"") + flagSet.Var(&redirectDomains, "redirect-domain", "Allow redirects on successful login to this domain (may be given multiple times)") flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)") flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path") flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream") diff --git a/oauthproxy.go b/oauthproxy.go index 8d3974ad2..c5a3d1350 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -72,6 +72,7 @@ type OAuthProxy struct { compiledRegex []*regexp.Regexp templates *template.Template Footer string + RedirectDomains []string } type UpstreamProxy struct { @@ -210,6 +211,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy { CookieCipher: cipher, templates: loadTemplates(opts.CustomTemplatesDir), Footer: opts.Footer, + RedirectDomains: opts.RedirectDomains, } } @@ -418,9 +420,6 @@ func (p *OAuthProxy) GetRedirect(req *http.Request) (redirect string, err error) } redirect = req.Form.Get("rd") - if redirect == "" || !strings.HasPrefix(redirect, "/") || strings.HasPrefix(redirect, "//") { - redirect = "/" - } return } @@ -513,6 +512,20 @@ func (p *OAuthProxy) OAuthStart(rw http.ResponseWriter, req *http.Request) { http.Redirect(rw, req, p.provider.GetLoginURL(redirectURI, fmt.Sprintf("%v:%v", nonce, redirect)), 302) } +func (p *OAuthProxy) isValidRedirectDomain(domain string) bool { + if domain == "" { + // No domain - an absolute URL - always permitted. + return true + } + + for _, validDomain := range p.RedirectDomains { + if validDomain == "*" || domain == validDomain { + return true + } + } + return false +} + func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) { remoteAddr := getRemoteAddr(req) @@ -554,7 +567,9 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) { return } - if !strings.HasPrefix(redirect, "/") || strings.HasPrefix(redirect, "//") { + u, err := url.Parse(redirect) + if err != nil || !strings.HasPrefix(u.Path, "/") || !p.isValidRedirectDomain(u.Host) { + log.Printf("redirect URL '%s' not permitted - redirecting to /", redirect) redirect = "/" } diff --git a/options.go b/options.go index d884f28b7..8a9ed5cba 100644 --- a/options.go +++ b/options.go @@ -41,6 +41,7 @@ type Options struct { DisplayHtpasswdForm bool `flag:"display-htpasswd-form" cfg:"display_htpasswd_form"` CustomTemplatesDir string `flag:"custom-templates-dir" cfg:"custom_templates_dir"` Footer string `flag:"footer" cfg:"footer"` + RedirectDomains []string `flag:"redirect-domain" cfg:"redirect_domains"` CookieName string `flag:"cookie-name" cfg:"cookie_name" env:"OAUTH2_PROXY_COOKIE_NAME"` CookieSecret string `flag:"cookie-secret" cfg:"cookie_secret" env:"OAUTH2_PROXY_COOKIE_SECRET"`