From 263e16eeeac3efadbfd7da44cdffda8eb39ae8ea Mon Sep 17 00:00:00 2001 From: Jehiah Czebotar Date: Tue, 17 Mar 2015 15:15:15 -0400 Subject: [PATCH] add --proxy-host-header option --- README.md | 1 + contrib/google_auth_proxy.cfg.example | 3 +++ main.go | 1 + oauthproxy.go | 21 +++++++++------ oauthproxy_test.go | 3 ++- options.go | 39 +++++++++++++++------------ options_test.go | 6 ++--- 7 files changed, 45 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index f9c752f..f7de4e8 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ Usage of google_auth_proxy: -htpasswd-file="": additionally authenticate against a htpasswd file. Entries must be created with "htpasswd -s" for SHA encryption -http-address="127.0.0.1:4180": [http://]: or unix:// to listen on for HTTP clients -pass-basic-auth=true: pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream + -pass-host-header=true: pass the request Host Header to upstream -redirect-url="": the OAuth Redirect URL. ie: "https://internalapp.yourcompany.com/oauth2/callback" -skip-auth-regex=: bypass authentication for requests path's that match (may be given multiple times) -upstream=: the http url(s) of the upstream endpoint. If multiple, routing is based on path diff --git a/contrib/google_auth_proxy.cfg.example b/contrib/google_auth_proxy.cfg.example index 7034a58..3158645 100644 --- a/contrib/google_auth_proxy.cfg.example +++ b/contrib/google_auth_proxy.cfg.example @@ -14,6 +14,9 @@ ## pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream # pass_basic_auth = true +## pass the request Host Header to upstream +## when disabled the upstream Host is used as the Host Header +# pass_host_header = true ## Google Apps Domains to allow authentication for # google_apps_domains = [ diff --git a/main.go b/main.go index 747b7f1..41a50e1 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,7 @@ func main() { flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"") flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint. If multiple, routing is based on path") flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream") + flagSet.Bool("pass-host-header", true, "pass the request Host Header to upstream") flagSet.Var(&skipAuthRegex, "skip-auth-regex", "bypass authentication for requests path's that match (may be given multiple times)") flagSet.Var(&googleAppsDomains, "google-apps-domain", "authenticate against the given Google apps domain (may be given multiple times)") diff --git a/oauthproxy.go b/oauthproxy.go index 0705b6d..1ead0ff 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -47,13 +47,14 @@ type OauthProxy struct { } func NewReverseProxy(target *url.URL) (proxy *httputil.ReverseProxy) { - proxy = httputil.NewSingleHostReverseProxy(target) - director := proxy.Director - proxy.Director = func(req *http.Request) { - director(req) - req.Host = target.Host - } - return proxy + return httputil.NewSingleHostReverseProxy(target) +} +func setProxyUpstreamHostHeader(proxy *httputil.ReverseProxy, target *url.URL) { + director := proxy.Director + proxy.Director = func(req *http.Request) { + director(req) + req.Host = target.Host + } } func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { @@ -64,7 +65,11 @@ func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { path := u.Path u.Path = "" log.Printf("mapping path %q => upstream %q", path, u) - serveMux.Handle(path, NewReverseProxy(u)) + proxy := NewReverseProxy(u) + if !opts.PassHostHeader { + setProxyUpstreamHostHeader(proxy, u) + } + serveMux.Handle(path, proxy) } for _, u := range opts.CompiledRegex { log.Printf("compiled skip-auth-regex => %q", u) diff --git a/oauthproxy_test.go b/oauthproxy_test.go index c4e68b3..c4e3836 100644 --- a/oauthproxy_test.go +++ b/oauthproxy_test.go @@ -12,7 +12,7 @@ import ( func TestNewReverseProxy(t *testing.T) { backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) - hostname, _, _ := net.SplitHostPort(r.Host) + hostname, _, _ := net.SplitHostPort(r.Host) w.Write([]byte(hostname)) })) defer backend.Close() @@ -24,6 +24,7 @@ func TestNewReverseProxy(t *testing.T) { proxyURL, _ := url.Parse(backendURL.Scheme + "://" + backendHost + "/") proxyHandler := NewReverseProxy(proxyURL) + setProxyUpstreamHostHeader(proxyHandler, proxyURL) frontend := httptest.NewServer(proxyHandler) defer frontend.Close() diff --git a/options.go b/options.go index 7ef737a..df2b3ca 100644 --- a/options.go +++ b/options.go @@ -10,22 +10,26 @@ import ( // Configuration Options that can be set by Command Line Flag, or Config File type Options struct { - HttpAddress string `flag:"http-address" cfg:"http_address"` - RedirectUrl string `flag:"redirect-url" cfg:"redirect_url"` - ClientID string `flag:"client-id" cfg:"client_id" env:"GOOGLE_AUTH_PROXY_CLIENT_ID"` - ClientSecret string `flag:"client-secret" cfg:"client_secret" env:"GOOGLE_AUTH_PROXY_CLIENT_SECRET"` - PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"` - HtpasswdFile string `flag:"htpasswd-file" cfg:"htpasswd_file"` - DisplayHtpasswdForm bool `flag:"display-htpasswd-form" cfg:"display_htpasswd_form"` - 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"` - CookieHttpOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly"` - AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"` - GoogleAppsDomains []string `flag:"google-apps-domain" cfg:"google_apps_domains"` - Upstreams []string `flag:"upstream" cfg:"upstreams"` - SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"` + HttpAddress string `flag:"http-address" cfg:"http_address"` + RedirectUrl string `flag:"redirect-url" cfg:"redirect_url"` + ClientID string `flag:"client-id" cfg:"client_id" env:"GOOGLE_AUTH_PROXY_CLIENT_ID"` + ClientSecret string `flag:"client-secret" cfg:"client_secret" env:"GOOGLE_AUTH_PROXY_CLIENT_SECRET"` + + AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"` + GoogleAppsDomains []string `flag:"google-apps-domain" cfg:"google_apps_domains"` + HtpasswdFile string `flag:"htpasswd-file" cfg:"htpasswd_file"` + DisplayHtpasswdForm bool `flag:"display-htpasswd-form" cfg:"display_htpasswd_form"` + + 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"` + CookieHttpOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly"` + + Upstreams []string `flag:"upstream" cfg:"upstreams"` + SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"` + PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"` + PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header"` // internal values that are set after config validation redirectUrl *url.URL @@ -39,8 +43,9 @@ func NewOptions() *Options { DisplayHtpasswdForm: true, CookieHttpsOnly: true, CookieHttpOnly: true, - PassBasicAuth: true, CookieExpire: time.Duration(168) * time.Hour, + PassBasicAuth: true, + PassHostHeader: true, } } diff --git a/options_test.go b/options_test.go index 37ab9d1..47c711a 100644 --- a/options_test.go +++ b/options_test.go @@ -1,14 +1,14 @@ package main import ( + "net/url" "strings" "testing" - "net/url" "github.com/bmizerany/assert" ) -func testOptions() (*Options) { +func testOptions() *Options { o := NewOptions() o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8080/") o.CookieSecret = "foobar" @@ -17,7 +17,7 @@ func testOptions() (*Options) { return o } -func errorMsg(msgs []string)(string) { +func errorMsg(msgs []string) string { result := make([]string, 0) result = append(result, "Invalid configuration:") result = append(result, msgs...)