fix(middleware): forward configured headers on SSE/WebSocket bypass (#162)

The SSE and WebSocket bypass forwarded only X-Forwarded-User. It did not
apply the configured headers. Backends that authenticate the proxy with a
shared-secret header returned 401 on WebSocket upgrades. Version 0.8.x sent
WebSocket upgrades through the normal flow, so this is a regression.

The bypass now renders the header templates through applyHeaderTemplates,
which forwardAuthorized also uses. Templates use the ID-token claims from
the session cookie. If the session has no ID token, they use the
access-token claims.

The bypass now also rejects a session that the IdP logged out through
back-channel or front-channel logout. Without this check, a logged-out
cookie can open streams with the proxy secret attached.

Add a yaegi check for the WebSocket case. Move tokenWithGroups to the
shared JWT test helpers, as FIX-41 requires.

Claude-Session: https://claude.ai/code/session_01G1d1n1BrHHHw8dBUkbiBPC
This commit is contained in:
2026-09-28 15:24:33 +01:00
parent 45e99551f9
commit c9844d0ff2
6 changed files with 468 additions and 93 deletions
+18
View File
@@ -80,3 +80,21 @@ func makeTestJWT(t *testing.T, claims map[string]interface{}) string {
return base64.RawURLEncoding.EncodeToString(hdr) + "." +
base64.RawURLEncoding.EncodeToString(pl) + ".c2ln"
}
// tokenWithGroups builds a JWT whose signature segment is long enough to pass
// the session chunk manager's format validation (>=10 chars) so the access
// token round-trips through Set/GetAccessToken.
func tokenWithGroups(t *testing.T, claims map[string]interface{}) string {
t.Helper()
hdr, _ := json.Marshal(map[string]string{"alg": "RS256", "typ": "JWT"})
pl, _ := json.Marshal(claims)
// Varied (non-repeating) signature bytes so the session chunk manager's
// repeated-character heuristic does not reject it.
sigBytes := make([]byte, 32)
for i := range sigBytes {
sigBytes[i] = byte(i + 1)
}
sig := base64.RawURLEncoding.EncodeToString(sigBytes)
return base64.RawURLEncoding.EncodeToString(hdr) + "." +
base64.RawURLEncoding.EncodeToString(pl) + "." + sig
}