zitadel/internal/api/http/header.go
Livio Spring b1f5b1979c
fix: respect x-zitadel-forwarded header again (#8473)
# Which Problems Are Solved

#8369 added the possibility to handle trusted domains for public hosts
as response. Additionally, the OIDC issuer is extracted from the
`DomainContext` and not from headers anymore.
This accidentally dropped support for the `x-zitadel-forwarded`.

# How the Problems Are Solved

Added `x-zitadel-forwarded` in the list of additionally handled headers.

# Additional Changes

None

# Additional Context

- relates to #8369
- reported in Discord:
https://discord.com/channels/927474939156643850/1275484169626980403
2024-08-21 16:36:16 +00:00

125 lines
3.0 KiB
Go

package http
import (
"context"
"net"
"net/http"
"strings"
)
const (
Authorization = "authorization"
Accept = "accept"
AcceptLanguage = "accept-language"
CacheControl = "cache-control"
ContentType = "content-type"
ContentLength = "content-length"
Expires = "expires"
Location = "location"
Origin = "origin"
Pragma = "pragma"
UserAgentHeader = "user-agent"
ForwardedFor = "x-forwarded-for"
ForwardedHost = "x-forwarded-host"
ForwardedProto = "x-forwarded-proto"
Forwarded = "forwarded"
ZitadelForwarded = "x-zitadel-forwarded"
XUserAgent = "x-user-agent"
XGrpcWeb = "x-grpc-web"
XRequestedWith = "x-requested-with"
XRobotsTag = "x-robots-tag"
IfNoneMatch = "If-None-Match"
LastModified = "Last-Modified"
Etag = "Etag"
ContentSecurityPolicy = "content-security-policy"
XXSSProtection = "x-xss-protection"
StrictTransportSecurity = "strict-transport-security"
XFrameOptions = "x-frame-options"
XContentTypeOptions = "x-content-type-options"
ReferrerPolicy = "referrer-policy"
FeaturePolicy = "feature-policy"
PermissionsPolicy = "permissions-policy"
ZitadelOrgID = "x-zitadel-orgid"
)
type key int
const (
httpHeaders key = iota
remoteAddr
domainCtx
)
func CopyHeadersToContext(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), httpHeaders, r.Header)
ctx = context.WithValue(ctx, remoteAddr, r.RemoteAddr)
r = r.WithContext(ctx)
h.ServeHTTP(w, r)
})
}
func HeadersFromCtx(ctx context.Context) (http.Header, bool) {
headers, ok := ctx.Value(httpHeaders).(http.Header)
return headers, ok
}
func OriginHeader(ctx context.Context) string {
headers, ok := ctx.Value(httpHeaders).(http.Header)
if !ok {
return ""
}
return headers.Get(Origin)
}
func RemoteIPFromCtx(ctx context.Context) string {
ctxHeaders, ok := HeadersFromCtx(ctx)
if !ok {
return RemoteAddrFromCtx(ctx)
}
forwarded, ok := GetForwardedFor(ctxHeaders)
if ok {
return forwarded
}
return RemoteAddrFromCtx(ctx)
}
func RemoteIPFromRequest(r *http.Request) net.IP {
return net.ParseIP(RemoteIPStringFromRequest(r))
}
func RemoteIPStringFromRequest(r *http.Request) string {
ip, ok := GetForwardedFor(r.Header)
if ok {
return ip
}
host, _, _ := net.SplitHostPort(r.RemoteAddr)
return host
}
func GetAuthorization(r *http.Request) string {
return r.Header.Get(Authorization)
}
func GetOrgID(r *http.Request) string {
return r.Header.Get(ZitadelOrgID)
}
func GetForwardedFor(headers http.Header) (string, bool) {
forwarded, ok := headers[ForwardedFor]
if ok {
ip := strings.TrimSpace(strings.Split(forwarded[0], ",")[0])
if ip != "" {
return ip, true
}
}
return "", false
}
func RemoteAddrFromCtx(ctx context.Context) string {
ctxRemoteAddr, _ := ctx.Value(remoteAddr).(string)
return ctxRemoteAddr
}