Repository: wso2/product-microgateway
Issue: Internal key caching issue

### Description:
<!-- Describe the issue -->

### Steps to reproduce:
use a valid internal key and invoke a created api
then tamper with the key (delete some characters) and use it to invoke the same api. -> it works (but this should not work)

### Affected Product Version:
<!-- Members can use Affected/*** labels -->
beta

### Environment details (with versions):
- OS:
- Client:
- Env (Docker/K8s):

---
### Optional Fields
#### Related Issues:
<!-- Any related issues from this/other repositories-->

#### Suggested Labels:
<!--Only to be used by non-members-->

#### Suggested Assignees:
<!--Only to be used by non-members-->


Changed files:
enforcer/src/main/java/org/wso2/choreo/connect/enforcer/dto/JWTTokenPayloadInfo.java
enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/InternalAPIKeyAuthenticator.java
integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/standalone/jwtValidator/InternalKeyTestCase.java

diff --git a/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/dto/JWTTokenPayloadInfo.java b/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/dto/JWTTokenPayloadInfo.java
index f07b0096e..d60cbaea3 100644
--- a/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/dto/JWTTokenPayloadInfo.java
+++ b/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/dto/JWTTokenPayloadInfo.java
@@ -28,7 +28,7 @@ public class JWTTokenPayloadInfo implements Serializable {
 
 
     JWTClaimsSet payload;
-    String rawPayload;
+    String accessToken;
 
     public JWTClaimsSet getPayload() {
         return payload;
@@ -38,11 +38,11 @@ public class JWTTokenPayloadInfo implements Serializable {
         this.payload = payload;
     }
 
-    public String getRawPayload() {
-        return rawPayload;
+    public String getAccessToken() {
+        return accessToken;
     }
 
-    public void setRawPayload(String rawPayload) {
-        this.rawPayload = rawPayload;
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
     }
 }
diff --git a/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/InternalAPIKeyAuthenticator.java b/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/InternalAPIKeyAuthenticator.java
index 69c91686b..f3201d068 100644
--- a/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/InternalAPIKeyAuthenticator.java
+++ b/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/InternalAPIKeyAuthenticator.java
@@ -122,9 +122,11 @@ public class InternalAPIKeyAuthenticator implements Authenticator {
                 JWTTokenPayloadInfo jwtTokenPayloadInfo = (JWTTokenPayloadInfo)
                         CacheProvider.getGatewayInternalKeyDataCache().getIfPresent(tokenIdentifier);
                 if (jwtTokenPayloadInfo != null) {
-                    String rawPayload = jwtTokenPayloadInfo.getRawPayload();
-                    isVerified = rawPayload.equals(splitToken[1]) && !isJwtTokenExpired(payload);
-                } else if (CacheProvider.getInvalidGatewayInternalKeyCache().getIfPresent(tokenIdentifier) != null) {
+                    String cachedToken = jwtTokenPayloadInfo.getAccessToken();
+                    isVerified = cachedToken.equals(internalKey) && !isJwtTokenExpired(payload);
+                } else if (CacheProvider.getInvalidGatewayInternalKeyCache().getIfPresent(tokenIdentifier) != null
+                        && internalKey
+                        .equals(CacheProvider.getInvalidGatewayInternalKeyCache().getIfPresent(tokenIdentifier))) {
                     if (log.isDebugEnabled()) {
                         log.debug("Internal Key retrieved from the invalid internal Key cache. Internal Key: "
                                 + FilterUtils.getMaskedToken(splitToken[0]));
@@ -168,7 +170,7 @@ public class InternalAPIKeyAuthenticator implements Authenticator {
                         }
                         jwtTokenPayloadInfo = new JWTTokenPayloadInfo();
                         jwtTokenPayloadInfo.setPayload(payload);
-                        jwtTokenPayloadInfo.setRawPayload(splitToken[1]);
+                        jwtTokenPayloadInfo.setAccessToken(internalKey);
                         CacheProvider.getGatewayInternalKeyDataCache().put(tokenIdentifier, jwtTokenPayloadInfo);
                     }
 
@@ -182,7 +184,7 @@ public class InternalAPIKeyAuthenticator implements Authenticator {
                             requestContext.getMatchedAPI().getAPIConfig().getUuid());
                 } else {
                     CacheProvider.getGatewayInternalKeyDataCache().invalidate(payload.getJWTID());
-                    CacheProvider.getInvalidGatewayInternalKeyCache().put(payload.getJWTID(), "carbon.super");
+                    CacheProvider.getInvalidGatewayInternalKeyCache().put(payload.getJWTID(), internalKey);
                     throw new APISecurityException(APIConstants.StatusCodes.UNAUTHENTICATED.getCode(),
                             APISecurityConstants.API_AUTH_INVALID_CREDENTIALS,
                             APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
diff --git a/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/standalone/jwtValidator/InternalKeyTestCase.java b/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/standalone/jwtValidator/InternalKeyTestCase.java
index b1700234c..bba6faf68 100644
--- a/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/standalone/jwtValidator/InternalKeyTestCase.java
+++ b/integration/test-integration/src/test/java/org/wso2/choreo/connect/tests/testcases/standalone/jwtValidator/InternalKeyTestCase.java
@@ -32,13 +32,30 @@ import java.util.Map;
 
 public class InternalKeyTestCase {
     protected String internalKey;
+    protected String tamperedInternalKey;
 
     @BeforeClass(description = "initialise the setup")
     void start() throws Exception {
         internalKey = TokenUtil.getJwtForPetstore(TestConstant.KEY_TYPE_PRODUCTION, null, true);
+        tamperedInternalKey = internalKey.substring(0, internalKey.length()-4);
     }
 
+    // First invoke with tampered internal key. This should fail.
     @Test(description = "Test to check the InternalKey is working")
+    public void invokeWithTamperedInternalKey() throws Exception {
+        // Set header
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Internal-Key", tamperedInternalKey);
+        HttpResponse response = HttpsClientRequest.doGet(Utils.getServiceURLHttps("/v2/pet/2") , headers);
+
+        Assert.assertNotNull(response);
+        Assert.assertEquals(response.getResponseCode(), HttpStatus.SC_UNAUTHORIZED,"Response code mismatched");
+        Assert.assertTrue(response.getData().contains("Invalid Credentials"), "Error response message mismatch");
+    }
+
+    // When invoke with original token even though the tampered key is in the invalid key cache,
+    // original token should pass.
+    @Test(description = "Test to check the InternalKey is working", dependsOnMethods = "invokeWithTamperedInternalKey")
     public void invokeInternalKeyHeaderSuccessTest() throws Exception {
         // Set header
         Map<String, String> headers = new HashMap<>();
@@ -61,6 +78,19 @@ public class InternalKeyTestCase {
         Assert.assertTrue(response.getData().contains("Invalid Credentials"), "Error response message mismatch");
     }
 
+    // After invoking with original key, it is cacahed as a success token. But again using the tampered key should fail.
+    @Test(description = "Test to check the InternalKey is working", dependsOnMethods = "invokeInternalKeyHeaderSuccessTest")
+    public void invokeAgainWithTamperedInternalKey() throws Exception {
+        // Set header
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Internal-Key", tamperedInternalKey);
+        HttpResponse response = HttpsClientRequest.doGet(Utils.getServiceURLHttps("/v2/pet/2") , headers);
+
+        Assert.assertNotNull(response);
+        Assert.assertEquals(response.getResponseCode(), HttpStatus.SC_UNAUTHORIZED,"Response code mismatched");
+        Assert.assertTrue(response.getData().contains("Invalid Credentials"), "Error response message mismatch");
+    }
+
     @Test(description = "Test to check the internal key auth validate expired token")
     public void invokeExpiredInternalKeyTest() throws Exception {