From ebae065b115fa60b8180930d366cdd0e4395968e Mon Sep 17 00:00:00 2001 From: Jehiah Czebotar Date: Tue, 17 Mar 2015 16:25:19 -0400 Subject: [PATCH] make redirect_uri optional --- README.md | 3 +-- contrib/google_auth_proxy.cfg.example | 1 + oauthproxy.go | 36 ++++++++++++++++++++------- options.go | 2 +- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 7fa4648..173879b 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,6 @@ The command line to run `google_auth_proxy` would look like this: ```bash ./google_auth_proxy \ - --redirect-url="https://internal.yourcompany.com/oauth2/callback" \ --google-apps-domain="yourcompany.com" \ --upstream=http://127.0.0.1:8080/ \ --cookie-secret=... \ @@ -134,4 +133,4 @@ Google Auth Proxy responds directly to the following endpoints. All other endpoi * /ping - returns an 200 OK response * /oauth2/sign_in - the login page, which also doubles as a sign out page (it clears cookies) * /oauth2/start - a URL that will redirect to start the OAuth cycle -* /oauth2/callback - the URL used at the end of the OAuth cycle +* /oauth2/callback - the URL used at the end of the OAuth cycle. The oauth app will be configured with this ass the callback url. diff --git a/contrib/google_auth_proxy.cfg.example b/contrib/google_auth_proxy.cfg.example index 64de399..d0105fd 100644 --- a/contrib/google_auth_proxy.cfg.example +++ b/contrib/google_auth_proxy.cfg.example @@ -5,6 +5,7 @@ # http_address = "127.0.0.1:4180" ## the OAuth Redirect URL. +# defaults to the "https://" + requested host header + "/oauth2/callback" # redirect_url = "https://internalapp.yourcompany.com/oauth2/callback" ## the http url(s) of the upstream endpoint. If multiple, routing is based on path diff --git a/oauthproxy.go b/oauthproxy.go index f2c4c7a..cf786fd 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -98,7 +98,7 @@ func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { if domain == "" { domain = "" } - log.Printf("Cookie settings: https_only: %v httponly: %v expiry: %s domain:%s", opts.CookieHttpsOnly, opts.CookieHttpOnly, opts.CookieExpire, domain) + log.Printf("Cookie settings: https_only (SSL required): %v httponly: %v expiry: %s domain:%s", opts.CookieHttpsOnly, opts.CookieHttpOnly, opts.CookieExpire, domain) return &OauthProxy{ CookieKey: "_oauthproxy", CookieSeed: opts.CookieSecret, @@ -122,15 +122,33 @@ func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { } } -func (p *OauthProxy) GetLoginURL(redirectUrl string) string { +func (p *OauthProxy) GetRedirectUrl(host string) string { + // default to the request Host if not set + if p.redirectUrl.Host != "" { + return p.redirectUrl.String() + } + var u url.URL + u = *p.redirectUrl + if u.Scheme == "" { + if p.CookieHttpsOnly { + u.Scheme = "https" + } else { + u.Scheme = "http" + } + } + u.Host = host + return u.String() +} + +func (p *OauthProxy) GetLoginURL(host, redirect string) string { params := url.Values{} - params.Add("redirect_uri", p.redirectUrl.String()) + params.Add("redirect_uri", p.GetRedirectUrl(host)) params.Add("approval_prompt", "force") params.Add("scope", p.oauthScope) params.Add("client_id", p.clientID) params.Add("response_type", "code") - if strings.HasPrefix(redirectUrl, "/") { - params.Add("state", redirectUrl) + if strings.HasPrefix(redirect, "/") { + params.Add("state", redirect) } return fmt.Sprintf("%s?%s", p.oauthLoginUrl, params.Encode()) } @@ -161,12 +179,12 @@ func (p *OauthProxy) displayCustomLoginForm() bool { return p.HtpasswdFile != nil && p.DisplayHtpasswdForm } -func (p *OauthProxy) redeemCode(code string) (string, string, error) { +func (p *OauthProxy) redeemCode(host, code string) (string, string, error) { if code == "" { return "", "", errors.New("missing code") } params := url.Values{} - params.Add("redirect_uri", p.redirectUrl.String()) + params.Add("redirect_uri", p.GetRedirectUrl(host)) params.Add("client_id", p.clientID) params.Add("client_secret", p.clientSecret) params.Add("code", code) @@ -370,7 +388,7 @@ func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { p.ErrorPage(rw, 500, "Internal Error", err.Error()) return } - http.Redirect(rw, req, p.GetLoginURL(redirect), 302) + http.Redirect(rw, req, p.GetLoginURL(req.Host, redirect), 302) return } if req.URL.Path == oauthCallbackPath { @@ -386,7 +404,7 @@ func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { return } - _, email, err := p.redeemCode(req.Form.Get("code")) + _, email, err := p.redeemCode(req.Host, req.Form.Get("code")) if err != nil { log.Printf("%s error redeeming code %s", remoteAddr, err) p.ErrorPage(rw, 500, "Internal Error", err.Error()) diff --git a/options.go b/options.go index 3b08864..e335e74 100644 --- a/options.go +++ b/options.go @@ -24,7 +24,7 @@ type Options struct { CookieSecret string `flag:"cookie-secret" cfg:"cookie_secret" env:"GOOGLE_AUTH_PROXY_COOKIE_SECRET"` CookieDomain string `flag:"cookie-domain" cfg:"cookie_domain" env:"GOOGLE_AUTH_PROXY_COOKIE_DOMAIN"` CookieExpire time.Duration `flag:"cookie-expire" cfg:"cookie_expire" env:"GOOGLE_AUTH_PROXY_COOKIE_EXPIRE"` - CookieHttpsOnly bool `flag:"cookie-https-only" cfg:"cookie_https_only"` + CookieHttpsOnly bool `flag:"cookie-https-only" cfg:"cookie_https_only"` // set secure cookie flag CookieHttpOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly"` Upstreams []string `flag:"upstream" cfg:"upstreams"`