Files
oauth2-proxy/pkg/requests/util/util.go
bea3f04bf8 release: v7.15.5 (#3553)
* update to release version v7.15.5

* Merge commit from fork

Signed-off-by: Jan Larwig <jan@larwig.com>
Co-authored-by: blakeroberts-wk <blake.roberts@workiva.com>

* Merge commit from fork

Signed-off-by: Jan Larwig <jan@larwig.com>

* Merge commit from fork

* fix: validate trusted IP proxy headers

Respect trusted proxy boundaries before using real-client-IP headers for authentication bypass decisions and safely traverse X-Forwarded-For chains.

Signed-off-by: Jan Larwig <jan@larwig.com>

* fix: trusted-ip header bypass

Signed-off-by: Jan Larwig <jan@larwig.com>

* docs: add changelog entry

Signed-off-by: Jan Larwig <jan.larwig@digits.schwarz>

---------

Signed-off-by: Jan Larwig <jan@larwig.com>
Signed-off-by: Jan Larwig <jan.larwig@digits.schwarz>

* docs: changelog for v7.15.5

Signed-off-by: Jan Larwig <jan.larwig@digits.schwarz>

* docs: update order of owners for prow

Signed-off-by: Jan Larwig <jan.larwig@digits.schwarz>

* ci: make the linter happy again

Signed-off-by: Jan Larwig <jan.larwig@digits.schwarz>

---------

Signed-off-by: Jan Larwig <jan@larwig.com>
Signed-off-by: Jan Larwig <jan.larwig@digits.schwarz>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jan Larwig <jan@larwig.com>
Co-authored-by: blakeroberts-wk <blake.roberts@workiva.com>
Co-authored-by: Jan Larwig <jan.larwig@digits.schwarz>
2026-10-01 11:01:25 +02:00

95 lines
2.8 KiB
Go

package util
import (
"errors"
"net/http"
"net/url"
"strings"
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
)
const (
XForwardedProto = "X-Forwarded-Proto"
XForwardedHost = "X-Forwarded-Host"
XForwardedURI = "X-Forwarded-Uri"
)
// GetRequestProto returns the request scheme or X-Forwarded-Proto if present
// and the request came from a trusted reverse proxy.
func GetRequestProto(req *http.Request) string {
proto := req.Header.Get(XForwardedProto)
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 came from a trusted reverse proxy.
func GetRequestHost(req *http.Request) string {
host := req.Header.Get(XForwardedHost)
if !CanTrustForwardedHeaders(req) || host == "" {
host = req.Host
}
return host
}
// GetRequestURI return the request URI or X-Forwarded-Uri if present and the
// request came from a trusted reverse proxy.
func GetRequestURI(req *http.Request) string {
uri := req.Header.Get(XForwardedURI)
if !CanTrustForwardedHeaders(req) || uri == "" {
// Use RequestURI to preserve ?query
uri = req.URL.RequestURI()
}
return uri
}
// GetRequestPath returns a decoded path suitable for skip-auth matching, using
// X-Forwarded-Uri only for a trusted reverse proxy. An error means the path must
// not grant an authentication exemption. It does not modify the request URL.
func GetRequestPath(req *http.Request) (string, error) {
uri := GetRequestURI(req)
if !strings.HasPrefix(uri, "/") || strings.ContainsAny(uri, "# \t\r\n") {
return "", errors.New("request target is not an unambiguous origin-form URI")
}
// Unlike url.Parse, ParseRequestURI keeps a leading // in the path.
parsedURL, err := url.ParseRequestURI(uri)
if err != nil {
return "", errors.New("invalid request target")
}
requestPath := parsedURL.Path
if strings.ContainsAny(requestPath, ";\\#?") || strings.Contains(requestPath, "//") {
return "", errors.New("request path contains ambiguous separators")
}
for _, char := range requestPath {
if char < 0x20 || char == 0x7f {
return "", errors.New("request path contains a control character")
}
}
for _, segment := range strings.Split(requestPath, "/") {
if segment == "." || segment == ".." {
return "", errors.New("request path contains a dot segment")
}
}
return requestPath, nil
}
// 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.CanTrustForwardedHeaders(req)
}
func IsForwardedRequest(req *http.Request) bool {
return CanTrustForwardedHeaders(req) &&
req.Host != GetRequestHost(req)
}