feat(observability): 增加 OIDC 失败关联诊断
将 OIDC Access Token 与 ID Token 校验失败映射为固定安全分类,并生成 diagnosticId 关联浏览器错误与服务端日志。日志不记录授权码、Token 或底层敏感输入,且保留 errors.Is(ErrUnauthorized) 兼容语义。 验证:go test ./... -count=1(apps/api)
This commit is contained in:
@@ -91,20 +91,30 @@ func TestOIDCVerifierRejectsMissingOrMismatchedSecurityClaims(t *testing.T) {
|
||||
RequiredScopes: []string{"gateway.access"}, HTTPClient: server.Client(),
|
||||
})
|
||||
tests := []struct {
|
||||
name string
|
||||
mutate func(jwt.MapClaims)
|
||||
name, wantCategory string
|
||||
mutate func(jwt.MapClaims)
|
||||
}{
|
||||
{"missing nbf", func(claims jwt.MapClaims) { delete(claims, "nbf") }},
|
||||
{"wrong audience", func(claims jwt.MapClaims) { claims["aud"] = "other-api" }},
|
||||
{"wrong tenant", func(claims jwt.MapClaims) { claims["tid"] = "tenant-2" }},
|
||||
{"missing scope", func(claims jwt.MapClaims) { claims["scope"] = "openid" }},
|
||||
{"unmapped role", func(claims jwt.MapClaims) { claims["roles"] = []string{"other.admin"} }},
|
||||
{"missing nbf", "NBF_MISSING", func(claims jwt.MapClaims) { delete(claims, "nbf") }},
|
||||
{"missing exp", "EXP_MISSING", func(claims jwt.MapClaims) { delete(claims, "exp") }},
|
||||
{"missing issuer", "ISSUER_MISSING", func(claims jwt.MapClaims) { delete(claims, "iss") }},
|
||||
{"missing audience", "AUDIENCE_MISSING", func(claims jwt.MapClaims) { delete(claims, "aud") }},
|
||||
{"wrong audience", "AUDIENCE_INVALID", func(claims jwt.MapClaims) { claims["aud"] = "other-api" }},
|
||||
{"wrong tenant", "STABLE_IDENTITY_CLAIMS_INVALID", func(claims jwt.MapClaims) { claims["tid"] = "tenant-2" }},
|
||||
{"missing scope", "REQUIRED_SCOPE_MISSING", func(claims jwt.MapClaims) { claims["scope"] = "openid" }},
|
||||
{"unmapped role", "MAPPED_ROLE_MISSING", func(claims jwt.MapClaims) { claims["roles"] = []string{"other.admin"} }},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
raw := signedOIDCToken(t, issuer, "ec-key", jwt.SigningMethodES256, key, test.mutate)
|
||||
if _, err := verifier.Verify(context.Background(), raw); err == nil {
|
||||
t.Fatal("expected token to be rejected")
|
||||
} else {
|
||||
if !errors.Is(err, ErrUnauthorized) {
|
||||
t.Fatalf("validation error no longer wraps ErrUnauthorized: %v", err)
|
||||
}
|
||||
if category := OIDCValidationCategory(err); category != test.wantCategory {
|
||||
t.Fatalf("validation category=%q, want %q", category, test.wantCategory)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user