Skip to content

Commit afb2d43

Browse files
authored
Merge pull request #42 from ploxiln/xheaders_opt
add new option "xheaders" for whether trust X-Real-IP request header
2 parents 12effa1 + 8c87815 commit afb2d43

7 files changed

+25
-15
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ Usage of oauth2_proxy:
329329
-validate-url string: Access token validation endpoint
330330
-version: print version string
331331
-whitelist-domain value: allowed domain for redirection after authentication, leading '.' allows subdomains (may be given multiple times)
332+
-xheaders: Trust X-Real-IP request header (appropriate when behind a reverse proxy) (default true)
332333
```
333334

334335

contrib/oauth2_proxy.cfg.example

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
# tls_cert_file = ""
1010
# tls_key_file = ""
1111

12+
## whether to trust the X-Real-IP request header for logging
13+
## disable if not running oauth2_proxy behind another reverse-proxy or load-balancer
14+
# xheaders = true
15+
1216
## the OAuth Redirect URL
1317
## defaults to "https://" + requested host header + "/oauth2/callback"
1418
# redirect_url = "https://internalapp.yourcompany.com/oauth2/callback"

logging_handler.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,17 @@ type loggingHandler struct {
107107
writer io.Writer
108108
handler http.Handler
109109
enabled bool
110+
xheaders bool
110111
logTemplate *template.Template
111112
}
112113

113-
func LoggingHandler(out io.Writer, h http.Handler, v bool, requestLoggingTpl string) http.Handler {
114+
func LoggingHandler(out io.Writer, h http.Handler, enabled bool, xheaders bool, requestLoggingTpl string) http.Handler {
114115
return loggingHandler{
115116
writer: out,
116117
handler: h,
117-
enabled: v,
118-
logTemplate: template.Must(template.New("request-log").Parse(requestLoggingTpl)),
118+
enabled: enabled,
119+
xheaders: xheaders,
120+
logTemplate: template.Must(template.New("request-log").Parse(requestLoggingTpl + "\n")),
119121
}
120122
}
121123

@@ -146,9 +148,9 @@ func (h loggingHandler) writeLogLine(username, upstream string, req *http.Reques
146148
}
147149
}
148150

149-
client := req.Header.Get("X-Real-IP")
150-
if client == "" {
151-
client = req.RemoteAddr
151+
client := req.RemoteAddr
152+
if h.xheaders && req.Header.Get("X-Real-IP") != "" {
153+
client = req.Header.Get("X-Real-IP")
152154
}
153155

154156
if c, _, err := net.SplitHostPort(client); err == nil {
@@ -171,6 +173,4 @@ func (h loggingHandler) writeLogLine(username, upstream string, req *http.Reques
171173
UserAgent: fmt.Sprintf("%q", req.UserAgent()),
172174
Username: username,
173175
})
174-
175-
h.writer.Write([]byte("\n"))
176176
}

logging_handler_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestLoggingHandler_ServeHTTP(t *testing.T) {
3131
w.Write([]byte("test"))
3232
}
3333

34-
h := LoggingHandler(buf, http.HandlerFunc(handler), true, test.Format)
34+
h := LoggingHandler(buf, http.HandlerFunc(handler), true, true, test.Format)
3535

3636
r, _ := http.NewRequest("GET", "/foo/bar", nil)
3737
r.RemoteAddr = "127.0.0.1"

main.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ func mainFlagSet() *flag.FlagSet {
2828
flagSet.String("tls-cert", "", "path to certificate file")
2929
flagSet.String("tls-key", "", "path to private key file")
3030
flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"")
31-
flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)")
3231
flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path")
32+
flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)")
3333
flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream")
3434
flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth header to upstream")
3535
flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header")
@@ -70,6 +70,7 @@ func mainFlagSet() *flag.FlagSet {
7070
flagSet.Bool("cookie-secure", true, "set secure (HTTPS) cookie flag")
7171
flagSet.Bool("cookie-httponly", true, "set HttpOnly cookie flag")
7272

73+
flagSet.Bool("xheaders", true, "Trust X-Real-IP request header (appropriate when behind a reverse proxy)")
7374
flagSet.Bool("request-logging", true, "Log requests to stdout")
7475
flagSet.String("request-logging-format", defaultRequestLoggingFormat, "Template for request log lines")
7576

@@ -142,7 +143,7 @@ func main() {
142143
}
143144

144145
s := &Server{
145-
Handler: LoggingHandler(os.Stdout, oauthproxy, opts.RequestLogging, opts.RequestLoggingFormat),
146+
Handler: LoggingHandler(os.Stdout, oauthproxy, opts.RequestLogging, opts.XHeaders, opts.RequestLoggingFormat),
146147
Opts: opts,
147148
}
148149
s.ListenAndServe()

oauthproxy.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ type OAuthProxy struct {
6969
PassUserHeaders bool
7070
BasicAuthPassword string
7171
PassAccessToken bool
72+
XHeaders bool
7273
CookieCipher *cookie.Cipher
7374
skipAuthRegex []string
7475
skipAuthPreflight bool
@@ -228,6 +229,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
228229
BasicAuthPassword: opts.BasicAuthPassword,
229230
PassAccessToken: opts.PassAccessToken,
230231
SkipProviderButton: opts.SkipProviderButton,
232+
XHeaders: opts.XHeaders,
231233
CookieCipher: cipher,
232234
templates: loadTemplates(opts.CustomTemplatesDir),
233235
Footer: opts.Footer,
@@ -500,9 +502,9 @@ func (p *OAuthProxy) IsWhitelistedPath(path string) (ok bool) {
500502
return
501503
}
502504

503-
func getRemoteAddr(req *http.Request) (s string) {
505+
func (p *OAuthProxy) getRemoteAddr(req *http.Request) (s string) {
504506
s = req.RemoteAddr
505-
if req.Header.Get("X-Real-IP") != "" {
507+
if p.XHeaders && req.Header.Get("X-Real-IP") != "" {
506508
s += fmt.Sprintf(" (%q)", req.Header.Get("X-Real-IP"))
507509
}
508510
return
@@ -574,7 +576,7 @@ func (p *OAuthProxy) OAuthStart(rw http.ResponseWriter, req *http.Request) {
574576
}
575577

576578
func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
577-
remoteAddr := getRemoteAddr(req)
579+
remoteAddr := p.getRemoteAddr(req)
578580

579581
// finish the oauth cycle
580582
err := req.ParseForm()
@@ -661,7 +663,7 @@ func (p *OAuthProxy) Proxy(rw http.ResponseWriter, req *http.Request) {
661663

662664
func (p *OAuthProxy) Authenticate(rw http.ResponseWriter, req *http.Request) int {
663665
var saveSession, clearSession, revalidated bool
664-
remoteAddr := getRemoteAddr(req)
666+
remoteAddr := p.getRemoteAddr(req)
665667

666668
session, sessionAge, err := p.LoadCookiedSession(req)
667669
if err != nil {

options.go

+2
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ type Options struct {
8181
Scope string `flag:"scope" cfg:"scope"`
8282
ApprovalPrompt string `flag:"approval-prompt" cfg:"approval_prompt"`
8383

84+
XHeaders bool `flag:"xheaders" cfg:"xheaders"`
8485
RequestLogging bool `flag:"request-logging" cfg:"request_logging"`
8586
RequestLoggingFormat string `flag:"request-logging-format" cfg:"request_logging_format"`
8687

@@ -118,6 +119,7 @@ func NewOptions() *Options {
118119
PassAccessToken: false,
119120
PassHostHeader: true,
120121
ApprovalPrompt: "force",
122+
XHeaders: true,
121123
RequestLogging: true,
122124
RequestLoggingFormat: defaultRequestLoggingFormat,
123125
}

0 commit comments

Comments
 (0)