add --proxy-host-header option
This commit is contained in:
		
							parent
							
								
									24ef555547
								
							
						
					
					
						commit
						263e16eeea
					
				|  | @ -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 |   -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://]<addr>:<port> or unix://<path> to listen on for HTTP clients |   -http-address="127.0.0.1:4180": [http://]<addr>:<port> or unix://<path> 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-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" |   -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) |   -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 |   -upstream=: the http url(s) of the upstream endpoint. If multiple, routing is based on path | ||||||
|  |  | ||||||
|  | @ -14,6 +14,9 @@ | ||||||
| 
 | 
 | ||||||
| ## pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream | ## pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream | ||||||
| # pass_basic_auth = true | # 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 to allow authentication for | ||||||
| # google_apps_domains = [ | # google_apps_domains = [ | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								main.go
								
								
								
								
							
							
						
						
									
										1
									
								
								main.go
								
								
								
								
							|  | @ -29,6 +29,7 @@ func main() { | ||||||
| 	flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"") | 	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.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-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(&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)") | 	flagSet.Var(&googleAppsDomains, "google-apps-domain", "authenticate against the given Google apps domain (may be given multiple times)") | ||||||
|  |  | ||||||
|  | @ -47,13 +47,14 @@ type OauthProxy struct { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewReverseProxy(target *url.URL) (proxy *httputil.ReverseProxy) { | func NewReverseProxy(target *url.URL) (proxy *httputil.ReverseProxy) { | ||||||
|     proxy = httputil.NewSingleHostReverseProxy(target) | 	return httputil.NewSingleHostReverseProxy(target) | ||||||
|     director := proxy.Director | } | ||||||
|     proxy.Director = func(req *http.Request) { | func setProxyUpstreamHostHeader(proxy *httputil.ReverseProxy, target *url.URL) { | ||||||
|         director(req) | 	director := proxy.Director | ||||||
|         req.Host = target.Host | 	proxy.Director = func(req *http.Request) { | ||||||
|     } | 		director(req) | ||||||
|     return proxy | 		req.Host = target.Host | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { | 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 | 		path := u.Path | ||||||
| 		u.Path = "" | 		u.Path = "" | ||||||
| 		log.Printf("mapping path %q => upstream %q", path, u) | 		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 { | 	for _, u := range opts.CompiledRegex { | ||||||
| 		log.Printf("compiled skip-auth-regex => %q", u) | 		log.Printf("compiled skip-auth-regex => %q", u) | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ import ( | ||||||
| func TestNewReverseProxy(t *testing.T) { | func TestNewReverseProxy(t *testing.T) { | ||||||
| 	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		w.WriteHeader(200) | 		w.WriteHeader(200) | ||||||
|         hostname, _, _ := net.SplitHostPort(r.Host) | 		hostname, _, _ := net.SplitHostPort(r.Host) | ||||||
| 		w.Write([]byte(hostname)) | 		w.Write([]byte(hostname)) | ||||||
| 	})) | 	})) | ||||||
| 	defer backend.Close() | 	defer backend.Close() | ||||||
|  | @ -24,6 +24,7 @@ func TestNewReverseProxy(t *testing.T) { | ||||||
| 	proxyURL, _ := url.Parse(backendURL.Scheme + "://" + backendHost + "/") | 	proxyURL, _ := url.Parse(backendURL.Scheme + "://" + backendHost + "/") | ||||||
| 
 | 
 | ||||||
| 	proxyHandler := NewReverseProxy(proxyURL) | 	proxyHandler := NewReverseProxy(proxyURL) | ||||||
|  | 	setProxyUpstreamHostHeader(proxyHandler, proxyURL) | ||||||
| 	frontend := httptest.NewServer(proxyHandler) | 	frontend := httptest.NewServer(proxyHandler) | ||||||
| 	defer frontend.Close() | 	defer frontend.Close() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										39
									
								
								options.go
								
								
								
								
							
							
						
						
									
										39
									
								
								options.go
								
								
								
								
							|  | @ -10,22 +10,26 @@ import ( | ||||||
| 
 | 
 | ||||||
| // Configuration Options that can be set by Command Line Flag, or Config File
 | // Configuration Options that can be set by Command Line Flag, or Config File
 | ||||||
| type Options struct { | type Options struct { | ||||||
| 	HttpAddress             string        `flag:"http-address" cfg:"http_address"` | 	HttpAddress  string `flag:"http-address" cfg:"http_address"` | ||||||
| 	RedirectUrl             string        `flag:"redirect-url" cfg:"redirect_url"` | 	RedirectUrl  string `flag:"redirect-url" cfg:"redirect_url"` | ||||||
| 	ClientID                string        `flag:"client-id" cfg:"client_id" env:"GOOGLE_AUTH_PROXY_CLIENT_ID"` | 	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"` | 	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"` | 	AuthenticatedEmailsFile string   `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"` | ||||||
| 	DisplayHtpasswdForm     bool          `flag:"display-htpasswd-form" cfg:"display_htpasswd_form"` | 	GoogleAppsDomains       []string `flag:"google-apps-domain" cfg:"google_apps_domains"` | ||||||
| 	CookieSecret            string        `flag:"cookie-secret" cfg:"cookie_secret" env:"GOOGLE_AUTH_PROXY_COOKIE_SECRET"` | 	HtpasswdFile            string   `flag:"htpasswd-file" cfg:"htpasswd_file"` | ||||||
| 	CookieDomain            string        `flag:"cookie-domain" cfg:"cookie_domain" env:"GOOGLE_AUTH_PROXY_COOKIE_DOMAIN"` | 	DisplayHtpasswdForm     bool     `flag:"display-htpasswd-form" cfg:"display_htpasswd_form"` | ||||||
| 	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"` | 	CookieSecret    string        `flag:"cookie-secret" cfg:"cookie_secret" env:"GOOGLE_AUTH_PROXY_COOKIE_SECRET"` | ||||||
| 	CookieHttpOnly          bool          `flag:"cookie-httponly" cfg:"cookie_httponly"` | 	CookieDomain    string        `flag:"cookie-domain" cfg:"cookie_domain" env:"GOOGLE_AUTH_PROXY_COOKIE_DOMAIN"` | ||||||
| 	AuthenticatedEmailsFile string        `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"` | 	CookieExpire    time.Duration `flag:"cookie-expire" cfg:"cookie_expire" env:"GOOGLE_AUTH_PROXY_COOKIE_EXPIRE"` | ||||||
| 	GoogleAppsDomains       []string      `flag:"google-apps-domain" cfg:"google_apps_domains"` | 	CookieHttpsOnly bool          `flag:"cookie-https-only" cfg:"cookie_https_only"` | ||||||
| 	Upstreams               []string      `flag:"upstream" cfg:"upstreams"` | 	CookieHttpOnly  bool          `flag:"cookie-httponly" cfg:"cookie_httponly"` | ||||||
| 	SkipAuthRegex           []string      `flag:"skip-auth-regex" cfg:"skip_auth_regex"` | 
 | ||||||
|  | 	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
 | 	// internal values that are set after config validation
 | ||||||
| 	redirectUrl   *url.URL | 	redirectUrl   *url.URL | ||||||
|  | @ -39,8 +43,9 @@ func NewOptions() *Options { | ||||||
| 		DisplayHtpasswdForm: true, | 		DisplayHtpasswdForm: true, | ||||||
| 		CookieHttpsOnly:     true, | 		CookieHttpsOnly:     true, | ||||||
| 		CookieHttpOnly:      true, | 		CookieHttpOnly:      true, | ||||||
| 		PassBasicAuth:       true, |  | ||||||
| 		CookieExpire:        time.Duration(168) * time.Hour, | 		CookieExpire:        time.Duration(168) * time.Hour, | ||||||
|  | 		PassBasicAuth:       true, | ||||||
|  | 		PassHostHeader:      true, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,14 +1,14 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"net/url" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"net/url" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/bmizerany/assert" | 	"github.com/bmizerany/assert" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func testOptions() (*Options) { | func testOptions() *Options { | ||||||
| 	o := NewOptions() | 	o := NewOptions() | ||||||
| 	o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8080/") | 	o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8080/") | ||||||
| 	o.CookieSecret = "foobar" | 	o.CookieSecret = "foobar" | ||||||
|  | @ -17,7 +17,7 @@ func testOptions() (*Options) { | ||||||
| 	return o | 	return o | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func errorMsg(msgs []string)(string) { | func errorMsg(msgs []string) string { | ||||||
| 	result := make([]string, 0) | 	result := make([]string, 0) | ||||||
| 	result = append(result, "Invalid configuration:") | 	result = append(result, "Invalid configuration:") | ||||||
| 	result = append(result, msgs...) | 	result = append(result, msgs...) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue