From aa9704ccc6d8b28c2005c4772db1edfd9f195f04 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Wed, 29 May 2024 16:01:44 +0100 Subject: [PATCH] Confirm that expired or wrong aud JWT cause 401 even if the cert chain is valid --- .../src/main/resources/application.properties | 1 + .../BearerTokenAuthorizationTest.java | 38 ++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/integration-tests/oidc-wiremock/src/main/resources/application.properties b/integration-tests/oidc-wiremock/src/main/resources/application.properties index a25886b891e32..367d87f1ad0e2 100644 --- a/integration-tests/oidc-wiremock/src/main/resources/application.properties +++ b/integration-tests/oidc-wiremock/src/main/resources/application.properties @@ -206,6 +206,7 @@ quarkus.oidc.bearer-certificate-full-chain.certificate-chain.trust-store-passwor quarkus.oidc.bearer-chain-custom-validator.certificate-chain.trust-store-file=truststore.p12 quarkus.oidc.bearer-chain-custom-validator.certificate-chain.trust-store-password=storepassword +quarkus.oidc.bearer-chain-custom-validator.token.audience=https://service.example.com quarkus.oidc.bearer-certificate-full-chain-root-only-wrongcname.certificate-chain.trust-store-file=truststore-rootcert.p12 quarkus.oidc.bearer-certificate-full-chain-root-only-wrongcname.certificate-chain.trust-store-password=storepassword diff --git a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java index af9862304184f..6977986b7d99f 100644 --- a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java +++ b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/BearerTokenAuthorizationTest.java @@ -199,7 +199,7 @@ public void testCertChainWithCustomValidator() throws Exception { // Send the token with the valid certificate chain and bind it to the token claim String accessToken = getAccessTokenForCustomValidator( List.of(subjectCert, intermediateCert, rootCert), - subjectPrivateKey, true); + subjectPrivateKey, "https://service.example.com", true, false); RestAssured.given().auth().oauth2(accessToken) .when().get("/api/admin/bearer-chain-custom-validator") @@ -207,10 +207,29 @@ public void testCertChainWithCustomValidator() throws Exception { .statusCode(200) .body(Matchers.containsString("admin")); - // Send the token with the valid certificate chain but do bind it to the token claim + // Send the token with the valid certificate chain but do not bind it to the token claim accessToken = getAccessTokenForCustomValidator( List.of(subjectCert, intermediateCert, rootCert), - subjectPrivateKey, false); + subjectPrivateKey, "https://service.example.com", false, false); + + RestAssured.given().auth().oauth2(accessToken) + .when().get("/api/admin/bearer-chain-custom-validator") + .then() + .statusCode(401); + + // Send the token with the valid certificate chain bound to the token claim, but expired + accessToken = getAccessTokenForCustomValidator( + List.of(subjectCert, intermediateCert, rootCert), + subjectPrivateKey, "https://service.example.com", true, true); + RestAssured.given().auth().oauth2(accessToken) + .when().get("/api/admin/bearer-chain-custom-validator") + .then() + .statusCode(401); + + // Send the token with the valid certificate chain but with the wrong audience + accessToken = getAccessTokenForCustomValidator( + List.of(subjectCert, intermediateCert, rootCert), + subjectPrivateKey, "https://server.example.com", true, false); RestAssured.given().auth().oauth2(accessToken) .when().get("/api/admin/bearer-chain-custom-validator") @@ -748,18 +767,25 @@ private String getAccessTokenWithCertChain(List chain, } private String getAccessTokenForCustomValidator(List chain, - PrivateKey privateKey, boolean setLeafCertThumbprint) throws Exception { + PrivateKey privateKey, String aud, boolean setLeafCertThumbprint, boolean expired) throws Exception { JwtClaimsBuilder builder = Jwt.preferredUserName("alice") .groups("admin") .issuer("https://server.example.com") - .audience("https://service.example.com") + .audience(aud) .claim("root-certificate-thumbprint", TrustStoreUtils.calculateThumprint(chain.get(chain.size() - 1))); if (setLeafCertThumbprint) { builder.claim("leaf-certificate-thumbprint", TrustStoreUtils.calculateThumprint(chain.get(0))); } - return builder.jws() + if (expired) { + builder.expiresIn(1); + } + String jwt = builder.jws() .chain(chain) .sign(privateKey); + if (expired) { + Thread.sleep(2000); + } + return jwt; } private String getAccessTokenWithoutKidAndThumbprint(String userName, Set groups) {