git.iko.soy/typeable/oauth2-proxy
on master help sign in
Feature: Allowing relative redirect url though an option (#2183)

* Adding relative redirect url option * Updating CHANGELOG.md * tests: adding unit test for getOAuthRedirectURI --------- Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk>

commit601477a52cf7d4eb4b8e4c36b916d6fbeb1a3468 authoraxel7083 <42176370+axel7083@users.noreply.github.com> dateWed 25 Oct 2023, 11:25 (3 years ago) parent464f3bc
5 files changed+105−11
CHANGELOG.md+3−1 docs/docs/configuration/overview.md+1 oauthproxy.go+3−1 oauthproxy_test.go+87 pkg/apis/options/options.go+11−9
CHANGELOG.md+3−1
@@ -7,10 +7,12 @@
77## Breaking Changes
88
99## Changes since v7.5.1
10+
1011- [#2128](https://github.com/oauth2-proxy/oauth2-proxy/pull/2128) Update dependencies (@vllvll)
1112- [#2274](https://github.com/oauth2-proxy/oauth2-proxy/pull/2274) Upgrade golang.org/x/net to v0.17.0 (@pierluigilenoci)
1213- [#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+-
1416# V7.5.1
1517
1618## 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/
165165| `--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 |
166166| `--redeem-url` | string | Token redemption endpoint | |
167167| `--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.` | |
168169| `--redis-cluster-connection-urls` | string \| list | List of Redis cluster connection URLs (e.g. `redis://HOST[:PORT]`). Used in conjunction with `--redis-use-cluster` | |
169170| `--redis-connection-url` | string | URL of redis server for redis session storage (e.g. `redis://HOST[:PORT]`) | |
170171| `--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 {
8686 allowedRoutes []allowedRoute
8787 apiRoutes []apiRoute
8888 redirectURL *url.URL // the url to receive requests at
89+ relativeRedirectURL bool
8990 whitelistDomains []string
9091 provider providers.Provider
9192 sessionStore sessionsapi.SessionStore
@@ -216,6 +217,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
216217 provider: provider,
217218 sessionStore: sessionStore,
218219 redirectURL: redirectURL,
220+ relativeRedirectURL: opts.RelativeRedirectURL,
219221 apiRoutes: apiRoutes,
220222 allowedRoutes: allowedRoutes,
221223 whitelistDomains: opts.WhitelistDomains,
@@ -1018,7 +1020,7 @@ func prepareNoCacheMiddleware(next http.Handler) http.Handler {
10181020// This is usually the OAuthProxy callback URL.
10191021func (p *OAuthProxy) getOAuthRedirectURI(req *http.Request) string {
10201022 // if `p.redirectURL` already has a host, return it
1021− if p.redirectURL.Host != "" {
1023+ if p.relativeRedirectURL || p.redirectURL.Host != "" {
10221024 return p.redirectURL.String()
10231025 }
10241026
oauthproxy_test.go+87
@@ -3257,3 +3257,90 @@ func TestAuthOnlyAllowedEmails(t *testing.T) {
32573257 })
32583258 }
32593259}
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 {
1818// Options holds Configuration Options that can be set by Command Line Flag,
1919// or Config File
2020type Options struct {
21− ProxyPrefix string `flag:"proxy-prefix" cfg:"proxy_prefix"`
22− PingPath string `flag:"ping-path" cfg:"ping_path"`
23− PingUserAgent string `flag:"ping-user-agent" cfg:"ping_user_agent"`
24− ReadyPath string `flag:"ready-path" cfg:"ready_path"`
25− ReverseProxy bool `flag:"reverse-proxy" cfg:"reverse_proxy"`
26− RealClientIPHeader string `flag:"real-client-ip-header" cfg:"real_client_ip_header"`
27− TrustedIPs []string `flag:"trusted-ip" cfg:"trusted_ips"`
28− ForceHTTPS bool `flag:"force-https" cfg:"force_https"`
29− RawRedirectURL string `flag:"redirect-url" cfg:"redirect_url"`
21+ ProxyPrefix string `flag:"proxy-prefix" cfg:"proxy_prefix"`
22+ PingPath string `flag:"ping-path" cfg:"ping_path"`
23+ PingUserAgent string `flag:"ping-user-agent" cfg:"ping_user_agent"`
24+ ReadyPath string `flag:"ready-path" cfg:"ready_path"`
25+ ReverseProxy bool `flag:"reverse-proxy" cfg:"reverse_proxy"`
26+ RealClientIPHeader string `flag:"real-client-ip-header" cfg:"real_client_ip_header"`
27+ TrustedIPs []string `flag:"trusted-ip" cfg:"trusted_ips"`
28+ ForceHTTPS bool `flag:"force-https" cfg:"force_https"`
29+ RawRedirectURL string `flag:"redirect-url" cfg:"redirect_url"`
30+ RelativeRedirectURL bool `flag:"relative-redirect-url" cfg:"relative_redirect_url"`
3031
3132 AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"`
3233 EmailDomains []string `flag:"email-domain" cfg:"email_domains"`
@@ -117,6 +118,7 @@ func NewFlagSet() *pflag.FlagSet {
117118 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.")
118119 flagSet.Bool("force-https", false, "force HTTPS redirect for HTTP requests")
119120 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.")
120122 flagSet.StringSlice("skip-auth-regex", []string{}, "(DEPRECATED for --skip-auth-route) bypass authentication for requests path's that match (may be given multiple times)")
121123 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")
122124 flagSet.StringSlice("api-route", []string{}, "return HTTP 401 instead of redirecting to authentication server if token is not valid. Format: path_regex")