From 6a53576739fd6b96d4cd32f466230fb8b4990234 Mon Sep 17 00:00:00 2001 From: Mevan Date: Wed, 6 Nov 2024 17:26:12 +0530 Subject: [PATCH] Add Component ID to API key identifier --- .../enforcer/security/jwt/APIKeyAuthenticator.java | 11 ++++++++--- .../enforcer/security/jwt/APIKeyConstants.java | 2 ++ .../connect/enforcer/security/jwt/APIKeyUtils.java | 8 ++++---- .../security/jwt/APIKeyAuthenticatorTest.java | 13 +++++++++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyAuthenticator.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyAuthenticator.java index caf7f8ff89..c009838caf 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyAuthenticator.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyAuthenticator.java @@ -109,7 +109,12 @@ protected String retrieveTokenFromRequestCtx(RequestContext requestContext) thro APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE); } String keyHash = APIKeyUtils.generateAPIKeyHash(apiKey); - Object cachedJWT = CacheProvider.getGatewayAPIKeyJWTCache().getIfPresent(keyHash); + String componentId = requestContext.getMatchedAPI().getChoreoComponentInfo().getComponentID(); + if (componentId == null) { + componentId = ""; + } + String apiKeyId = keyHash + APIKeyConstants.API_KEY_ID_SEPARATOR + componentId; + Object cachedJWT = CacheProvider.getGatewayAPIKeyJWTCache().getIfPresent(apiKeyId); if (cachedJWT != null && !APIKeyUtils.isJWTExpired((String) cachedJWT)) { if (log.isDebugEnabled()) { log.debug("Token retrieved from the cache. Token: " + FilterUtils.getMaskedToken(keyHash)); @@ -117,14 +122,14 @@ protected String retrieveTokenFromRequestCtx(RequestContext requestContext) thro return (String) cachedJWT; } // Exchange the API Key to a JWT token. - Optional jwt = APIKeyUtils.exchangeAPIKeyToJWT(keyHash); + Optional jwt = APIKeyUtils.exchangeAPIKeyToJWT(apiKeyId); if (jwt.isEmpty()) { throw new APISecurityException(APIConstants.StatusCodes.UNAUTHENTICATED.getCode(), APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE); } // Cache the JWT token. - CacheProvider.getGatewayAPIKeyJWTCache().put(keyHash, jwt.get()); + CacheProvider.getGatewayAPIKeyJWTCache().put(apiKeyId, jwt.get()); return jwt.get(); } diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyConstants.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyConstants.java index 82fc8613ba..746213361c 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyConstants.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyConstants.java @@ -28,6 +28,8 @@ public class APIKeyConstants { public static final String API_KEY_JSON_KEY = "key"; + public static final String API_KEY_ID_SEPARATOR = "#"; + public static final String PAT_EXCHANGE_ENDPOINT = "/internal/pat"; public static final String API_KEY_EXCHANGE_ENDPOINT = "/internal/apiKey/token"; } diff --git a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyUtils.java b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyUtils.java index 19351df21a..6a929ce6f0 100644 --- a/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyUtils.java +++ b/enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyUtils.java @@ -142,12 +142,12 @@ public static Optional exchangePATToJWT(String patHash) { } /** - * Exchange a given API key hash to a JWT token. + * Exchange a given API key ID to a JWT token. * - * @param apiKeyHash API Key Hash + * @param apiKeyId API Key Hash + "#" + Target component ID. * @return JWT corresponding to given API Key. */ - public static Optional exchangeAPIKeyToJWT(String apiKeyHash) { + public static Optional exchangeAPIKeyToJWT(String apiKeyId) { URL url = null; try { @@ -162,7 +162,7 @@ public static Optional exchangeAPIKeyToJWT(String apiKeyHash) { // Create a request to exchange API key to JWT. HttpPost exchangeRequest = new HttpPost(url.toURI()); exchangeRequest.addHeader("Content-Type", ContentType.APPLICATION_JSON.toString()); - exchangeRequest.setEntity(new StringEntity(createKeyHashExchangeRequest(apiKeyHash))); + exchangeRequest.setEntity(new StringEntity(createKeyHashExchangeRequest(apiKeyId))); try (CloseableHttpResponse response = httpClient.execute(exchangeRequest)) { if (response.getStatusLine().getStatusCode() == 200) { HttpEntity entity = response.getEntity(); diff --git a/enforcer-parent/enforcer/src/test/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyAuthenticatorTest.java b/enforcer-parent/enforcer/src/test/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyAuthenticatorTest.java index 47371e7fd2..082f282a7b 100644 --- a/enforcer-parent/enforcer/src/test/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyAuthenticatorTest.java +++ b/enforcer-parent/enforcer/src/test/java/org/wso2/choreo/connect/enforcer/security/jwt/APIKeyAuthenticatorTest.java @@ -30,6 +30,7 @@ import org.wso2.carbon.apimgt.common.gateway.dto.JWTConfigurationDto; import org.wso2.choreo.connect.enforcer.common.CacheProvider; import org.wso2.choreo.connect.enforcer.commons.model.APIConfig; +import org.wso2.choreo.connect.enforcer.commons.model.ChoreoComponentInfo; import org.wso2.choreo.connect.enforcer.commons.model.RequestContext; import org.wso2.choreo.connect.enforcer.config.ConfigHolder; import org.wso2.choreo.connect.enforcer.config.EnforcerConfig; @@ -68,9 +69,13 @@ public void setup() { public void retrieveTokenFromRequestCtxTest_invalidKey() { RequestContext.Builder requestContextBuilder = new RequestContext.Builder("/api-key"); + ChoreoComponentInfo choreoComponentInfo = new ChoreoComponentInfo(); + choreoComponentInfo.setComponentID("component_id"); requestContextBuilder.matchedAPI(new APIConfig.Builder("Petstore") .basePath("/test") + .uuid("6003a3b7-af0f-4fb3-853e-a6562b2345f2") .apiType("REST") + .choreoComponentInfo(choreoComponentInfo) .build()); Map headersMap = new HashMap<>(); headersMap.put("choreo-api-key", @@ -97,9 +102,13 @@ public void retrieveTokenFromRequestCtxTest_cached_validKey() throws APISecurity PowerMockito.when(CacheProvider.getGatewayAPIKeyJWTCache()).thenReturn(gatewayAPIKeyJWTCache); PowerMockito.when(gatewayAPIKeyJWTCache.getIfPresent(Mockito.anyString())).thenReturn(mockJWT); + ChoreoComponentInfo choreoComponentInfo = new ChoreoComponentInfo(); + choreoComponentInfo.setComponentID("component_id"); RequestContext.Builder requestContextBuilder = new RequestContext.Builder("/api-key"); requestContextBuilder.matchedAPI(new APIConfig.Builder("Petstore") .basePath("/test") + .uuid("6003a3b7-af0f-4fb3-853e-a6562b2345f2") + .choreoComponentInfo(choreoComponentInfo) .apiType("REST") .build()); Map headersMap = new HashMap<>(); @@ -128,10 +137,14 @@ public void retrieveTokenFromRequestCtxTest_validKey() throws APISecurityExcepti PowerMockito.when(CacheProvider.getGatewayAPIKeyJWTCache()).thenReturn(gatewayAPIKeyJWTCache); PowerMockito.when(gatewayAPIKeyJWTCache.getIfPresent(Mockito.anyString())).thenReturn(null); + ChoreoComponentInfo choreoComponentInfo = new ChoreoComponentInfo(); + choreoComponentInfo.setComponentID("component_id"); RequestContext.Builder requestContextBuilder = new RequestContext.Builder("/api-key"); requestContextBuilder.matchedAPI(new APIConfig.Builder("Petstore") .basePath("/test") + .uuid("6003a3b7-af0f-4fb3-853e-a6562b2345f2") .apiType("REST") + .choreoComponentInfo(choreoComponentInfo) .build()); Map headersMap = new HashMap<>(); headersMap.put("choreo-api-key",