mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-17 04:37:48 +00:00
- fail-on-old regression tests for every shipped fix (R-rounds) - fuzz targets (parseJWT, bearer), concurrency-stress, shuffle-flake guards - coverage-closing contract tests (health-check backend, TLS-posture reuse) - r154 ID-token fixture built from parts to avoid false-positive secret scan
66 lines
2.5 KiB
Go
66 lines
2.5 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
cryptorand "crypto/rand"
|
|
"encoding/base64"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
// TestR170_PreservesChunkedOldAccessTokenOnNewTooLarge regresses a gap in the
|
|
// R122 fix to SetAccessToken (session.go): R122 covered the case where the
|
|
// PREVIOUS access token was stored inline (accessSession.Values["token"]),
|
|
// but NOT the case where the previous token was itself large enough to be
|
|
// stored as CHUNKS (sd.accessTokenChunks). The early
|
|
//
|
|
// for k := range sd.accessTokenChunks { delete }
|
|
//
|
|
// still ran before the new token's chunk validation, so when a new token's
|
|
// compressed size lands in the (70KB, 100KB] band (splitIntoChunks yields
|
|
// >50 chunks at maxCookieSize=1400) the write aborts after already wiping
|
|
// the previous chunked access token — the user keeps a session whose valid
|
|
// access token is gone, forcing an unnecessary re-authentication.
|
|
func TestR170_PreservesChunkedOldAccessTokenOnNewTooLarge(t *testing.T) {
|
|
sm, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, NewLogger("error"))
|
|
if err != nil {
|
|
t.Fatalf("session manager: %v", err)
|
|
}
|
|
req := httptest.NewRequest("GET", "/", nil)
|
|
sess, err := sm.GetSession(req)
|
|
if err != nil {
|
|
t.Fatalf("get session: %v", err)
|
|
}
|
|
t.Cleanup(sess.returnToPoolSafely)
|
|
|
|
// A previous access token large enough to be stored as chunks (> maxCookieSize)
|
|
// but under the 50-chunk cap: ~30KB of incompressible data.
|
|
oldRaw := make([]byte, 30*1024)
|
|
if _, err := cryptorand.Read(oldRaw); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
oldToken := base64.StdEncoding.EncodeToString(oldRaw)
|
|
|
|
sess.SetAccessToken(oldToken)
|
|
if got := sess.GetAccessToken(); got != oldToken {
|
|
t.Fatalf("precondition: chunked old token must be retrievable, got len %d (want %d)", len(got), len(oldToken))
|
|
}
|
|
if len(sess.accessTokenChunks) == 0 {
|
|
t.Fatal("precondition: old access token should be stored as chunks")
|
|
}
|
|
|
|
// A new incompressible token whose compressed size lands between
|
|
// 50*maxCookieSize (70KB) and the 100KB cap, so the chunked branch
|
|
// splits into >50 chunks and aborts after too-many-chunks.
|
|
newRaw := make([]byte, 60*1024)
|
|
if _, err := cryptorand.Read(newRaw); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
bigToken := base64.StdEncoding.EncodeToString(newRaw)
|
|
|
|
sess.SetAccessToken(bigToken)
|
|
|
|
if got := sess.GetAccessToken(); got != oldToken {
|
|
t.Fatalf("previous chunked access token must be preserved when storing a new oversized token fails, got len %d (want %d)", len(got), len(oldToken))
|
|
}
|
|
}
|