diff --git a/pkg/handler/reverseproxy.go b/pkg/handler/reverseproxy.go index af7b87c..ca8f21b 100644 --- a/pkg/handler/reverseproxy.go +++ b/pkg/handler/reverseproxy.go @@ -32,13 +32,13 @@ type ReverseProxySource interface { type ReverseProxy struct { *httputil.ReverseProxy EnableAccessLogs bool - IncludeIdToken bool + IncludeIDToken bool } -func NewUpstreamProxy(upstream *urllib.URL, enableAccessLogs bool, includeIdToken bool) *ReverseProxy { +func NewUpstreamProxy(upstream *urllib.URL, enableAccessLogs bool, includeIDToken bool) *ReverseProxy { rp := NewReverseProxy(upstream, true) rp.EnableAccessLogs = enableAccessLogs - rp.IncludeIdToken = includeIdToken + rp.IncludeIDToken = includeIDToken return rp } @@ -74,9 +74,12 @@ func NewReverseProxy(upstream *urllib.URL, preserveInboundHostHeader bool) *Reve r.Out.Header.Set("authorization", "Bearer "+accessToken) } - idToken, ok := mw.IdTokenFrom(r.In.Context()) + idToken, ok := mw.IDTokenFrom(r.In.Context()) if ok { r.Out.Header.Set("X-Wonderwall-Id-Token", idToken) + } else { + // remove the header if it was set by the client + r.Out.Header.Del("X-Wonderwall-Id-Token") } }, Transport: httpinternal.Transport(), @@ -140,9 +143,8 @@ func (rp *ReverseProxy) Handler(src ReverseProxySource, w http.ResponseWriter, r if isAuthenticated { ctx = mw.WithAccessToken(ctx, accessToken) span.SetAttributes(attribute.Bool("proxy.with_access_token", true)) - if rp.IncludeIdToken && sess != nil { - idToken := sess.IDToken() - ctx = mw.WithIdToken(ctx, idToken) + if rp.IncludeIDToken && sess != nil { + ctx = mw.WithIDToken(ctx, sess.IDToken()) span.SetAttributes(attribute.Bool("proxy.with_id_token", true)) } diff --git a/pkg/handler/reverseproxy_test.go b/pkg/handler/reverseproxy_test.go index 08986d2..5897889 100644 --- a/pkg/handler/reverseproxy_test.go +++ b/pkg/handler/reverseproxy_test.go @@ -444,7 +444,7 @@ func TestReverseProxy(t *testing.T) { assertUpstreamOKResponse(t, resp) }) - t.Run("request should not include idToken by default", func(t *testing.T) { + t.Run("request should not include id_token by default", func(t *testing.T) { cfg := mock.Config() cfg.UpstreamHost = up.URL.Host idp := mock.NewIdentityProvider(cfg) @@ -464,7 +464,7 @@ func TestReverseProxy(t *testing.T) { assertUpstreamOKResponse(t, resp) }) - t.Run("request should include idToken", func(t *testing.T) { + t.Run("request should include id_token", func(t *testing.T) { cfg := mock.Config() cfg.UpstreamHost = up.URL.Host cfg.UpstreamIncludeIdToken = true @@ -484,4 +484,24 @@ func TestReverseProxy(t *testing.T) { resp := get(t, rpClient, idp.RelyingPartyServer.URL) assertUpstreamOKResponse(t, resp) }) + + t.Run("request should strip incoming id_token if unauthenticated", func(t *testing.T) { + cfg := mock.Config() + cfg.UpstreamHost = up.URL.Host + cfg.UpstreamIncludeIdToken = true + idp := mock.NewIdentityProvider(cfg) + defer idp.Close() + + up.SetIdentityProvider(idp) + rpClient := idp.RelyingPartyClient() + + up.requestCallback = func(r *http.Request) { + assert.Empty(t, r.Header.Get("x-wonderwall-id-token")) + } + + resp := get(t, rpClient, idp.RelyingPartyServer.URL, header{ + "x-wonderwall-id-token", "some-id-token", + }) + assertUpstreamUnauthorizedResponse(t, resp) + }) } diff --git a/pkg/middleware/context.go b/pkg/middleware/context.go index 8d057fc..0958568 100644 --- a/pkg/middleware/context.go +++ b/pkg/middleware/context.go @@ -11,7 +11,7 @@ type contextKey string const ( ctxAccessToken = contextKey("AccessToken") - ctxIdToken = contextKey("IdToken") + ctxIDToken = contextKey("IDToken") ctxIngress = contextKey("Ingress") ctxPath = contextKey("Path") ) @@ -25,13 +25,13 @@ func WithAccessToken(ctx context.Context, accessToken string) context.Context { return context.WithValue(ctx, ctxAccessToken, accessToken) } -func IdTokenFrom(ctx context.Context) (string, bool) { - idToken, ok := ctx.Value(ctxIdToken).(string) +func IDTokenFrom(ctx context.Context) (string, bool) { + idToken, ok := ctx.Value(ctxIDToken).(string) return idToken, ok } -func WithIdToken(ctx context.Context, idToken string) context.Context { - return context.WithValue(ctx, ctxIdToken, idToken) +func WithIDToken(ctx context.Context, idToken string) context.Context { + return context.WithValue(ctx, ctxIDToken, idToken) } func IngressFrom(ctx context.Context) (ingress.Ingress, bool) {