From 7d65eeff3564202ef2db6850734b66e59b4dc701 Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Mon, 22 May 2023 09:14:24 +0530 Subject: [PATCH 1/8] Add support to include kid claim to backend JWT header --- .../distribution/product/src/main/resources/conf/default.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/distribution/product/src/main/resources/conf/default.json b/modules/distribution/product/src/main/resources/conf/default.json index d4b057c09e..25717515f7 100644 --- a/modules/distribution/product/src/main/resources/conf/default.json +++ b/modules/distribution/product/src/main/resources/conf/default.json @@ -458,5 +458,6 @@ "apim.analytics.properties.keystore_password": "$ref{keystore.primary.password}", "apim.analytics.properties.truststore_location": "${carbon.home}/repository/resources/security/$ref{truststore.file_name}", "apim.analytics.properties.truststore_password": "$ref{truststore.password}", - "tenant_mgt.disable_email_domain_validation": true + "tenant_mgt.disable_email_domain_validation": true, + "apim.jwt.use_kid_property": false } From 1dc4c02df1675df272962433d563ce295ad74094 Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Thu, 20 Jul 2023 11:24:42 +0530 Subject: [PATCH 2/8] Change the default to true --- .../distribution/product/src/main/resources/conf/default.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/distribution/product/src/main/resources/conf/default.json b/modules/distribution/product/src/main/resources/conf/default.json index 25717515f7..9895d593f3 100644 --- a/modules/distribution/product/src/main/resources/conf/default.json +++ b/modules/distribution/product/src/main/resources/conf/default.json @@ -459,5 +459,5 @@ "apim.analytics.properties.truststore_location": "${carbon.home}/repository/resources/security/$ref{truststore.file_name}", "apim.analytics.properties.truststore_password": "$ref{truststore.password}", "tenant_mgt.disable_email_domain_validation": true, - "apim.jwt.use_kid_property": false + "apim.jwt.use_kid_property": true } From c4bedc77bc1aeea942215226300ae5f2b04aa87c Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Fri, 28 Jul 2023 09:02:12 +0530 Subject: [PATCH 3/8] Bump carbon.apimgt.version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2186f82e73..994e027265 100644 --- a/pom.xml +++ b/pom.xml @@ -1280,7 +1280,7 @@ 9.0.453 - 9.28.160 + 9.28.161 [9.0.0, 10.0.0) From ef5d9f368398e6b28eb45d6acb1095648aebd9b2 Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Fri, 28 Jul 2023 14:57:43 +0530 Subject: [PATCH 4/8] Fix JWTTestCase failure due to kid claim addition to backend JWT header --- .../java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java index fc3dcb5552..c58d863531 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java @@ -55,7 +55,7 @@ public static void verifyJWTHeader(String decodedJWTHeaderString) throws JSONExc JSONObject jsonHeaderObject = new JSONObject(decodedJWTHeaderString); Assert.assertEquals(jsonHeaderObject.getString("typ"), "JWT"); Assert.assertEquals(jsonHeaderObject.getString("alg"), "RS256"); - Assert.assertFalse(jsonHeaderObject.has("kid")); + Assert.assertTrue(jsonHeaderObject.has("kid")); } /** From 155b1dcda26708d72e4c3530ac9c91062e56eb5c Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Mon, 11 Sep 2023 14:34:16 +0530 Subject: [PATCH 5/8] Add integration test for JWKS endpoint support --- .../integration/tests/jwt/BackendJWTUtil.java | 9 +++++++- .../am/integration/tests/jwt/JWTTestCase.java | 23 +++++++++++++++---- pom.xml | 4 ++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java index c58d863531..adb6dbbc89 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/BackendJWTUtil.java @@ -49,13 +49,20 @@ public static void verifySignature(Header jwtheader) throws UnsupportedEncodingE * verify JWT Header * * @param decodedJWTHeaderString decoded JWT Header value + * @param jwksKidClaim kid claim in JWKS endpoint * @throws JSONException if JSON payload is malformed */ - public static void verifyJWTHeader(String decodedJWTHeaderString) throws JSONException { + public static void verifyJWTHeader(String decodedJWTHeaderString, String jwksKidClaim) throws JSONException { JSONObject jsonHeaderObject = new JSONObject(decodedJWTHeaderString); Assert.assertEquals(jsonHeaderObject.getString("typ"), "JWT"); Assert.assertEquals(jsonHeaderObject.getString("alg"), "RS256"); + + // Verify kid claim: check if kid claim in JWT header match with that of JWKS endpoint Assert.assertTrue(jsonHeaderObject.has("kid")); + if (jwksKidClaim != null) { + Assert.assertEquals(jsonHeaderObject.getString("kid"), jwksKidClaim, "kid claim in JWT header " + + "does not match with that of JWKS endpoint"); + } } /** diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/JWTTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/JWTTestCase.java index dcb6506b30..8ede9d48b6 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/JWTTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/JWTTestCase.java @@ -28,6 +28,7 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; import org.testng.Assert; @@ -76,6 +77,7 @@ import javax.ws.rs.core.Response; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.AssertJUnit.assertTrue; @@ -107,6 +109,7 @@ public class JWTTestCase extends APIManagerLifecycleBaseTest { URL tokenEndpointURL; private String tokenURL; private String identityLoginURL; + private String jwksKidClaim; private final String CALLBACK_URL = "https://localhost:9443/store/"; @BeforeClass(alwaysRun = true) @@ -191,6 +194,16 @@ public void setEnvironment() throws Exception { APIMIntegrationConstants.IS_API_EXISTS); waitForAPIDeploymentSync(user.getUserName(), api2Request.getName(), api2Request.getVersion(), APIMIntegrationConstants.IS_API_EXISTS); + + // Invoke JWKS endpoint and retrieve kid claim to validate backend JWT + HttpClient httpclient = HttpClientBuilder.create().build(); + HttpGet jwksGet = new HttpGet(getAPIInvocationURLHttp("jwks")); + HttpResponse jwksResponse = httpclient.execute(jwksGet); + assertEquals(jwksResponse.getStatusLine().getStatusCode(), HTTP_RESPONSE_CODE_OK, + "Invocation fails for JWKS GET request"); + String jwksResponseString = EntityUtils.toString(jwksResponse.getEntity(), "UTF-8"); + JSONObject jwksResponseObject = new JSONObject(jwksResponseString); + jwksKidClaim = jwksResponseObject.getJSONArray("keys").getJSONObject(0).getString("kid"); } @Test(groups = {"wso2.am"}, description = "Backend JWT Token Generation for Oauth Based App") @@ -225,7 +238,7 @@ public void testEnableJWTAndClaimsForOauthApp() throws Exception { //Do the signature verification for super tenant as tenant key store not there accessible BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); log.info("JWT Received ==" + jsonObject.toString()); //Validate expiry time @@ -273,7 +286,7 @@ public void testEnableJWTAndClaimsForJWTApp() throws Exception { //Do the signature verification BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims @@ -341,7 +354,7 @@ public void testEnableJWTAndClaimsForAPIKeyApp() throws Exception { //Do the signature verification BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims @@ -386,7 +399,7 @@ public void testBackendJWTWithClientCredentialsGrant() throws Exception { //Do the signature verification BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims @@ -434,7 +447,7 @@ public void testBackendJWTWithAuthCodeGrant() throws Exception { //Do the signature verification BackendJWTUtil.verifySignature(jwtheader); log.debug("Decoded JWT header String = " + decodedJWTHeaderString); - BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString); + BackendJWTUtil.verifyJWTHeader(decodedJWTHeaderString, jwksKidClaim); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims diff --git a/pom.xml b/pom.xml index 994e027265..71debad6d4 100644 --- a/pom.xml +++ b/pom.xml @@ -1277,10 +1277,10 @@ 5.3.5 - 9.0.453 + 9.0.468 - 9.28.161 + 9.28.175 [9.0.0, 10.0.0) From 795bcd6e56ffdc7ecbf243515bb32d8775b6a965 Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Mon, 11 Sep 2023 21:18:57 +0530 Subject: [PATCH 6/8] Fix URLSafeJWTTestCase --- .../am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java index b175554f07..1b6191d48a 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java @@ -212,7 +212,7 @@ public void testEnableJWTAndClaimsForJWTApp() throws Exception { JSONObject jsonHeaderObject = new JSONObject(decodedJWTHeaderString); Assert.assertEquals(jsonHeaderObject.getString("typ"), "JWT"); Assert.assertEquals(jsonHeaderObject.getString("alg"), "RS256"); - Assert.assertFalse(jsonHeaderObject.has("kid")); + Assert.assertTrue(jsonHeaderObject.has("kid")); JSONObject jsonObject = new JSONObject(decodedJWTString); // check default claims From 25fb718b8d1afc7af8428ab232afdf0ce2fd9c8a Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Tue, 12 Sep 2023 10:09:03 +0530 Subject: [PATCH 7/8] Fix URLSafeJWTTestCase --- .../am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java index 1b6191d48a..ac8253b4bf 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/jwt/urlsafe/URLSafeJWTTestCase.java @@ -156,7 +156,7 @@ public void testEnableJWTAndClaimsForOauthApp() throws Exception { JSONObject jsonHeaderObject = new JSONObject(decodedJWTHeaderString); Assert.assertEquals(jsonHeaderObject.getString("typ"), "JWT"); Assert.assertEquals(jsonHeaderObject.getString("alg"), "RS256"); - Assert.assertFalse(jsonHeaderObject.has("kid")); + Assert.assertTrue(jsonHeaderObject.has("kid")); JSONObject jsonObject = new JSONObject(decodedJWTString); log.info("JWT Received ==" + jsonObject.toString()); // check default claims From 9b6789bf81299ea6a2181933d550541e391eb3ba Mon Sep 17 00:00:00 2001 From: Ashera Silva Date: Wed, 13 Sep 2023 11:40:19 +0530 Subject: [PATCH 8/8] Bump carbon.apimgt.version --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 71debad6d4..994e027265 100644 --- a/pom.xml +++ b/pom.xml @@ -1277,10 +1277,10 @@ 5.3.5 - 9.0.468 + 9.0.453 - 9.28.175 + 9.28.161 [9.0.0, 10.0.0)