@@ -1892,3 +1892,166 @@ func baseTestOptions() *options.Options {
18921892 opts.EmailDomains = []string{"*"}
18931893 return opts
18941894}
1895+
1896+func TestTrustedIPs(t *testing.T) {
1897+ tests := []struct {
1898+ name string
1899+ trustedIPs []string
1900+ reverseProxy bool
1901+ realClientIPHeader string
1902+ req *http.Request
1903+ expectTrusted bool
1904+ }{
1905+ // Check unconfigured behavior.
1906+ {
1907+ name: "Default",
1908+ trustedIPs: nil,
1909+ reverseProxy: false,
1910+ realClientIPHeader: "X-Real-IP", // Default value
1911+ req: func() *http.Request {
1912+ req, _ := http.NewRequest("GET", "/", nil)
1913+ return req
1914+ }(),
1915+ expectTrusted: false,
1916+ },
1917+ // Check using req.RemoteAddr (Options.ReverseProxy == false).
1918+ {
1919+ name: "WithRemoteAddr",
1920+ trustedIPs: []string{"127.0.0.1"},
1921+ reverseProxy: false,
1922+ realClientIPHeader: "X-Real-IP", // Default value
1923+ req: func() *http.Request {
1924+ req, _ := http.NewRequest("GET", "/", nil)
1925+ req.RemoteAddr = "127.0.0.1:43670"
1926+ return req
1927+ }(),
1928+ expectTrusted: true,
1929+ },
1930+ // Check ignores req.RemoteAddr match when behind a reverse proxy / missing header.
1931+ {
1932+ name: "IgnoresRemoteAddrInReverseProxyMode",
1933+ trustedIPs: []string{"127.0.0.1"},
1934+ reverseProxy: true,
1935+ realClientIPHeader: "X-Real-IP", // Default value
1936+ req: func() *http.Request {
1937+ req, _ := http.NewRequest("GET", "/", nil)
1938+ req.RemoteAddr = "127.0.0.1:44324"
1939+ return req
1940+ }(),
1941+ expectTrusted: false,
1942+ },
1943+ // Check successful trusting of localhost in IPv4.
1944+ {
1945+ name: "TrustsLocalhostInReverseProxyMode",
1946+ trustedIPs: []string{"127.0.0.0/8", "::1"},
1947+ reverseProxy: true,
1948+ realClientIPHeader: "X-Forwarded-For",
1949+ req: func() *http.Request {
1950+ req, _ := http.NewRequest("GET", "/", nil)
1951+ req.Header.Add("X-Forwarded-For", "127.0.0.1")
1952+ return req
1953+ }(),
1954+ expectTrusted: true,
1955+ },
1956+ // Check successful trusting of localhost in IPv6.
1957+ {
1958+ name: "TrustsIP6LocalostInReverseProxyMode",
1959+ trustedIPs: []string{"127.0.0.0/8", "::1"},
1960+ reverseProxy: true,
1961+ realClientIPHeader: "X-Forwarded-For",
1962+ req: func() *http.Request {
1963+ req, _ := http.NewRequest("GET", "/", nil)
1964+ req.Header.Add("X-Forwarded-For", "::1")
1965+ return req
1966+ }(),
1967+ expectTrusted: true,
1968+ },
1969+ // Check does not trust random IPv4 address.
1970+ {
1971+ name: "DoesNotTrustRandomIP4Address",
1972+ trustedIPs: []string{"127.0.0.0/8", "::1"},
1973+ reverseProxy: true,
1974+ realClientIPHeader: "X-Forwarded-For",
1975+ req: func() *http.Request {
1976+ req, _ := http.NewRequest("GET", "/", nil)
1977+ req.Header.Add("X-Forwarded-For", "12.34.56.78")
1978+ return req
1979+ }(),
1980+ expectTrusted: false,
1981+ },
1982+ // Check does not trust random IPv6 address.
1983+ {
1984+ name: "DoesNotTrustRandomIP6Address",
1985+ trustedIPs: []string{"127.0.0.0/8", "::1"},
1986+ reverseProxy: true,
1987+ realClientIPHeader: "X-Forwarded-For",
1988+ req: func() *http.Request {
1989+ req, _ := http.NewRequest("GET", "/", nil)
1990+ req.Header.Add("X-Forwarded-For", "::2")
1991+ return req
1992+ }(),
1993+ expectTrusted: false,
1994+ },
1995+ // Check respects correct header.
1996+ {
1997+ name: "RespectsCorrectHeaderInReverseProxyMode",
1998+ trustedIPs: []string{"127.0.0.0/8", "::1"},
1999+ reverseProxy: true,
2000+ realClientIPHeader: "X-Forwarded-For",
2001+ req: func() *http.Request {
2002+ req, _ := http.NewRequest("GET", "/", nil)
2003+ req.Header.Add("X-Real-IP", "::1")
2004+ return req
2005+ }(),
2006+ expectTrusted: false,
2007+ },
2008+ // Check doesn't trust if garbage is provided.
2009+ {
2010+ name: "DoesNotTrustGarbageInReverseProxyMode",
2011+ trustedIPs: []string{"127.0.0.0/8", "::1"},
2012+ reverseProxy: true,
2013+ realClientIPHeader: "X-Forwarded-For",
2014+ req: func() *http.Request {
2015+ req, _ := http.NewRequest("GET", "/", nil)
2016+ req.Header.Add("X-Forwarded-For", "adsfljk29242as!!")
2017+ return req
2018+ }(),
2019+ expectTrusted: false,
2020+ },
2021+ // Check doesn't trust if garbage is provided (no reverse-proxy).
2022+ {
2023+ name: "DoesNotTrustGarbage",
2024+ trustedIPs: []string{"127.0.0.0/8", "::1"},
2025+ reverseProxy: false,
2026+ realClientIPHeader: "X-Real-IP",
2027+ req: func() *http.Request {
2028+ req, _ := http.NewRequest("GET", "/", nil)
2029+ req.RemoteAddr = "adsfljk29242as!!"
2030+ return req
2031+ }(),
2032+ expectTrusted: false,
2033+ },
2034+ }
2035+
2036+ for _, tt := range tests {
2037+ t.Run(tt.name, func(t *testing.T) {
2038+ opts := baseTestOptions()
2039+ opts.Upstreams = []string{"static://200"}
2040+ opts.TrustedIPs = tt.trustedIPs
2041+ opts.ReverseProxy = tt.reverseProxy
2042+ opts.RealClientIPHeader = tt.realClientIPHeader
2043+ validation.Validate(opts)
2044+
2045+ proxy, err := NewOAuthProxy(opts, func(string) bool { return true })
2046+ assert.NoError(t, err)
2047+ rw := httptest.NewRecorder()
2048+
2049+ proxy.ServeHTTP(rw, tt.req)
2050+ if tt.expectTrusted {
2051+ assert.Equal(t, 200, rw.Code)
2052+ } else {
2053+ assert.Equal(t, 403, rw.Code)
2054+ }
2055+ })
2056+ }
2057+}