mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-17 04:37:48 +00:00
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:
+16
-6
@@ -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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user