git.iko.soy/typeable/oauth2-proxy
on master help sign in
Feature: Allowing relative redirect url though an option (#2183)
601477aaxel7083
CHANGELOG.md+3−1
@@ -7,10 +7,12 @@
7## Breaking Changes
7## Breaking Changes
8
8
9## Changes since v7.5.1
9## Changes since v7.5.1
10+
10- [#2128](https://github.com/oauth2-proxy/oauth2-proxy/pull/2128) Update dependencies (@vllvll)
11- [#2128](https://github.com/oauth2-proxy/oauth2-proxy/pull/2128) Update dependencies (@vllvll)
11- [#2274](https://github.com/oauth2-proxy/oauth2-proxy/pull/2274) Upgrade golang.org/x/net to v0.17.0 (@pierluigilenoci)
12- [#2274](https://github.com/oauth2-proxy/oauth2-proxy/pull/2274) Upgrade golang.org/x/net to v0.17.0 (@pierluigilenoci)
12- [#2282](https://github.com/oauth2-proxy/oauth2-proxy/pull/2282) Fixed checking Google Groups membership using Google Application Credentials (@kvanzuijlen)
13- [#2282](https://github.com/oauth2-proxy/oauth2-proxy/pull/2282) Fixed checking Google Groups membership using Google Application Credentials (@kvanzuijlen)
13−
14+- [#2183](https://github.com/oauth2-proxy/oauth2-proxy/pull/2183) Allowing relative redirect url though an option
15+-
14# V7.5.1
16# V7.5.1
15
17
16## Release Highlights
18## Release Highlights
docs/docs/configuration/overview.md+1
@@ -165,6 +165,7 @@ An example [oauth2-proxy.cfg](https://github.com/oauth2-proxy/oauth2-proxy/blob/
165| `--real-client-ip-header` | string | Header used to determine the real IP of the client, requires `--reverse-proxy` to be set (one of: X-Forwarded-For, X-Real-IP, or X-ProxyUser-IP) | X-Real-IP |
165| `--real-client-ip-header` | string | Header used to determine the real IP of the client, requires `--reverse-proxy` to be set (one of: X-Forwarded-For, X-Real-IP, or X-ProxyUser-IP) | X-Real-IP |
166| `--redeem-url` | string | Token redemption endpoint | |
166| `--redeem-url` | string | Token redemption endpoint | |
167| `--redirect-url` | string | the OAuth Redirect URL, e.g. `"https://internalapp.yourcompany.com/oauth2/callback"` | |
167| `--redirect-url` | string | the OAuth Redirect URL, e.g. `"https://internalapp.yourcompany.com/oauth2/callback"` | |
168+| `--relative-redirect-url` | bool | allow relative OAuth Redirect URL.` | |
168| `--redis-cluster-connection-urls` | string \| list | List of Redis cluster connection URLs (e.g. `redis://HOST[:PORT]`). Used in conjunction with `--redis-use-cluster` | |
169| `--redis-cluster-connection-urls` | string \| list | List of Redis cluster connection URLs (e.g. `redis://HOST[:PORT]`). Used in conjunction with `--redis-use-cluster` | |
169| `--redis-connection-url` | string | URL of redis server for redis session storage (e.g. `redis://HOST[:PORT]`) | |
170| `--redis-connection-url` | string | URL of redis server for redis session storage (e.g. `redis://HOST[:PORT]`) | |
170| `--redis-insecure-skip-tls-verify` | bool | skip TLS verification when connecting to Redis | false |
171| `--redis-insecure-skip-tls-verify` | bool | skip TLS verification when connecting to Redis | false |
oauthproxy.go+3−1
@@ -86,6 +86,7 @@ type OAuthProxy struct {
86 allowedRoutes []allowedRoute
86 allowedRoutes []allowedRoute
87 apiRoutes []apiRoute
87 apiRoutes []apiRoute
88 redirectURL *url.URL // the url to receive requests at
88 redirectURL *url.URL // the url to receive requests at
89+ relativeRedirectURL bool
89 whitelistDomains []string
90 whitelistDomains []string
90 provider providers.Provider
91 provider providers.Provider
91 sessionStore sessionsapi.SessionStore
92 sessionStore sessionsapi.SessionStore
@@ -216,6 +217,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
216 provider: provider,
217 provider: provider,
217 sessionStore: sessionStore,
218 sessionStore: sessionStore,
218 redirectURL: redirectURL,
219 redirectURL: redirectURL,
220+ relativeRedirectURL: opts.RelativeRedirectURL,
219 apiRoutes: apiRoutes,
221 apiRoutes: apiRoutes,
220 allowedRoutes: allowedRoutes,
222 allowedRoutes: allowedRoutes,
221 whitelistDomains: opts.WhitelistDomains,
223 whitelistDomains: opts.WhitelistDomains,
@@ -1018,7 +1020,7 @@ func prepareNoCacheMiddleware(next http.Handler) http.Handler {
1018// This is usually the OAuthProxy callback URL.
1020// This is usually the OAuthProxy callback URL.
1019func (p *OAuthProxy) getOAuthRedirectURI(req *http.Request) string {
1021func (p *OAuthProxy) getOAuthRedirectURI(req *http.Request) string {
1020 // if `p.redirectURL` already has a host, return it
1022 // if `p.redirectURL` already has a host, return it
1021− if p.redirectURL.Host != "" {
1023+ if p.relativeRedirectURL || p.redirectURL.Host != "" {
1022 return p.redirectURL.String()
1024 return p.redirectURL.String()
1023 }
1025 }
1024
1026
oauthproxy_test.go+87
@@ -3257,3 +3257,90 @@ func TestAuthOnlyAllowedEmails(t *testing.T) {
3257 })
3257 })
3258 }
3258 }
3259}
3259}
3260+
3261+func TestGetOAuthRedirectURI(t *testing.T) {
3262+ tests := []struct {
3263+ name string
3264+ setupOpts func(*options.Options) *options.Options
3265+ req *http.Request
3266+ want string
3267+ }{
3268+ {
3269+ name: "redirect with https schema",
3270+ setupOpts: func(baseOpts *options.Options) *options.Options {
3271+ return baseOpts
3272+ },
3273+ req: &http.Request{
3274+ Host: "example",
3275+ URL: &url.URL{
3276+ Scheme: schemeHTTPS,
3277+ },
3278+ },
3279+ want: "https://example/oauth2/callback",
3280+ },
3281+ {
3282+ name: "redirect with http schema",
3283+ setupOpts: func(baseOpts *options.Options) *options.Options {
3284+ baseOpts.Cookie.Secure = false
3285+ return baseOpts
3286+ },
3287+ req: &http.Request{
3288+ Host: "example",
3289+ URL: &url.URL{
3290+ Scheme: schemeHTTP,
3291+ },
3292+ },
3293+ want: "http://example/oauth2/callback",
3294+ },
3295+ {
3296+ name: "relative redirect url",
3297+ setupOpts: func(baseOpts *options.Options) *options.Options {
3298+ baseOpts.RelativeRedirectURL = true
3299+ return baseOpts
3300+ },
3301+ req: &http.Request{},
3302+ want: "/oauth2/callback",
3303+ },
3304+ {
3305+ name: "proxy prefix",
3306+ setupOpts: func(baseOpts *options.Options) *options.Options {
3307+ baseOpts.ProxyPrefix = "/prefix"
3308+ return baseOpts
3309+ },
3310+ req: &http.Request{
3311+ Host: "example",
3312+ URL: &url.URL{
3313+ Scheme: schemeHTTP,
3314+ },
3315+ },
3316+ want: "https://example/prefix/callback",
3317+ },
3318+ {
3319+ name: "proxy prefix with relative redirect",
3320+ setupOpts: func(baseOpts *options.Options) *options.Options {
3321+ baseOpts.ProxyPrefix = "/prefix"
3322+ baseOpts.RelativeRedirectURL = true
3323+ return baseOpts
3324+ },
3325+ req: &http.Request{
3326+ Host: "example",
3327+ URL: &url.URL{
3328+ Scheme: schemeHTTP,
3329+ },
3330+ },
3331+ want: "/prefix/callback",
3332+ },
3333+ }
3334+ for _, tt := range tests {
3335+ t.Run(tt.name, func(t *testing.T) {
3336+ baseOpts := baseTestOptions()
3337+ err := validation.Validate(baseOpts)
3338+ assert.NoError(t, err)
3339+
3340+ proxy, err := NewOAuthProxy(tt.setupOpts(baseOpts), func(string) bool { return true })
3341+ assert.NoError(t, err)
3342+
3343+ assert.Equalf(t, tt.want, proxy.getOAuthRedirectURI(tt.req), "getOAuthRedirectURI(%v)", tt.req)
3344+ })
3345+ }
3346+}
pkg/apis/options/options.go+11−9
@@ -18,15 +18,16 @@ type SignatureData struct {
18// Options holds Configuration Options that can be set by Command Line Flag,
18// Options holds Configuration Options that can be set by Command Line Flag,
19// or Config File
19// or Config File
20type Options struct {
20type Options struct {
21− ProxyPrefix string `flag:"proxy-prefix" cfg:"proxy_prefix"`
21+ ProxyPrefix string `flag:"proxy-prefix" cfg:"proxy_prefix"`
22− PingPath string `flag:"ping-path" cfg:"ping_path"`
22+ PingPath string `flag:"ping-path" cfg:"ping_path"`
23− PingUserAgent string `flag:"ping-user-agent" cfg:"ping_user_agent"`
23+ PingUserAgent string `flag:"ping-user-agent" cfg:"ping_user_agent"`
24− ReadyPath string `flag:"ready-path" cfg:"ready_path"`
24+ ReadyPath string `flag:"ready-path" cfg:"ready_path"`
25− ReverseProxy bool `flag:"reverse-proxy" cfg:"reverse_proxy"`
25+ ReverseProxy bool `flag:"reverse-proxy" cfg:"reverse_proxy"`
26− RealClientIPHeader string `flag:"real-client-ip-header" cfg:"real_client_ip_header"`
26+ RealClientIPHeader string `flag:"real-client-ip-header" cfg:"real_client_ip_header"`
27− TrustedIPs []string `flag:"trusted-ip" cfg:"trusted_ips"`
27+ TrustedIPs []string `flag:"trusted-ip" cfg:"trusted_ips"`
28− ForceHTTPS bool `flag:"force-https" cfg:"force_https"`
28+ ForceHTTPS bool `flag:"force-https" cfg:"force_https"`
29− RawRedirectURL string `flag:"redirect-url" cfg:"redirect_url"`
29+ RawRedirectURL string `flag:"redirect-url" cfg:"redirect_url"`
30+ RelativeRedirectURL bool `flag:"relative-redirect-url" cfg:"relative_redirect_url"`
30
31
31 AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"`
32 AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"`
32 EmailDomains []string `flag:"email-domain" cfg:"email_domains"`
33 EmailDomains []string `flag:"email-domain" cfg:"email_domains"`
@@ -117,6 +118,7 @@ func NewFlagSet() *pflag.FlagSet {
117 flagSet.StringSlice("trusted-ip", []string{}, "list of IPs or CIDR ranges to allow to bypass authentication. WARNING: trusting by IP has inherent security flaws, read the configuration documentation for more information.")
118 flagSet.StringSlice("trusted-ip", []string{}, "list of IPs or CIDR ranges to allow to bypass authentication. WARNING: trusting by IP has inherent security flaws, read the configuration documentation for more information.")
118 flagSet.Bool("force-https", false, "force HTTPS redirect for HTTP requests")
119 flagSet.Bool("force-https", false, "force HTTPS redirect for HTTP requests")
119 flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"")
120 flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"")
121+ flagSet.Bool("relative-redirect-url", false, "allow relative OAuth Redirect URL.")
120 flagSet.StringSlice("skip-auth-regex", []string{}, "(DEPRECATED for --skip-auth-route) bypass authentication for requests path's that match (may be given multiple times)")
122 flagSet.StringSlice("skip-auth-regex", []string{}, "(DEPRECATED for --skip-auth-route) bypass authentication for requests path's that match (may be given multiple times)")
121 flagSet.StringSlice("skip-auth-route", []string{}, "bypass authentication for requests that match the method & path. Format: method=path_regex OR method!=path_regex. For all methods: path_regex OR !=path_regex")
123 flagSet.StringSlice("skip-auth-route", []string{}, "bypass authentication for requests that match the method & path. Format: method=path_regex OR method!=path_regex. For all methods: path_regex OR !=path_regex")
122 flagSet.StringSlice("api-route", []string{}, "return HTTP 401 instead of redirecting to authentication server if token is not valid. Format: path_regex")
124 flagSet.StringSlice("api-route", []string{}, "return HTTP 401 instead of redirecting to authentication server if token is not valid. Format: path_regex")