Merge commit from fork

Signed-off-by: Jan Larwig <jan@larwig.com>
This commit is contained in:
Jan Larwig
2026-04-13 18:22:56 +02:00
committed by GitHub
parent 43596a7bab
commit aff369dfa3
23 changed files with 498 additions and 104 deletions
+48 -1
View File
@@ -2,9 +2,12 @@ package middleware
import (
"context"
"net"
"net/http"
"strings"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
)
type scopeKey string
@@ -18,9 +21,13 @@ const RequestScopeKey scopeKey = "request-scope"
// within the chain.
type RequestScope struct {
// ReverseProxy tracks whether OAuth2-Proxy is operating in reverse proxy
// mode and if request `X-Forwarded-*` headers should be trusted
// mode and if request `X-Forwarded-*` headers may be trusted
ReverseProxy bool
// TrustedProxies tracks which direct callers are allowed to supply
// forwarded headers when ReverseProxy mode is enabled.
TrustedProxies *ip.NetSet
// RequestID is set to the request's `X-Request-Id` header if set.
// Otherwise a random UUID is set.
RequestID string
@@ -58,3 +65,43 @@ func AddRequestScope(req *http.Request, scope *RequestScope) *http.Request {
ctx := context.WithValue(req.Context(), RequestScopeKey, scope)
return req.WithContext(ctx)
}
// CanTrustForwardedHeaders returns whether forwarded headers should be
// processed for this request.
func (s *RequestScope) CanTrustForwardedHeaders(req *http.Request) bool {
if s == nil || req == nil || !s.ReverseProxy || s.TrustedProxies == nil {
return false
}
if isUnixSocketRemoteAddr(req.RemoteAddr) {
return true
}
remoteIP := parseRemoteAddrIP(req.RemoteAddr)
if remoteIP == nil {
return false
}
return s.TrustedProxies.Has(remoteIP)
}
func parseRemoteAddrIP(remoteAddr string) net.IP {
if remoteAddr == "" {
return nil
}
if ip := net.ParseIP(remoteAddr); ip != nil {
return ip
}
host, _, err := net.SplitHostPort(remoteAddr)
if err != nil {
return nil
}
return net.ParseIP(host)
}
func isUnixSocketRemoteAddr(remoteAddr string) bool {
return remoteAddr == "@" || strings.HasPrefix(remoteAddr, "/")
}
+34
View File
@@ -4,6 +4,7 @@ import (
"net/http"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
@@ -53,4 +54,37 @@ var _ = Describe("Scope Suite", func() {
})
})
})
Context("CanTrustForwardedHeaders", func() {
var request *http.Request
var scope *middleware.RequestScope
BeforeEach(func() {
var err error
request, err = http.NewRequest("", "http://127.0.0.1/", nil)
Expect(err).ToNot(HaveOccurred())
trustedProxies, err := ip.ParseNetSet([]string{"127.0.0.1"})
Expect(err).ToNot(HaveOccurred())
scope = &middleware.RequestScope{
ReverseProxy: true,
TrustedProxies: trustedProxies,
}
})
It("returns true for a trusted remote address", func() {
request.RemoteAddr = "127.0.0.1:4180"
Expect(scope.CanTrustForwardedHeaders(request)).To(BeTrue())
})
It("returns false for an untrusted remote address", func() {
request.RemoteAddr = "192.0.2.10:4180"
Expect(scope.CanTrustForwardedHeaders(request)).To(BeFalse())
})
It("returns true for unix socket callers", func() {
request.RemoteAddr = "@"
Expect(scope.CanTrustForwardedHeaders(request)).To(BeTrue())
})
})
})
+2
View File
@@ -24,6 +24,7 @@ type Options struct {
ReadyPath string `flag:"ready-path" cfg:"ready_path"`
ReverseProxy bool `flag:"reverse-proxy" cfg:"reverse_proxy"`
RealClientIPHeader string `flag:"real-client-ip-header" cfg:"real_client_ip_header"`
TrustedProxyIPs []string `flag:"trusted-proxy-ip" cfg:"trusted_proxy_ips"`
TrustedIPs []string `flag:"trusted-ip" cfg:"trusted_ips"`
ForceHTTPS bool `flag:"force-https" cfg:"force_https"`
RawRedirectURL string `flag:"redirect-url" cfg:"redirect_url"`
@@ -119,6 +120,7 @@ func NewFlagSet() *pflag.FlagSet {
flagSet.Bool("reverse-proxy", false, "are we running behind a reverse proxy, controls whether headers like X-Real-Ip are accepted")
flagSet.String("real-client-ip-header", "X-Real-IP", "Header used to determine the real IP of the client (one of: X-Forwarded-For, X-Real-IP, X-ProxyUser-IP, X-Envoy-External-Address, or CF-Connecting-IP)")
flagSet.StringSlice("trusted-proxy-ip", []string{}, "list of IPs or CIDR ranges that are allowed to set X-Forwarded-* headers when --reverse-proxy is enabled. Defaults to trusting all IPs for backwards compatibility; configure this to your reverse proxy addresses to prevent header spoofing.")
flagSet.StringSlice("trusted-ip", []string{}, "list of IPs or CIDR ranges to allow to bypass authentication. WARNING: trusting by IP has inherent security flaws, read the configuration documentation for more information.")
flagSet.Bool("force-https", false, "force HTTPS redirect for HTTP requests")
flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"")
+33 -2
View File
@@ -4,6 +4,7 @@ import (
"net/http"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
@@ -33,9 +34,16 @@ var _ = Describe("Director Suite", func() {
req.Header.Add(header, value)
}
}
req = middleware.AddRequestScope(req, &middleware.RequestScope{
scope := &middleware.RequestScope{
ReverseProxy: in.reverseProxy,
})
}
if in.reverseProxy {
req.RemoteAddr = "127.0.0.1:4180"
trustedProxies, err := ip.ParseNetSet([]string{"127.0.0.1"})
Expect(err).ToNot(HaveOccurred())
scope.TrustedProxies = trustedProxies
}
req = middleware.AddRequestScope(req, scope)
redirect, err := appDirector.GetRedirect(req)
Expect(err).ToNot(HaveOccurred())
@@ -174,4 +182,27 @@ var _ = Describe("Director Suite", func() {
expectedRedirect: "https://a-service.example.com/foo/bar",
}),
)
It("ignores forwarded headers from an untrusted remote address", func() {
appDirector := NewAppDirector(AppDirectorOpts{
ProxyPrefix: testProxyPrefix,
Validator: testValidator(true),
})
req, _ := http.NewRequest("GET", "https://oauth.example.com/foo?bar", nil)
req.RemoteAddr = "192.0.2.10:4180"
req.Header.Add("X-Forwarded-Proto", "https")
req.Header.Add("X-Forwarded-Host", "a-service.example.com")
req.Header.Add("X-Forwarded-Uri", fooBar)
trustedProxies, err := ip.ParseNetSet([]string{"127.0.0.1"})
Expect(err).ToNot(HaveOccurred())
req = middleware.AddRequestScope(req, &middleware.RequestScope{
ReverseProxy: true,
TrustedProxies: trustedProxies,
})
redirect, err := appDirector.GetRedirect(req)
Expect(err).ToNot(HaveOccurred())
Expect(redirect).To(Equal("/foo?bar"))
})
})
+7 -1
View File
@@ -6,6 +6,7 @@ import (
"time"
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
@@ -30,8 +31,13 @@ var _ = Describe("Cookie Tests", func() {
if in.xForwardedHost != "" {
req.Header.Add("X-Forwarded-Host", in.xForwardedHost)
req.RemoteAddr = "127.0.0.1:4180"
trustedProxies, err := ip.ParseNetSet([]string{"127.0.0.1"})
Expect(err).ToNot(HaveOccurred())
req = middlewareapi.AddRequestScope(req, &middlewareapi.RequestScope{
ReverseProxy: true,
ReverseProxy: true,
TrustedProxies: trustedProxies,
})
}
+16
View File
@@ -1,6 +1,7 @@
package ip
import (
"fmt"
"net"
"strings"
)
@@ -37,3 +38,18 @@ func ParseIPNet(s string) *net.IPNet {
return ipNet
}
}
func ParseNetSet(ipStrs []string) (*NetSet, error) {
netSet := NewNetSet()
for _, ipStr := range ipStrs {
ipNet := ParseIPNet(ipStr)
if ipNet == nil {
return nil, fmt.Errorf("could not parse IP network (%s)", ipStr)
}
netSet.AddIPNet(*ipNet)
}
return netSet, nil
}
+118
View File
@@ -0,0 +1,118 @@
package ip
import (
"net"
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseIPNet(t *testing.T) {
tests := []struct {
name string
input string
expectedIP net.IP
expectedMask net.IPMask
}{
{
name: "ipv4 address",
input: "127.0.0.1",
expectedIP: net.ParseIP("127.0.0.1"),
expectedMask: net.CIDRMask(32, 32),
},
{
name: "ipv6 address",
input: "::1",
expectedIP: net.ParseIP("::1"),
expectedMask: net.CIDRMask(128, 128),
},
{
name: "ipv4 cidr",
input: "10.0.0.0/24",
expectedIP: net.ParseIP("10.0.0.0"),
expectedMask: net.CIDRMask(24, 32),
},
{
name: "ipv6 cidr",
input: "2001:db8::/64",
expectedIP: net.ParseIP("2001:db8::"),
expectedMask: net.CIDRMask(64, 128),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ipNet := ParseIPNet(test.input)
assert.NotNil(t, ipNet)
if ipNet == nil {
return
}
assert.True(t, test.expectedIP.Equal(ipNet.IP))
assert.Equal(t, test.expectedMask, ipNet.Mask)
})
}
}
func TestParseIPNetRejectsInvalidNetworks(t *testing.T) {
tests := []struct {
name string
input string
}{
{
name: "invalid ip",
input: "not-an-ip",
},
{
name: "ipv4 cidr with host bits set",
input: "10.0.0.1/24",
},
{
name: "ipv6 cidr with host bits set",
input: "2001:db8::1/64",
},
{
name: "invalid cidr mask",
input: "10.0.0.0/33",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Nil(t, ParseIPNet(test.input))
})
}
}
func TestParseNetSet(t *testing.T) {
netSet, err := ParseNetSet([]string{
"127.0.0.1",
"10.0.0.0/24",
"::1",
"2001:db8::/64",
})
assert.NoError(t, err)
assert.NotNil(t, netSet)
if netSet == nil {
return
}
assert.True(t, netSet.Has(net.ParseIP("127.0.0.1")))
assert.True(t, netSet.Has(net.ParseIP("10.0.0.55")))
assert.True(t, netSet.Has(net.ParseIP("::1")))
assert.True(t, netSet.Has(net.ParseIP("2001:db8::abcd")))
assert.False(t, netSet.Has(net.ParseIP("127.0.0.2")))
assert.False(t, netSet.Has(net.ParseIP("10.0.1.1")))
assert.False(t, netSet.Has(net.ParseIP("::2")))
assert.False(t, netSet.Has(net.ParseIP("2001:db9::1")))
}
func TestParseNetSetReturnsErrorForInvalidNetwork(t *testing.T) {
netSet, err := ParseNetSet([]string{"127.0.0.1", "10.0.0.1/24"})
assert.Nil(t, netSet)
assert.EqualError(t, err, "could not parse IP network (10.0.0.1/24)")
}
+15
View File
@@ -6,6 +6,7 @@ import (
"net/http/httptest"
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
@@ -39,6 +40,10 @@ var _ = Describe("RedirectToHTTPS suite", func() {
scope := &middlewareapi.RequestScope{
ReverseProxy: in.reverseProxy,
}
if in.reverseProxy {
req.RemoteAddr = "127.0.0.1:4180"
scope.TrustedProxies = newRedirectTrustedProxySet("127.0.0.1")
}
req = middlewareapi.AddRequestScope(req, scope)
rw := httptest.NewRecorder()
@@ -207,3 +212,13 @@ var _ = Describe("RedirectToHTTPS suite", func() {
}),
)
})
func newRedirectTrustedProxySet(cidrs ...string) *ip.NetSet {
set := ip.NewNetSet()
for _, cidr := range cidrs {
ipNet := ip.ParseIPNet(cidr)
Expect(ipNet).ToNot(BeNil())
set.AddIPNet(*ipNet)
}
return set
}
+5 -3
View File
@@ -6,14 +6,16 @@ import (
"github.com/google/uuid"
"github.com/justinas/alice"
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
)
func NewScope(reverseProxy bool, idHeader string) alice.Constructor {
func NewScope(reverseProxy bool, idHeader string, trustedProxies *ip.NetSet) alice.Constructor {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
scope := &middlewareapi.RequestScope{
ReverseProxy: reverseProxy,
RequestID: genRequestID(req, idHeader),
ReverseProxy: reverseProxy,
TrustedProxies: trustedProxies,
RequestID: genRequestID(req, idHeader),
}
req = middlewareapi.AddRequestScope(req, scope)
next.ServeHTTP(rw, req)
+18 -4
View File
@@ -6,6 +6,7 @@ import (
"github.com/google/uuid"
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
@@ -32,7 +33,7 @@ var _ = Describe("Scope Suite", func() {
Context("ReverseProxy is false", func() {
BeforeEach(func() {
handler := NewScope(false, testRequestHeader)(
handler := NewScope(false, testRequestHeader, nil)(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nextRequest = r
w.WriteHeader(200)
@@ -60,8 +61,15 @@ var _ = Describe("Scope Suite", func() {
})
Context("ReverseProxy is true", func() {
var trustedProxies *ip.NetSet
BeforeEach(func() {
handler := NewScope(true, testRequestHeader)(
var err error
trustedProxies, err = ip.ParseNetSet([]string{"127.0.0.1"})
Expect(err).ToNot(HaveOccurred())
handler := NewScope(true, testRequestHeader, trustedProxies)(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nextRequest = r
w.WriteHeader(200)
@@ -74,12 +82,18 @@ var _ = Describe("Scope Suite", func() {
Expect(scope).ToNot(BeNil())
Expect(scope.ReverseProxy).To(BeTrue())
})
It("stores the trusted proxies on the scope", func() {
scope := middlewareapi.GetRequestScope(nextRequest)
Expect(scope).ToNot(BeNil())
Expect(scope.TrustedProxies).To(BeIdenticalTo(trustedProxies))
})
})
Context("Request ID header is present", func() {
BeforeEach(func() {
request.Header.Add(testRequestHeader, testRequestID)
handler := NewScope(false, testRequestHeader)(
handler := NewScope(false, testRequestHeader, nil)(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nextRequest = r
w.WriteHeader(200)
@@ -97,7 +111,7 @@ var _ = Describe("Scope Suite", func() {
BeforeEach(func() {
uuid.SetRand(mockRand{})
handler := NewScope(true, testRequestHeader)(
handler := NewScope(true, testRequestHeader, nil)(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nextRequest = r
w.WriteHeader(200)
+14 -13
View File
@@ -15,30 +15,30 @@ const (
)
// GetRequestProto returns the request scheme or X-Forwarded-Proto if present
// and the request is proxied.
// and the request came from a trusted reverse proxy.
func GetRequestProto(req *http.Request) string {
proto := req.Header.Get(XForwardedProto)
if !IsProxied(req) || proto == "" {
if !CanTrustForwardedHeaders(req) || proto == "" {
proto = req.URL.Scheme
}
return proto
}
// GetRequestHost returns the request host header or X-Forwarded-Host if
// present and the request is proxied.
// present and the request came from a trusted reverse proxy.
func GetRequestHost(req *http.Request) string {
host := req.Header.Get(XForwardedHost)
if !IsProxied(req) || host == "" {
if !CanTrustForwardedHeaders(req) || host == "" {
host = req.Host
}
return host
}
// GetRequestURI return the request URI or X-Forwarded-Uri if present and the
// request is proxied.
// request came from a trusted reverse proxy.
func GetRequestURI(req *http.Request) string {
uri := req.Header.Get(XForwardedURI)
if !IsProxied(req) || uri == "" {
if !CanTrustForwardedHeaders(req) || uri == "" {
// Use RequestURI to preserve ?query
uri = req.URL.RequestURI()
}
@@ -46,8 +46,8 @@ func GetRequestURI(req *http.Request) string {
}
// GetRequestPath returns the request URI or X-Forwarded-Uri if present and the
// request is proxied but always strips the query parameters and only returns
// the pure path
// request came from a trusted reverse proxy but always strips the query
// parameters and only returns the pure path.
func GetRequestPath(req *http.Request) string {
uri := GetRequestURI(req)
@@ -64,17 +64,18 @@ func GetRequestPath(req *http.Request) string {
return uri
}
// IsProxied determines if a request was from a proxy based on the RequestScope
// ReverseProxy tracker.
func IsProxied(req *http.Request) bool {
// CanTrustForwardedHeaders determines if forwarded headers should be processed
// based on the RequestScope and the direct caller's address.
func CanTrustForwardedHeaders(req *http.Request) bool {
scope := middlewareapi.GetRequestScope(req)
if scope == nil {
return false
}
return scope.ReverseProxy
return scope.CanTrustForwardedHeaders(req)
}
func IsForwardedRequest(req *http.Request) bool {
return IsProxied(req) &&
return CanTrustForwardedHeaders(req) &&
req.Host != GetRequestHost(req)
}
+52 -12
View File
@@ -6,6 +6,7 @@ import (
"net/http/httptest"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests/util"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
@@ -19,8 +20,13 @@ var _ = Describe("Util Suite", func() {
uriNoQueryParams = "/test/endpoint"
)
var req *http.Request
var trustedProxies *ip.NetSet
BeforeEach(func() {
var err error
trustedProxies, err = ip.ParseNetSet([]string{"127.0.0.1"})
Expect(err).ToNot(HaveOccurred())
req = httptest.NewRequest(
http.MethodGet,
fmt.Sprintf("%s://%s%s", proto, host, uriWithQueryParams),
@@ -29,7 +35,7 @@ var _ = Describe("Util Suite", func() {
})
Context("GetRequestHost", func() {
Context("IsProxied is false", func() {
Context("trusted forwarded headers are disabled", func() {
BeforeEach(func() {
req = middleware.AddRequestScope(req, &middleware.RequestScope{})
})
@@ -44,10 +50,12 @@ var _ = Describe("Util Suite", func() {
})
})
Context("IsProxied is true", func() {
Context("trusted forwarded headers are enabled", func() {
BeforeEach(func() {
req.RemoteAddr = "127.0.0.1:4180"
req = middleware.AddRequestScope(req, &middleware.RequestScope{
ReverseProxy: true,
ReverseProxy: true,
TrustedProxies: trustedProxies,
})
})
@@ -63,7 +71,7 @@ var _ = Describe("Util Suite", func() {
})
Context("GetRequestProto", func() {
Context("IsProxied is false", func() {
Context("trusted forwarded headers are disabled", func() {
BeforeEach(func() {
req = middleware.AddRequestScope(req, &middleware.RequestScope{})
})
@@ -78,10 +86,12 @@ var _ = Describe("Util Suite", func() {
})
})
Context("IsProxied is true", func() {
Context("trusted forwarded headers are enabled", func() {
BeforeEach(func() {
req.RemoteAddr = "127.0.0.1:4180"
req = middleware.AddRequestScope(req, &middleware.RequestScope{
ReverseProxy: true,
ReverseProxy: true,
TrustedProxies: trustedProxies,
})
})
@@ -97,7 +107,7 @@ var _ = Describe("Util Suite", func() {
})
Context("GetRequestURI", func() {
Context("IsProxied is false", func() {
Context("trusted forwarded headers are disabled", func() {
BeforeEach(func() {
req = middleware.AddRequestScope(req, &middleware.RequestScope{})
})
@@ -112,10 +122,12 @@ var _ = Describe("Util Suite", func() {
})
})
Context("IsProxied is true", func() {
Context("trusted forwarded headers are enabled", func() {
BeforeEach(func() {
req.RemoteAddr = "127.0.0.1:4180"
req = middleware.AddRequestScope(req, &middleware.RequestScope{
ReverseProxy: true,
ReverseProxy: true,
TrustedProxies: trustedProxies,
})
})
@@ -131,7 +143,7 @@ var _ = Describe("Util Suite", func() {
})
Context("GetRequestPath", func() {
Context("IsProxied is false", func() {
Context("trusted forwarded headers are disabled", func() {
BeforeEach(func() {
req = middleware.AddRequestScope(req, &middleware.RequestScope{})
})
@@ -146,10 +158,12 @@ var _ = Describe("Util Suite", func() {
})
})
Context("IsProxied is true", func() {
Context("trusted forwarded headers are enabled", func() {
BeforeEach(func() {
req.RemoteAddr = "127.0.0.1:4180"
req = middleware.AddRequestScope(req, &middleware.RequestScope{
ReverseProxy: true,
ReverseProxy: true,
TrustedProxies: trustedProxies,
})
})
@@ -163,4 +177,30 @@ var _ = Describe("Util Suite", func() {
})
})
})
Context("CanTrustForwardedHeaders", func() {
It("returns false when no scope is present", func() {
Expect(util.CanTrustForwardedHeaders(req)).To(BeFalse())
})
It("returns true when the remote address is trusted", func() {
req.RemoteAddr = "127.0.0.1:4180"
req = middleware.AddRequestScope(req, &middleware.RequestScope{
ReverseProxy: true,
TrustedProxies: trustedProxies,
})
Expect(util.CanTrustForwardedHeaders(req)).To(BeTrue())
})
It("returns false when the remote address is untrusted", func() {
req.RemoteAddr = "192.0.2.10:4180"
req = middleware.AddRequestScope(req, &middleware.RequestScope{
ReverseProxy: true,
TrustedProxies: trustedProxies,
})
Expect(util.CanTrustForwardedHeaders(req)).To(BeFalse())
})
})
})
+2 -2
View File
@@ -498,7 +498,7 @@ var _ = Describe("HTTP Upstream Suite", func() {
handler := newHTTPUpstreamProxy(upstream, u, nil, nil)
proxyServer = httptest.NewServer(middleware.NewScope(false, "X-Request-Id")(handler))
proxyServer = httptest.NewServer(middleware.NewScope(false, "X-Request-Id", nil)(handler))
})
AfterEach(func() {
@@ -549,7 +549,7 @@ var _ = Describe("HTTP Upstream Suite", func() {
Expect(err).ToNot(HaveOccurred())
handler := newHTTPUpstreamProxy(upstream, u, nil, nil)
noPassHostServer := httptest.NewServer(middleware.NewScope(false, "X-Request-Id")(handler))
noPassHostServer := httptest.NewServer(middleware.NewScope(false, "X-Request-Id", nil)(handler))
defer noPassHostServer.Close()
origin := "http://example.localhost"
+12
View File
@@ -16,6 +16,7 @@ func validateAllowlists(o *options.Options) []string {
msgs = append(msgs, validateAuthRoutes(o)...)
msgs = append(msgs, validateAuthRegexes(o)...)
msgs = append(msgs, validateTrustedProxyIPs(o)...)
msgs = append(msgs, validateTrustedIPs(o)...)
if len(o.TrustedIPs) > 0 && o.ReverseProxy {
@@ -28,6 +29,17 @@ func validateAllowlists(o *options.Options) []string {
return msgs
}
// validateTrustedProxyIPs validates IP/CIDRs for trusted reverse proxies.
func validateTrustedProxyIPs(o *options.Options) []string {
msgs := []string{}
for i, ipStr := range o.TrustedProxyIPs {
if ip.ParseIPNet(ipStr) == nil {
msgs = append(msgs, fmt.Sprintf("trusted_proxy_ips[%d] (%s) could not be recognized", i, ipStr))
}
}
return msgs
}
// validateAuthRoutes validates method=path routes passed with options.SkipAuthRoutes
func validateAuthRoutes(o *options.Options) []string {
msgs := []string{}
+30
View File
@@ -23,6 +23,11 @@ var _ = Describe("Allowlist", func() {
errStrings []string
}
type validateTrustedProxyIPsTableInput struct {
trustedProxyIPs []string
errStrings []string
}
DescribeTable("validateRoutes",
func(r *validateRoutesTableInput) {
opts := &options.Options{
@@ -121,4 +126,29 @@ var _ = Describe("Allowlist", func() {
},
}),
)
DescribeTable("validateTrustedProxyIPs",
func(t *validateTrustedProxyIPsTableInput) {
opts := &options.Options{
TrustedProxyIPs: t.trustedProxyIPs,
}
Expect(validateTrustedProxyIPs(opts)).To(ConsistOf(t.errStrings))
},
Entry("Valid trusted proxy IPs", &validateTrustedProxyIPsTableInput{
trustedProxyIPs: []string{
"127.0.0.1",
"10.32.0.1/32",
"::1",
"2a12:105:ee7:9234:0:0:0:0/64",
},
errStrings: []string{},
}),
Entry("Invalid trusted proxy IPs", &validateTrustedProxyIPsTableInput{
trustedProxyIPs: []string{"[::1]", "alkwlkbn/32"},
errStrings: []string{
"trusted_proxy_ips[0] ([::1]) could not be recognized",
"trusted_proxy_ips[1] (alkwlkbn/32) could not be recognized",
},
}),
)
})