diff --git a/main.go b/main.go index 5cfa1f5..9b70da2 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,7 @@ func main() { flagSet := flag.NewFlagSet("oauth2_proxy", flag.ExitOnError) emailDomains := StringArray{} + whitelistDomains := StringArray{} upstreams := StringArray{} skipAuthRegex := StringArray{} googleGroups := StringArray{} @@ -45,6 +46,7 @@ func main() { flagSet.Bool("ssl-insecure-skip-verify", false, "skip validation of certificates presented when using HTTPS") flagSet.Var(&emailDomains, "email-domain", "authenticate emails with the specified domain (may be given multiple times). Use * to authenticate any email") + flagSet.Var(&whitelistDomains, "whitelist-domains", "allowed domains for redirection after authentication") flagSet.String("azure-tenant", "common", "go to a tenant-specific or common (tenant-independent) endpoint.") flagSet.String("github-org", "", "restrict logins to members of this organisation") flagSet.String("github-team", "", "restrict logins to members of this team") diff --git a/oauthproxy.go b/oauthproxy.go index 64503cb..8029eab 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -68,6 +68,7 @@ type OAuthProxy struct { AuthOnlyPath string redirectURL *url.URL // the url to receive requests at + whitelistDomains []string provider providers.Provider ProxyPrefix string SignInMessage string @@ -220,6 +221,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy { provider: opts.provider, serveMux: serveMux, redirectURL: redirectURL, + whitelistDomains: opts.WhitelistDomains, skipAuthRegex: opts.SkipAuthRegex, skipAuthPreflight: opts.SkipAuthPreflight, compiledRegex: opts.CompiledRegex, @@ -563,7 +565,7 @@ func (p *OAuthProxy) GetRedirect(req *http.Request) (redirect string, err error) } redirect = req.Form.Get("rd") - if redirect == "" || !strings.HasPrefix(redirect, "/") || strings.HasPrefix(redirect, "//") { + if !p.IsValidRedirect(redirect) { redirect = req.URL.Path if strings.HasPrefix(redirect, p.ProxyPrefix) { redirect = "/" @@ -573,6 +575,34 @@ func (p *OAuthProxy) GetRedirect(req *http.Request) (redirect string, err error) return } +// IsValidRedirect checks whether the redirect URL is whitelisted +func (p *OAuthProxy) IsValidRedirect(redirect string) bool { + switch { + case strings.HasPrefix(redirect, "/") && !strings.HasPrefix(redirect, "//"): + return true + case strings.HasPrefix(redirect, "http://"): + redirect = strings.TrimPrefix(redirect, "http://") + redirect = strings.Split(redirect, "/")[0] + for _, domain := range p.whitelistDomains { + if strings.HasSuffix(redirect, domain) { + return true + } + } + return false + case strings.HasPrefix(redirect, "https://"): + redirect = strings.TrimPrefix(redirect, "https://") + redirect = strings.Split(redirect, "/")[0] + for _, domain := range p.whitelistDomains { + if strings.HasSuffix(redirect, domain) { + return true + } + } + return false + default: + return false + } +} + // IsWhitelistedRequest is used to check if auth should be skipped for this request func (p *OAuthProxy) IsWhitelistedRequest(req *http.Request) (ok bool) { isPreflightRequestAllowed := p.skipAuthPreflight && req.Method == "OPTIONS" @@ -709,7 +739,7 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) { return } - if !strings.HasPrefix(redirect, "/") || strings.HasPrefix(redirect, "//") { + if !p.IsValidRedirect(redirect) { redirect = "/" } diff --git a/options.go b/options.go index 9696144..3306567 100644 --- a/options.go +++ b/options.go @@ -33,6 +33,7 @@ type Options struct { AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"` AzureTenant string `flag:"azure-tenant" cfg:"azure_tenant"` EmailDomains []string `flag:"email-domain" cfg:"email_domains"` + WhitelistDomains []string `flag:"whitelist-domains" cfg:"whitelist_domains"` GitHubOrg string `flag:"github-org" cfg:"github_org"` GitHubTeam string `flag:"github-team" cfg:"github_team"` GoogleGroups []string `flag:"google-group" cfg:"google_group"`