test: add R-round regression and security suite

- 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
This commit is contained in:
2026-08-14 16:22:39 +01:00
parent cf0a7e2440
commit 6d96e8869b
116 changed files with 9261 additions and 182 deletions
+16 -6
View File
@@ -232,9 +232,16 @@ func (m *MockJWKCache) GetPublicKey(ctx context.Context, jwksURL, kid string, ht
return nil, fmt.Errorf("unsupported key type: %s", k.Kty)
}
}
return nil, fmt.Errorf("no matching public key found for kid: %s", kid)
}
// getPublicKeyFresh mirrors GetPublicKey for the interface; the mock serves
// the same configured key, so a signature retry yields the identical result.
func (m *MockJWKCache) getPublicKeyFresh(ctx context.Context, jwksURL, kid string, httpClient *http.Client) (crypto.PublicKey, error) {
return m.GetPublicKey(ctx, jwksURL, kid, httpClient)
}
func (m *MockJWKCache) Cleanup() {
// Mock cleanup is a no-op - we don't want to destroy the mock JWKS data
// Real cleanup is for expired entries, not resetting all data
@@ -2214,6 +2221,7 @@ func TestHandleExpiredToken(t *testing.T) {
tokenVerifier: ts.tOidc.tokenVerifier,
jwtVerifier: ts.tOidc.jwtVerifier,
initComplete: make(chan struct{}),
issuerURL: "https://test-issuer.com",
initiateAuthenticationFunc: func(rw http.ResponseWriter, req *http.Request, session *SessionData, redirectURL string) {
http.Redirect(rw, req, "/login", http.StatusFound)
},
@@ -2314,10 +2322,12 @@ func TestExtractGroupsAndRoles(t *testing.T) {
{
name: "Invalid groups format",
claims: map[string]interface{}{
"groups": 12345, // non-string, non-array scalar
"groups": 12345, // non-string, non-array scalar -> treated as empty, roles preserved
"roles": []interface{}{"role1"},
},
expectError: true,
expectGroups: []string{},
expectRoles: []string{"role1"},
expectError: false,
},
}
@@ -3759,7 +3769,7 @@ func TestAuthenticationFlowReplayDetection(t *testing.T) {
}
// Verify JTI is in cache (use shardedReplayCache which is the actual cache used)
exists := shardedReplayCache.Exists(jti)
exists := shardedReplayCache.Exists(replayCacheKey(ts.tOidc.issuerURL, jti))
if !exists {
t.Error("JTI should be added to replay cache during initial authentication")
}
@@ -3942,7 +3952,7 @@ func TestConcurrentTokenValidation(t *testing.T) {
// Verify all JTIs are in cache (use shardedReplayCache which is the actual cache used)
for i, jti := range jtis {
if !shardedReplayCache.Exists(jti) {
if !shardedReplayCache.Exists(replayCacheKey(ts.tOidc.issuerURL, jti)) {
t.Errorf("JTI %d (%s) should be in replay cache", i, jti)
}
}
@@ -3999,7 +4009,7 @@ func TestJTIBlacklistBehavior(t *testing.T) {
name: "JTI exists in blacklist after verification",
action: func() error {
// Use shardedReplayCache which is the actual cache used
if !shardedReplayCache.Exists(jti) {
if !shardedReplayCache.Exists(replayCacheKey(ts.tOidc.issuerURL, jti)) {
return fmt.Errorf("JTI not found in blacklist cache")
}
return nil
@@ -4107,7 +4117,7 @@ func TestSessionBasedTokenRevalidation(t *testing.T) {
// Check replay cache
// Use shardedReplayCache which is the actual cache used
inReplayCache := shardedReplayCache.Exists(jti)
inReplayCache := shardedReplayCache.Exists(replayCacheKey(ts.tOidc.issuerURL, jti))
if !inReplayCache {
t.Error("JTI should be in replay cache")
}