commit
fa2545636b
@ -7,6 +7,8 @@
|
|||||||
- Implement token refreshing in OIDC provider
|
- Implement token refreshing in OIDC provider
|
||||||
- Split cookies larger than 4k limit into multiple cookies
|
- Split cookies larger than 4k limit into multiple cookies
|
||||||
- Implement token validation in OIDC provider
|
- Implement token validation in OIDC provider
|
||||||
|
- [#15](https://github.com/pusher/oauth2_proxy/pull/21) WhitelistDomains (@joelspeed)
|
||||||
|
- Add `--whitelist-domain` flag to allow redirection to approved domains after OAuth flow
|
||||||
- [#21](https://github.com/pusher/oauth2_proxy/pull/21) Docker Improvement (@yaegashi)
|
- [#21](https://github.com/pusher/oauth2_proxy/pull/21) Docker Improvement (@yaegashi)
|
||||||
- Move Docker base image from debian to alpine
|
- Move Docker base image from debian to alpine
|
||||||
- Install ca-certificates in docker image
|
- Install ca-certificates in docker image
|
||||||
|
@ -237,8 +237,11 @@ Usage of oauth2_proxy:
|
|||||||
-upstream value: the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path
|
-upstream value: the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path
|
||||||
-validate-url string: Access token validation endpoint
|
-validate-url string: Access token validation endpoint
|
||||||
-version: print version string
|
-version: print version string
|
||||||
|
-whitelist-domain: allowed domains for redirection after authentication. Prefix domain with a . to allow subdomains (eg .example.com)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note, when using the `whitelist-domain` option, any domain prefixed with a `.` will allow any subdomain of the specified domain as a valid redirect URL.
|
||||||
|
|
||||||
See below for provider specific options
|
See below for provider specific options
|
||||||
|
|
||||||
### Upstreams Configuration
|
### Upstreams Configuration
|
||||||
|
2
main.go
2
main.go
@ -18,6 +18,7 @@ func main() {
|
|||||||
flagSet := flag.NewFlagSet("oauth2_proxy", flag.ExitOnError)
|
flagSet := flag.NewFlagSet("oauth2_proxy", flag.ExitOnError)
|
||||||
|
|
||||||
emailDomains := StringArray{}
|
emailDomains := StringArray{}
|
||||||
|
whitelistDomains := StringArray{}
|
||||||
upstreams := StringArray{}
|
upstreams := StringArray{}
|
||||||
skipAuthRegex := StringArray{}
|
skipAuthRegex := StringArray{}
|
||||||
googleGroups := StringArray{}
|
googleGroups := StringArray{}
|
||||||
@ -46,6 +47,7 @@ func main() {
|
|||||||
flagSet.Duration("flush-interval", time.Duration(1)*time.Second, "period between response flushing when streaming responses")
|
flagSet.Duration("flush-interval", time.Duration(1)*time.Second, "period between response flushing when streaming responses")
|
||||||
|
|
||||||
flagSet.Var(&emailDomains, "email-domain", "authenticate emails with the specified domain (may be given multiple times). Use * to authenticate any email")
|
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-domain", "allowed domains for redirection after authentication. Prefix domain with a . to allow subdomains (eg .example.com)")
|
||||||
flagSet.String("azure-tenant", "common", "go to a tenant-specific or common (tenant-independent) endpoint.")
|
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-org", "", "restrict logins to members of this organisation")
|
||||||
flagSet.String("github-team", "", "restrict logins to members of this team")
|
flagSet.String("github-team", "", "restrict logins to members of this team")
|
||||||
|
@ -70,6 +70,7 @@ type OAuthProxy struct {
|
|||||||
AuthOnlyPath string
|
AuthOnlyPath string
|
||||||
|
|
||||||
redirectURL *url.URL // the url to receive requests at
|
redirectURL *url.URL // the url to receive requests at
|
||||||
|
whitelistDomains []string
|
||||||
provider providers.Provider
|
provider providers.Provider
|
||||||
ProxyPrefix string
|
ProxyPrefix string
|
||||||
SignInMessage string
|
SignInMessage string
|
||||||
@ -224,6 +225,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
|
|||||||
provider: opts.provider,
|
provider: opts.provider,
|
||||||
serveMux: serveMux,
|
serveMux: serveMux,
|
||||||
redirectURL: redirectURL,
|
redirectURL: redirectURL,
|
||||||
|
whitelistDomains: opts.WhitelistDomains,
|
||||||
skipAuthRegex: opts.SkipAuthRegex,
|
skipAuthRegex: opts.SkipAuthRegex,
|
||||||
skipAuthPreflight: opts.SkipAuthPreflight,
|
skipAuthPreflight: opts.SkipAuthPreflight,
|
||||||
compiledRegex: opts.CompiledRegex,
|
compiledRegex: opts.CompiledRegex,
|
||||||
@ -567,7 +569,7 @@ func (p *OAuthProxy) GetRedirect(req *http.Request) (redirect string, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
redirect = req.Form.Get("rd")
|
redirect = req.Form.Get("rd")
|
||||||
if redirect == "" || !strings.HasPrefix(redirect, "/") || strings.HasPrefix(redirect, "//") {
|
if !p.IsValidRedirect(redirect) {
|
||||||
redirect = req.URL.Path
|
redirect = req.URL.Path
|
||||||
if strings.HasPrefix(redirect, p.ProxyPrefix) {
|
if strings.HasPrefix(redirect, p.ProxyPrefix) {
|
||||||
redirect = "/"
|
redirect = "/"
|
||||||
@ -577,6 +579,27 @@ func (p *OAuthProxy) GetRedirect(req *http.Request) (redirect string, err error)
|
|||||||
return
|
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://") || strings.HasPrefix(redirect, "https://"):
|
||||||
|
redirectURL, err := url.Parse(redirect)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, domain := range p.whitelistDomains {
|
||||||
|
if (redirectURL.Host == domain) || (strings.HasPrefix(domain, ".") && strings.HasSuffix(redirectURL.Host, domain)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IsWhitelistedRequest is used to check if auth should be skipped for this request
|
// IsWhitelistedRequest is used to check if auth should be skipped for this request
|
||||||
func (p *OAuthProxy) IsWhitelistedRequest(req *http.Request) (ok bool) {
|
func (p *OAuthProxy) IsWhitelistedRequest(req *http.Request) (ok bool) {
|
||||||
isPreflightRequestAllowed := p.skipAuthPreflight && req.Method == "OPTIONS"
|
isPreflightRequestAllowed := p.skipAuthPreflight && req.Method == "OPTIONS"
|
||||||
@ -713,7 +736,7 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(redirect, "/") || strings.HasPrefix(redirect, "//") {
|
if !p.IsValidRedirect(redirect) {
|
||||||
redirect = "/"
|
redirect = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,57 @@ func TestRobotsTxt(t *testing.T) {
|
|||||||
assert.Equal(t, "User-agent: *\nDisallow: /", rw.Body.String())
|
assert.Equal(t, "User-agent: *\nDisallow: /", rw.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsValidRedirect(t *testing.T) {
|
||||||
|
opts := NewOptions()
|
||||||
|
opts.ClientID = "bazquux"
|
||||||
|
opts.ClientSecret = "foobar"
|
||||||
|
opts.CookieSecret = "xyzzyplugh"
|
||||||
|
// Should match domains that are exactly foo.bar and any subdomain of bar.foo
|
||||||
|
opts.WhitelistDomains = []string{"foo.bar", ".bar.foo"}
|
||||||
|
opts.Validate()
|
||||||
|
|
||||||
|
proxy := NewOAuthProxy(opts, func(string) bool { return true })
|
||||||
|
|
||||||
|
noRD := proxy.IsValidRedirect("")
|
||||||
|
assert.Equal(t, false, noRD)
|
||||||
|
|
||||||
|
singleSlash := proxy.IsValidRedirect("/redirect")
|
||||||
|
assert.Equal(t, true, singleSlash)
|
||||||
|
|
||||||
|
doubleSlash := proxy.IsValidRedirect("//redirect")
|
||||||
|
assert.Equal(t, false, doubleSlash)
|
||||||
|
|
||||||
|
validHTTP := proxy.IsValidRedirect("http://foo.bar/redirect")
|
||||||
|
assert.Equal(t, true, validHTTP)
|
||||||
|
|
||||||
|
validHTTPS := proxy.IsValidRedirect("https://foo.bar/redirect")
|
||||||
|
assert.Equal(t, true, validHTTPS)
|
||||||
|
|
||||||
|
invalidHTTPSubdomain := proxy.IsValidRedirect("http://baz.foo.bar/redirect")
|
||||||
|
assert.Equal(t, false, invalidHTTPSubdomain)
|
||||||
|
|
||||||
|
invalidHTTPSSubdomain := proxy.IsValidRedirect("https://baz.foo.bar/redirect")
|
||||||
|
assert.Equal(t, false, invalidHTTPSSubdomain)
|
||||||
|
|
||||||
|
validHTTPSubdomain := proxy.IsValidRedirect("http://baz.bar.foo/redirect")
|
||||||
|
assert.Equal(t, true, validHTTPSubdomain)
|
||||||
|
|
||||||
|
validHTTPSSubdomain := proxy.IsValidRedirect("https://baz.bar.foo/redirect")
|
||||||
|
assert.Equal(t, true, validHTTPSSubdomain)
|
||||||
|
|
||||||
|
invalidHTTP1 := proxy.IsValidRedirect("http://foo.bar.evil.corp/redirect")
|
||||||
|
assert.Equal(t, false, invalidHTTP1)
|
||||||
|
|
||||||
|
invalidHTTPS1 := proxy.IsValidRedirect("https://foo.bar.evil.corp/redirect")
|
||||||
|
assert.Equal(t, false, invalidHTTPS1)
|
||||||
|
|
||||||
|
invalidHTTP2 := proxy.IsValidRedirect("http://evil.corp/redirect?rd=foo.bar")
|
||||||
|
assert.Equal(t, false, invalidHTTP2)
|
||||||
|
|
||||||
|
invalidHTTPS2 := proxy.IsValidRedirect("https://evil.corp/redirect?rd=foo.bar")
|
||||||
|
assert.Equal(t, false, invalidHTTPS2)
|
||||||
|
}
|
||||||
|
|
||||||
type TestProvider struct {
|
type TestProvider struct {
|
||||||
*providers.ProviderData
|
*providers.ProviderData
|
||||||
EmailAddress string
|
EmailAddress string
|
||||||
|
@ -33,6 +33,7 @@ type Options struct {
|
|||||||
AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"`
|
AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"`
|
||||||
AzureTenant string `flag:"azure-tenant" cfg:"azure_tenant"`
|
AzureTenant string `flag:"azure-tenant" cfg:"azure_tenant"`
|
||||||
EmailDomains []string `flag:"email-domain" cfg:"email_domains"`
|
EmailDomains []string `flag:"email-domain" cfg:"email_domains"`
|
||||||
|
WhitelistDomains []string `flag:"whitelist-domain" cfg:"whitelist_domains" env:"OAUTH2_PROXY_WHITELIST_DOMAINS"`
|
||||||
GitHubOrg string `flag:"github-org" cfg:"github_org"`
|
GitHubOrg string `flag:"github-org" cfg:"github_org"`
|
||||||
GitHubTeam string `flag:"github-team" cfg:"github_team"`
|
GitHubTeam string `flag:"github-team" cfg:"github_team"`
|
||||||
GoogleGroups []string `flag:"google-group" cfg:"google_group"`
|
GoogleGroups []string `flag:"google-group" cfg:"google_group"`
|
||||||
|
Loading…
Reference in New Issue
Block a user