Le TCK officiel MicroProfile JWT 2.1 valide qu’une implémentation accepte, rejette et expose correctement un éventail de tokens forgés contre une application Arquillian de référence — clés inline, JWKS, JWE, claims standard, claims MP, transport Authorization et cookie, rotation de clés, signatures falsifiées, exp/nbf/iat aux bornes. Cervantes le passe à 206 / 206 sur la version 2.1 (mai 2026, jalon M6).

Statut

Métrique Valeur

Tests exécutés

206

Réussis

206 ✅

Échoués

0

Erreurs

0

Ignorés

0

Tout écart ultérieur doit être journalisé dans TCK.md du dépôt avec : nom de test, motif, plan de correction.

Prérequis

L’artefact org.eclipse.microprofile.jwt:microprofile-jwt-auth-tck:2.1 (et son classifier tests) est désormais disponible sur Maven Central — il se télécharge automatiquement. Le runner installe également cassini-tck dans le M2 local pour disposer du CassiniTestHarness.

sdk env                              # Java 25 + Maven 3.9.16
./mvnw -ntp install -DskipTests     # installe cervantes-core, cervantes-jaxrs, cervantes-cdi-vauban, …

Exécution du runner

Le script run-official-tck-mp-jwt-2.1.sh à la racine du dépôt orchestre toutes les variantes.

# Smoke — un test rapide pour valider l'installation
./run-official-tck-mp-jwt-2.1.sh

# Suite complète — équivalent du TCK officiel à 206 tests
./run-official-tck-mp-jwt-2.1.sh all

# Test ciblé via -Dtest=
./run-official-tck-mp-jwt-2.1.sh -Dtest=PublicKeyAsPEMTest

Le runner exécute Arquillian. Le rapport Surefire atterrit dans cervantes-tck/target/surefire-reports/.

Architecture du runner

cervantes-tck est in-reactor derrière le profil Maven tck de cervantes-parent (harmonisation TCK, pattern vidocq-runtime-tck-*) : un mvn install classique ne le construit ni ne le télécharge. Invocation directe : ./mvnw -P"tck,smoke" -pl cervantes-tck test (smoke) ou ./mvnw -P"tck,tck-official" -pl cervantes-tck test (suite complète). Gabarit initialement calqué sur heisenberg-tck.

Le runner était historiquement détaché du reactor (POM modelVersion 4.0.0 standalone, sans <parent>) parce que ShrinkWrap Maven Resolver 3.3, transitive du TCK officiel, ne savait pas parser les POMs Model 4.1.0. Cette contrainte est obsolète depuis la migration du workspace vers Maven 3.9.16 / Model 4.0.0, ce qui a permis la réintégration derrière le profil tck.

Stack assemblée par le runner :

Couche Composant

Spec

microprofile-jwt-auth-api 2.1, microprofile-jwt-auth-tck 2.1 (+ classifier tests)

Implémentation MP JWT

cervantes-mp-jwt-api, cervantes-api, cervantes-core, cervantes-cdi-vauban, cervantes-jaxrs

Container CDI

Vauban (io.vidocq.vauban.core) en mode embarqué — instancié par déploiement Arquillian

Container Arquillian

CervantesJwtDeployableContainer — pour chaque archive ShrinkWrap : extrait les bean classes, copie le META-INF/microprofile-config.properties en system properties, démarre Cassini + Chappe sur port aléatoire, réécrit les mp.jwt.verify.publickey.location=http://localhost:8080/… vers le port éphémère réel

Transport HTTP

Chappe (io.vidocq.chappe.http)

Cadre de test

Arquillian + REST (le TCK MP JWT n’est pas TestNG-only contrairement au TCK MP FT)

Exclusions documentées

Deux exclusions, non-applicables au profil Core + JWT visé par Cervantes :

Exclusion Justification

Tests …/tck/container/servlet/**

Tests destinés au profil container servlet Jakarta EE Full. Cervantes vise le profil Core (MicroProfile) — pas d’engagement Servlet 6.1. Le rôle Servlet est tenu par Foy, hors périmètre de cette implémentation MP JWT.

Groupe TestNG ee-security-optional

Tests marqués optional par la spec pour l’intégration Jakarta EE Security 3.0. Non requis pour la conformité MP JWT 2.1.

Les exclusions sont listées dans le fichier suite Arquillian/TestNG de cervantes-tck/src/test/resources/. Une exclusion ajoutée à l’avenir doit être tracée dans TCK.md avec sa justification.

Écarts résolus pendant la course au 100 %

Le TCK a révélé plusieurs écarts entre la spec et l’implémentation initiale ; tous ont été corrigés dans le moteur, pas masqués par des exclusions :

Composant Écart corrigé

KeyResolvers

Charge HTTP paresseuse + auto-détection PEM vs JWKS sur la même URL + relecture de l’URL après démarrage du serveur (le port n’est connu qu’après bind).

JwksSource

Ajout du header Accept: application/json (§9.2.2) + résolution classpath: honorée.

JwkParser

Parsing de clé privée JWK (d) et certificat (x5c).

Jwe / JweDecryptor

Contrôle explicite de l’algorithme requis + vérification cty=JWT pour les JWE nested.

ClaimResolver

raw_token exposé comme JsonString, aud simple converti en array d’un élément.

CervantesClaimExtension

Unwrap Provider<T> et Instance<T> dans la détection de types des points d’injection.

JwtAuthenticationFilter

Extraction token via cookie (§9.2.3), distinction des cas d’erreur, comportement anonyme sur token absent.

DefaultJsonWebToken

Principal anonyme → null pour tout claim demandé.

Prérequis livrés en amont

Deux fixes externes ont été nécessaires pour atteindre 206/206 :

  • cassini — patch @Context SecurityContext injecté dans une ressource pour refléter le JWT du JwtAuthenticationFilter. Mergé sur main de Cassini, REST TCK 4.0 (2535 tests) préservé.

  • vauban — fix VAU-INJ-PRIM : le TypeMapper exposait un point d’injection primitif (boolean) comme ClassType[name=boolean] au lieu de PrimitiveType, ce qui faisait échouer silencieusement l’injection @Claim boolean. Fix + test de régression PrimitiveQualifiedInjectionTest. Mergé sur main de Vauban.

Contrat qualité

Toute modification structurelle de cervantes-core, cervantes-cdi-vauban ou cervantes-jaxrs doit préserver le score 206 / 206 avant merge. Une régression TCK est bloquante au sens CI : la PR ne passe pas.

Pour aller plus loin