diff --git a/http.go b/http.go index d15d3bf00..57cac5a5f 100644 --- a/http.go +++ b/http.go @@ -122,3 +122,21 @@ func extractClientIP(req *http.Request, header string) string { } return "" } + +func redirectToHTTPS(h http.Handler, httpsAddr string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.TLS == nil && strings.ToLower(r.Header.Get("X-Forwarded-Proto")) != "https" { + url := *r.URL + host := strings.Split(r.Host, ":")[0] + if !strings.HasSuffix(httpsAddr, ":443") { + host += ":" + strings.Split(httpsAddr, ":")[1] + } + url.Host = host + url.Scheme = "https" + http.Redirect(w, r, url.String(), http.StatusPermanentRedirect) + } else { + // normal case + h.ServeHTTP(w, r) + } + }) +} diff --git a/logging_handler.go b/logging_handler.go index 8c33e5f87..186310759 100644 --- a/logging_handler.go +++ b/logging_handler.go @@ -106,16 +106,14 @@ type logMessageData struct { type loggingHandler struct { writer io.Writer handler http.Handler - enabled bool ipHeader string logTemplate *template.Template } -func LoggingHandler(out io.Writer, h http.Handler, enabled bool, ipHeader, requestLoggingTpl string) http.Handler { +func LoggingHandler(out io.Writer, h http.Handler, ipHeader, requestLoggingTpl string) http.Handler { return loggingHandler{ writer: out, handler: h, - enabled: enabled, ipHeader: ipHeader, logTemplate: template.Must(template.New("request-log").Parse(requestLoggingTpl + "\n")), } @@ -126,9 +124,6 @@ func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { url := *req.URL logger := &responseLogger{w: w} h.handler.ServeHTTP(logger, req) - if !h.enabled { - return - } h.writeLogLine(logger.authInfo, logger.upstream, req, url, t, logger.Status(), logger.Size()) } @@ -175,3 +170,20 @@ func (h loggingHandler) writeLogLine(username, upstream string, req *http.Reques Username: username, }) } + +// if logging is disabled, more efficient +// but still need to remove GAP-* metadata response headers via responseLogger +type noLoggingHandler struct { + handler http.Handler +} + +func (h noLoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + logger := &responseLogger{w: w} + h.handler.ServeHTTP(logger, req) +} + +func NoLoggingHandler(h http.Handler) http.Handler { + return noLoggingHandler{ + handler: h, + } +} diff --git a/logging_handler_test.go b/logging_handler_test.go index 94e40c51c..e9d806578 100644 --- a/logging_handler_test.go +++ b/logging_handler_test.go @@ -34,7 +34,7 @@ func TestLoggingHandler_ServeHTTP(t *testing.T) { w.Write([]byte("test")) } - h := LoggingHandler(buf, http.HandlerFunc(handler), true, "", test.Format) + h := LoggingHandler(buf, http.HandlerFunc(handler), "", test.Format) r, _ := http.NewRequest("GET", "/foo/bar", nil) r.RemoteAddr = "127.0.0.1" r.Host = "test-server" diff --git a/main.go b/main.go index fd6661b71..2a17a37c4 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "flag" "fmt" "log" + "net/http" "os" "runtime" "strings" @@ -25,6 +26,7 @@ func mainFlagSet() *flag.FlagSet { flagSet.String("http-address", "127.0.0.1:4180", "[http://]: or unix:// to listen on for HTTP clients") flagSet.String("https-address", ":443", ": to listen on for HTTPS clients") + flagSet.Bool("force-https", false, "redirect http requests to https") flagSet.String("tls-cert", "", "path to certificate file") flagSet.String("tls-key", "", "path to private key file") flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"") @@ -150,8 +152,19 @@ func main() { } } + var handler http.Handler = oauthproxy + if opts.ForceHTTPS { + handler = redirectToHTTPS(handler, opts.HttpsAddress) + } + if opts.RequestLogging { + handler = LoggingHandler( + os.Stdout, handler, opts.RealClientIPHeader, opts.RequestLoggingFormat, + ) + } else { + handler = NoLoggingHandler(handler) + } s := &Server{ - Handler: LoggingHandler(os.Stdout, oauthproxy, opts.RequestLogging, opts.RealClientIPHeader, opts.RequestLoggingFormat), + Handler: handler, Opts: opts, } s.ListenAndServe() diff --git a/options.go b/options.go index ec925d80e..646e0b4b5 100644 --- a/options.go +++ b/options.go @@ -22,6 +22,7 @@ type Options struct { ProxyWebSockets bool `flag:"proxy-websockets" cfg:"proxy_websockets"` HttpAddress string `flag:"http-address" cfg:"http_address"` HttpsAddress string `flag:"https-address" cfg:"https_address"` + ForceHTTPS bool `flag:"force-https" cfg:"force_https"` RedirectURL string `flag:"redirect-url" cfg:"redirect_url"` ClientID string `flag:"client-id" cfg:"client_id" env:"OAUTH2_PROXY_CLIENT_ID"` ClientSecret string `flag:"client-secret" cfg:"client_secret" env:"OAUTH2_PROXY_CLIENT_SECRET"` @@ -108,6 +109,7 @@ func NewOptions() *Options { ProxyWebSockets: true, HttpAddress: "127.0.0.1:4180", HttpsAddress: ":443", + ForceHTTPS: false, DisplayHtpasswdForm: true, CookieName: "_oauth2_proxy", CookieSecure: true,