mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2026-10-17 20:17:03 +02:00
@@ -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, "/")
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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\"")
|
||||
|
||||
Reference in New Issue
Block a user