From b3dcd3f069ce9cf67ae49562fd2ac6c86976eb07 Mon Sep 17 00:00:00 2001 From: AmaliMatharaarachchi Date: Thu, 19 Oct 2023 23:50:30 +0530 Subject: [PATCH] add unit tests --- .../commons/model/AuthenticationContext.java | 56 -- .../org.wso2.apk.enforcer/build.gradle | 3 + .../security/AuthenticationContext.java | 263 --------- .../security/jwt/JWTAuthenticator.java | 4 +- .../security/jwt/validator/JWTValidator.java | 4 +- .../security/mtls/MTLSAuthenticator.java | 2 - .../wso2/apk/enforcer/util/FilterUtils.java | 4 - .../apk/enforcer/jwt/JWTValidatorTest.java | 546 ++++++++++++++++++ 8 files changed, 554 insertions(+), 328 deletions(-) delete mode 100644 gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/AuthenticationContext.java create mode 100644 gateway/enforcer/org.wso2.apk.enforcer/src/test/java/org/wso2/apk/enforcer/jwt/JWTValidatorTest.java diff --git a/gateway/enforcer/org.wso2.apk.enforcer.commons/src/main/java/org/wso2/apk/enforcer/commons/model/AuthenticationContext.java b/gateway/enforcer/org.wso2.apk.enforcer.commons/src/main/java/org/wso2/apk/enforcer/commons/model/AuthenticationContext.java index 7718f3598c..067fcfeb0a 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer.commons/src/main/java/org/wso2/apk/enforcer/commons/model/AuthenticationContext.java +++ b/gateway/enforcer/org.wso2.apk.enforcer.commons/src/main/java/org/wso2/apk/enforcer/commons/model/AuthenticationContext.java @@ -40,11 +40,7 @@ public class AuthenticationContext { private String subscriberTenantDomain; private String spikeArrestUnit; private boolean stopOnQuotaReach; - private String productName; - private String productProvider; - private String apiName; private String apiPublisher; - private String apiVersion; private String apiUUID; private String rawToken; private String tokenType; @@ -267,45 +263,6 @@ public void setStopOnQuotaReach(boolean stopOnQuotaReach) { this.stopOnQuotaReach = stopOnQuotaReach; } - public void setProductName(String productName) { - this.productName = productName; - } - - /** - * Matched API Product Name (If the request is from API Product) - * - * @return API Product Name - */ - public String getProductName() { - return productName; - } - - public void setProductProvider(String productProvider) { - this.productProvider = productProvider; - } - - /** - * API Product Provider of the matched API. - * - * @return API Product provider. - */ - public String getProductProvider() { - return productProvider; - } - - /** - * API Name of the matched API. - * - * @return API Name - */ - public String getApiName() { - return apiName; - } - - public void setApiName(String apiName) { - this.apiName = apiName; - } - /** * API Publisher of the matched API. * @@ -319,19 +276,6 @@ public void setApiPublisher(String apiPublisher) { this.apiPublisher = apiPublisher; } - /** - * API Version of the matched API - * - * @return API Version - */ - public String getApiVersion() { - return apiVersion; - } - - public void setApiVersion(String apiVersion) { - this.apiVersion = apiVersion; - } - /** * API UUID of the corresponding API. * diff --git a/gateway/enforcer/org.wso2.apk.enforcer/build.gradle b/gateway/enforcer/org.wso2.apk.enforcer/build.gradle index 4a675bea90..af2a4b3e68 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/build.gradle +++ b/gateway/enforcer/org.wso2.apk.enforcer/build.gradle @@ -85,4 +85,7 @@ dependencies { implementation libs.protobuf.java // Test dependencites testImplementation libs.junit + testImplementation libs.mockito.core + testImplementation libs.powermock.api.mockito2 + testImplementation libs.powermock.module.junit4 } diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/AuthenticationContext.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/AuthenticationContext.java deleted file mode 100644 index 06b6e73a4b..0000000000 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/AuthenticationContext.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2020, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.apk.enforcer.security; - -import org.wso2.apk.enforcer.constants.Constants; - -import java.util.List; - -/** - * Contains some context information related to an authenticated request. This can be used - * to access API keys and tier information related to already authenticated requests. - */ -public class AuthenticationContext { - - private boolean authenticated; - private String username; - private String applicationTier; - private String tier; - private String apiTier; - private boolean isContentAwareTierPresent; - private String apiKey; - private String keyType; - private String callerToken; - private String applicationId; - private String applicationName; - private String consumerKey; - private String subscriber; - private List throttlingDataList; - private int spikeArrestLimit; - private String subscriberTenantDomain; - private String spikeArrestUnit; - private boolean stopOnQuotaReach; - private String productName; - private String productProvider; - private String apiName; - private String apiPublisher; - private String apiVersion; - private String apiUUID; - - public AuthenticationContext() { - this.applicationId = Constants.UNKNOWN_VALUE; - this.apiPublisher = Constants.UNKNOWN_VALUE; - this.apiTier = ""; - this.applicationId = Constants.UNKNOWN_VALUE; - this.applicationName = Constants.UNKNOWN_VALUE; - this.applicationTier = "Unlimited"; - this.consumerKey = Constants.UNKNOWN_VALUE; - this.spikeArrestUnit = ""; - this.subscriber = Constants.UNKNOWN_VALUE; - this.subscriberTenantDomain = Constants.UNKNOWN_VALUE; - } - - public List getThrottlingDataList() { - return throttlingDataList; - } - - public void setThrottlingDataList(List throttlingDataList) { - this.throttlingDataList = throttlingDataList; - } - //Following throttle data list can be use to hold throttle data and api level throttle key - //should be its first element. - - public boolean isContentAwareTierPresent() { - return isContentAwareTierPresent; - } - - public void setIsContentAware(boolean isContentAware) { - this.isContentAwareTierPresent = isContentAware; - } - - public String getApiTier() { - return apiTier; - } - - public void setApiTier(String apiTier) { - this.apiTier = apiTier; - } - - public String getSubscriber() { - return subscriber; - } - - public void setSubscriber(String subscriber) { - this.subscriber = subscriber; - } - - public boolean isAuthenticated() { - return authenticated; - } - - public String getUsername() { - return username; - } - - public String getTier() { - return tier; - } - - public String getApiKey() { - return apiKey; - } - - public void setApiKey(String apiKey) { - this.apiKey = apiKey; - } - - public void setAuthenticated(boolean authenticated) { - this.authenticated = authenticated; - } - - public void setUsername(String username) { - this.username = username; - } - - public void setTier(String tier) { - this.tier = tier; - } - - public String getKeyType() { - return keyType; - } - - public void setKeyType(String keyType) { - this.keyType = keyType; - } - - public String getCallerToken() { - return callerToken; - } - - public void setCallerToken(String callerToken) { - this.callerToken = callerToken; - } - - public String getApplicationTier() { - return applicationTier; - } - - public void setApplicationTier(String applicationTier) { - this.applicationTier = applicationTier; - } - - public String getApplicationId() { - return applicationId; - } - - public void setApplicationId(String applicationId) { - this.applicationId = applicationId; - } - - public String getApplicationName() { - return applicationName; - } - - public void setApplicationName(String applicationName) { - this.applicationName = applicationName; - } - - public String getConsumerKey() { - return consumerKey; - } - - public void setConsumerKey(String consumerKey) { - this.consumerKey = consumerKey; - } - - public int getSpikeArrestLimit() { - return spikeArrestLimit; - } - - public void setSpikeArrestLimit(int spikeArrestLimit) { - this.spikeArrestLimit = spikeArrestLimit; - } - - public String getSubscriberTenantDomain() { - return subscriberTenantDomain; - } - - public void setSubscriberTenantDomain(String subscriberTenantDomain) { - this.subscriberTenantDomain = subscriberTenantDomain; - } - - public String getSpikeArrestUnit() { - return spikeArrestUnit; - } - - public void setSpikeArrestUnit(String spikeArrestUnit) { - this.spikeArrestUnit = spikeArrestUnit; - } - - public boolean isStopOnQuotaReach() { - return stopOnQuotaReach; - } - - public void setStopOnQuotaReach(boolean stopOnQuotaReach) { - this.stopOnQuotaReach = stopOnQuotaReach; - } - - public void setProductName(String productName) { - this.productName = productName; - } - - public String getProductName() { - return productName; - } - - public void setProductProvider(String productProvider) { - this.productProvider = productProvider; - } - - public String getProductProvider() { - return productProvider; - } - - public String getApiName() { - return apiName; - } - - public void setApiName(String apiName) { - this.apiName = apiName; - } - - public String getApiPublisher() { - return apiPublisher; - } - - public void setApiPublisher(String apiPublisher) { - this.apiPublisher = apiPublisher; - } - - public String getApiVersion() { - return apiVersion; - } - - public void setApiVersion(String apiVersion) { - this.apiVersion = apiVersion; - } - - public String getApiUUID() { - return apiUUID; - } - - public void setApiUUID(String apiUUID) { - this.apiUUID = apiUUID; - } -} - diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/JWTAuthenticator.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/JWTAuthenticator.java index 114d763c4a..c3c258c7f0 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/JWTAuthenticator.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/JWTAuthenticator.java @@ -487,8 +487,8 @@ private JWTValidationInfo getJwtValidationInfo(String jwtToken, String organizat CacheProviderUtil.getOrganizationCache(organization).getGatewayKeyCache().invalidate(signature); CacheProviderUtil.getOrganizationCache(organization).getInvalidTokenCache().put(signature, true); throw new APISecurityException(APIConstants.StatusCodes.UNAUTHENTICATED.getCode(), - APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, - APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE); + APISecurityConstants.API_AUTH_ACCESS_TOKEN_EXPIRED, + APISecurityConstants.API_AUTH_ACCESS_TOKEN_EXPIRED_MESSAGE); } } else if (CacheProviderUtil.getOrganizationCache(organization).getInvalidTokenCache() .getIfPresent(signature) != null) { diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/validator/JWTValidator.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/validator/JWTValidator.java index 1813c99977..66a1f3b4a8 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/validator/JWTValidator.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/jwt/validator/JWTValidator.java @@ -36,6 +36,7 @@ import org.wso2.apk.enforcer.config.ConfigHolder; import org.wso2.apk.enforcer.config.dto.ExtendedTokenIssuerDto; import org.wso2.apk.enforcer.constants.APIConstants; +import org.wso2.apk.enforcer.constants.APISecurityConstants; import org.wso2.apk.enforcer.security.jwt.SignedJWTInfo; import org.wso2.apk.enforcer.util.JWKSClient; import org.wso2.apk.enforcer.util.JWTUtils; @@ -94,15 +95,16 @@ public JWTValidationInfo validateToken(String token, SignedJWTInfo signedJWTInfo jwtValidationInfo.setToken(token); return jwtValidationInfo; } + jwtValidationInfo.setValidationCode(APISecurityConstants.API_AUTH_ACCESS_TOKEN_EXPIRED); logger.debug("Token is expired."); } else { + jwtValidationInfo.setValidationCode(APIConstants.KeyValidationStatus.API_AUTH_INVALID_CREDENTIALS); logger.debug("Token signature is invalid."); } } catch (ParseException | JWTGeneratorException e) { throw new EnforcerException("Error while parsing JWT", e); } jwtValidationInfo.setValid(false); - jwtValidationInfo.setValidationCode(APIConstants.KeyValidationStatus.API_AUTH_INVALID_CREDENTIALS); return jwtValidationInfo; } diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/mtls/MTLSAuthenticator.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/mtls/MTLSAuthenticator.java index 17e940a621..01ab0324f1 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/mtls/MTLSAuthenticator.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/security/mtls/MTLSAuthenticator.java @@ -122,9 +122,7 @@ public AuthenticationContext authenticate(RequestContext requestContext) throws String apiUUID = requestContext.getMatchedAPI().getUuid(); authenticationContext.setAuthenticated(authenticated); - authenticationContext.setApiName(apiName); authenticationContext.setApiUUID(apiUUID); - authenticationContext.setApiVersion(apiVersion); return authenticationContext; } finally { diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/util/FilterUtils.java b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/util/FilterUtils.java index 2cd818479b..3f34219644 100644 --- a/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/util/FilterUtils.java +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/main/java/org/wso2/apk/enforcer/util/FilterUtils.java @@ -251,7 +251,6 @@ public static AuthenticationContext generateAuthenticationContextForUnsecured(Re authContext.setApplicationName(null); authContext.setApplicationTier(APIConstants.UNLIMITED_TIER); authContext.setSubscriber(APIConstants.END_USER_ANONYMOUS); - authContext.setApiName(requestContext.getMatchedAPI().getName()); authContext.setStopOnQuotaReach(true); authContext.setConsumerKey(null); authContext.setCallerToken(null); @@ -281,8 +280,6 @@ public static AuthenticationContext generateAuthenticationContext(RequestContext authContext.setSubscriber(apiKeyValidationInfoDTO.getSubscriber()); authContext.setTier(apiKeyValidationInfoDTO.getTier()); authContext.setSubscriberTenantDomain(apiKeyValidationInfoDTO.getSubscriberTenantDomain()); - authContext.setApiName(apiKeyValidationInfoDTO.getApiName()); - authContext.setApiVersion(apiKeyValidationInfoDTO.getApiVersion()); authContext.setApiPublisher(apiKeyValidationInfoDTO.getApiPublisher()); authContext.setStopOnQuotaReach(apiKeyValidationInfoDTO.isStopOnQuotaReach()); authContext.setSpikeArrestLimit(apiKeyValidationInfoDTO.getSpikeArrestLimit()); @@ -363,7 +360,6 @@ public static AuthenticationContext generateAuthenticationContext(String tokenId if (api != null) { authContext.setTier(APIConstants.UNLIMITED_TIER); - authContext.setApiName(api.getAsString(APIConstants.JwtTokenConstants.API_NAME)); authContext.setApiPublisher(api.getAsString(APIConstants.JwtTokenConstants.API_PUBLISHER)); } diff --git a/gateway/enforcer/org.wso2.apk.enforcer/src/test/java/org/wso2/apk/enforcer/jwt/JWTValidatorTest.java b/gateway/enforcer/org.wso2.apk.enforcer/src/test/java/org/wso2/apk/enforcer/jwt/JWTValidatorTest.java new file mode 100644 index 0000000000..480be50d20 --- /dev/null +++ b/gateway/enforcer/org.wso2.apk.enforcer/src/test/java/org/wso2/apk/enforcer/jwt/JWTValidatorTest.java @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wso2.apk.enforcer.jwt; + +import com.google.common.cache.LoadingCache; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.wso2.apk.enforcer.common.CacheProvider; +import org.wso2.apk.enforcer.common.CacheProviderUtil; +import org.wso2.apk.enforcer.commons.dto.JWKSConfigurationDTO; +import org.wso2.apk.enforcer.commons.dto.JWTConfigurationDto; +import org.wso2.apk.enforcer.commons.dto.JWTValidationInfo; +import org.wso2.apk.enforcer.commons.exception.APISecurityException; +import org.wso2.apk.enforcer.commons.exception.EnforcerException; +import org.wso2.apk.enforcer.commons.jwtgenerator.AbstractAPIMgtGatewayJWTGenerator; +import org.wso2.apk.enforcer.commons.jwttransformer.DefaultJWTTransformer; +import org.wso2.apk.enforcer.commons.jwttransformer.JWTTransformer; +import org.wso2.apk.enforcer.commons.model.APIConfig; +import org.wso2.apk.enforcer.commons.model.AuthenticationConfig; +import org.wso2.apk.enforcer.commons.model.AuthenticationContext; +import org.wso2.apk.enforcer.commons.model.JWTAuthenticationConfig; +import org.wso2.apk.enforcer.commons.model.RequestContext; +import org.wso2.apk.enforcer.commons.model.ResourceConfig; +import org.wso2.apk.enforcer.config.ConfigHolder; +import org.wso2.apk.enforcer.config.EnforcerConfig; +import org.wso2.apk.enforcer.config.dto.ExtendedTokenIssuerDto; +import org.wso2.apk.enforcer.constants.APISecurityConstants; +import org.wso2.apk.enforcer.security.KeyValidator; +import org.wso2.apk.enforcer.security.jwt.JWTAuthenticator; +import org.wso2.apk.enforcer.security.jwt.validator.JWTValidator; +import org.wso2.apk.enforcer.subscription.SubscriptionDataStoreImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({JWTValidator.class, LogManager.class, CacheProviderUtil.class, ConfigHolder.class, + SubscriptionDataStoreImpl.class, KeyValidator.class, Logger.class, JWTAuthenticator.class, + AbstractAPIMgtGatewayJWTGenerator.class, Log.class, LogFactory.class}) +public class JWTValidatorTest { + + @Before + public void setup() { + PowerMockito.mockStatic(CacheProviderUtil.class); + PowerMockito.mockStatic(ConfigHolder.class); + PowerMockito.mockStatic(SubscriptionDataStoreImpl.class); + PowerMockito.mockStatic(KeyValidator.class); + Logger logger = Mockito.mock(Logger.class); + Log logger2 = Mockito.mock(Log.class); + PowerMockito.mockStatic(LogManager.class); + PowerMockito.mockStatic(LogFactory.class); + Mockito.when(LogManager.getLogger(JWTAuthenticator.class)).thenReturn(logger); + Mockito.when(LogFactory.getLog(AbstractAPIMgtGatewayJWTGenerator.class)).thenReturn(logger2); + } + + @Test + public void testJWTValidator() throws APISecurityException, EnforcerException { + String organization = "org1"; + String issuer = "https://localhost:9443/oauth2/token"; + String signature = "sBgeoqJn0log5EZflj_G7ADvm6B3KQ9bdfFCEFVQS1U3oY9" + + "-cqPwAPyOLLh95pdfjYjakkf1UtjPZjeIupwXnzg0SffIc704RoVlZocAx9Ns2XihjU6Imx2MbXq9ARmQxQkyGVkJUMTwZ8" + + "-SfOnprfrhX2cMQQS8m2Lp7hcsvWFRGKxAKIeyUrbY4ihRIA5vOUrMBWYUx9Di1N7qdKA4S3e8O4KQX2VaZPBzN594c9TG" + + "riiH8AuuqnrftfvidSnlRLaFJmko8-QZo8jDepwacaFhtcaPVVJFG4uYP-_-N6sqfxLw3haazPN0_xU0T1zJLPRLC5HPfZMJDMGp" + + "EuSe9w"; + String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5UZG1aak00WkRrM05qWTBZemM1T" + + "W1abU9EZ3dNVEUzTVdZd05ERTVNV1JsWkRnNE56YzRaQT09In0" + + ".eyJhdWQiOiJodHRwOlwvXC9vcmcud3NvMi5hcGltZ3RcL2dhdGV" + + "3YXkiLCJzdWIiOiJhZG1pbkBjYXJib24uc3VwZXIiLCJhcHBsaWNhdGlvbiI6eyJvd25lciI6ImFkbWluIiwidGllclF1b3RhVHlwZ" + + "SI6InJlcXVlc3RDb3VudCIsInRpZXIiOiJVbmxpbWl0ZWQiLCJuYW1lIjoiRGVmYXVsdEFwcGxpY2F0aW9uIiwiaWQiOjEsInV1aWQ" + + "iOm51bGx9LCJzY29wZSI6ImFtX2FwcGxpY2F0aW9uX3Njb3BlIGRlZmF1bHQiLCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0" + + "NDNcL29hdXRoMlwvdG9rZW4iLCJ0aWVySW5mbyI6e30sImtleXR5cGUiOiJQUk9EVUNUSU9OIiwic3Vic2NyaWJlZEFQSXMiOltdL" + + "CJjb25zdW1lcktleSI6IlhnTzM5NklIRks3ZUZZeWRycVFlNEhLR3oxa2EiLCJleHAiOjE1OTAzNDIzMTMsImlhdCI6MTU5MDMzO" + + "DcxMywianRpIjoiYjg5Mzg3NjgtMjNmZC00ZGVjLThiNzAtYmVkNDVlYjdjMzNkIn0." + signature; + JWTValidationInfo jwtValidationInfo = new JWTValidationInfo(); + jwtValidationInfo.setValid(true); + jwtValidationInfo.setExpiryTime(System.currentTimeMillis() + 5000L); + jwtValidationInfo.setConsumerKey(UUID.randomUUID().toString()); + jwtValidationInfo.setUser("user1"); + jwtValidationInfo.setKeyManager("Default"); + + JWTConfigurationDto jwtConfigurationDto = new JWTConfigurationDto(); + JWTAuthenticator jwtAuthenticator = new JWTAuthenticator(jwtConfigurationDto, true); + RequestContext requestContext = Mockito.mock(RequestContext.class); + + ArrayList resourceConfigs = new ArrayList<>(); + ResourceConfig resourceConfig = Mockito.mock(ResourceConfig.class); + AuthenticationConfig authenticationConfig = new AuthenticationConfig(); + JWTAuthenticationConfig jwtAuthenticationConfig = new JWTAuthenticationConfig(); + jwtAuthenticationConfig.setHeader("Authorization"); + authenticationConfig.setJwtAuthenticationConfig(jwtAuthenticationConfig); + Mockito.when(resourceConfig.getAuthenticationConfig()).thenReturn(authenticationConfig); + Mockito.when(resourceConfig.getMethod()).thenReturn(ResourceConfig.HttpMethods.GET); + resourceConfigs.add(resourceConfig); + Mockito.when(requestContext.getMatchedResourcePaths()).thenReturn(resourceConfigs); + Map headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + jwt); + Mockito.when(requestContext.getHeaders()).thenReturn(headers); + Mockito.when(requestContext.getAuthenticationContext()).thenReturn(new AuthenticationContext()); + APIConfig apiConfig = Mockito.mock(APIConfig.class); + Mockito.when(apiConfig.getName()).thenReturn("api1"); + Mockito.when(apiConfig.getOrganizationId()).thenReturn(organization); + Mockito.when(requestContext.getMatchedAPI()).thenReturn(apiConfig); + CacheProvider cacheProvider = Mockito.mock(CacheProvider.class); + LoadingCache gatewayKeyCache = Mockito.mock(LoadingCache.class); + LoadingCache invalidTokenCache = Mockito.mock(LoadingCache.class); + Mockito.when(cacheProvider.getGatewayKeyCache()).thenReturn(gatewayKeyCache); + Mockito.when(cacheProvider.getInvalidTokenCache()).thenReturn(invalidTokenCache); + Mockito.when(CacheProviderUtil.getOrganizationCache(organization)).thenReturn(cacheProvider); + + ExtendedTokenIssuerDto tokenIssuerDto = Mockito.mock(ExtendedTokenIssuerDto.class); + Mockito.when(tokenIssuerDto.getIssuer()).thenReturn(issuer); + JWKSConfigurationDTO jwksConfigurationDTO = new JWKSConfigurationDTO(); + jwksConfigurationDTO.setEnabled(true); + + Mockito.when(tokenIssuerDto.getJwksConfigurationDTO()).thenReturn(jwksConfigurationDTO); + + EnforcerConfig enforcerConfig = Mockito.mock(EnforcerConfig.class); + ConfigHolder configHolder = Mockito.mock(ConfigHolder.class); + Mockito.when(ConfigHolder.getInstance()).thenReturn(configHolder); + Mockito.when(configHolder.getConfig()).thenReturn(enforcerConfig); + JWTTransformer jwtTransformer = new DefaultJWTTransformer(); + Mockito.when(enforcerConfig.getJwtTransformer(issuer)).thenReturn(jwtTransformer); + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + + SubscriptionDataStoreImpl subscriptionDataStore = Mockito.mock(SubscriptionDataStoreImpl.class); + Mockito.when(SubscriptionDataStoreImpl.getInstance()).thenReturn(subscriptionDataStore); + Mockito.when(subscriptionDataStore.getJWTValidatorByIssuer(issuer, + organization)).thenReturn(jwtValidator); + Mockito.when(jwtValidator.validateToken(Mockito.eq(jwt), Mockito.any())).thenReturn(jwtValidationInfo); + + Mockito.when(KeyValidator.validateScopes(Mockito.any())).thenReturn(true); + AuthenticationContext authenticate = jwtAuthenticator.authenticate(requestContext); + + Assert.assertNotNull(authenticate); + // TODO(amali) enable after subscription validation is enabled +// Assert.assertEquals(authenticate.getApiPublisher(), "admin"); +// Assert.assertEquals(authenticate.getConsumerKey(), jwtValidationInfo.getConsumerKey()); + Mockito.verify(gatewayKeyCache, Mockito.atLeast(1)).put(signature, jwtValidationInfo); + } + + @Test + public void testCachedJWTValidator() throws APISecurityException, EnforcerException { + String organization = "org1"; + String issuer = "https://localhost:9443/oauth2/token"; + String signature = "sBgeoqJn0log5EZflj_G7ADvm6B3KQ9bdfF" + + "CEFVQS1U3oY9" + + "-cqPwAPyOLLh95pdfjYjakkf1UtjPZjeIupwXnzg0SffIc704RoVlZocAx9Ns2XihjU6Imx2MbXq9ARmQxQkyGVkJ" + + "UMTwZ8" + + "-SfOnprfrhX2cMQQS8m2Lp7hcsvWFRGKxAKIeyUrbY4ihRIA5vOUrMBWYUx9Di1N7qdKA4S3e8O4KQX2VaZPBzN594c9TG" + + "riiH8AuuqnrftfvidSnlRLaFJmko8-QZo8jDepwacaFhtcaPVVJFG4uYP-_" + + "-N6sqfxLw3haazPN0_xU0T1zJLPRLC5HPfZMJDMGp" + + "EuSe9w"; + String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5UZG1aak00WkRrM05qWTBZemM1T" + + "W1abU9EZ3dNVEUzTVdZd05ERTVNV1JsWkRnNE56YzRaQT09In0" + + ".eyJhdWQiOiJodHRwOlwvXC9vcmcud3NvMi5hcGltZ3RcL2dhdGV" + + "3YXkiLCJzdWIiOiJhZG1pbkBjYXJib24uc3VwZXIiLCJhcHBsaWNhdGlvbiI6eyJvd25lciI6ImFkbWluIiwidGllclF1b3RhVHlwZ" + + "SI6InJlcXVlc3RDb3VudCIsInRpZXIiOiJVbmxpbWl0ZWQiLCJuYW1lIjoiRGVmYXVsdEFwcGxpY2F0aW9uIiwiaWQiOjEsInV1aWQ" + + "iOm51bGx9LCJzY29wZSI6ImFtX2FwcGxpY2F0aW9uX3Njb3BlIGRlZmF1bHQiLCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0" + + "NDNcL29hdXRoMlwvdG9rZW4iLCJ0aWVySW5mbyI6e30sImtleXR5cGUiOiJQUk9EVUNUSU9OIiwic3Vic2NyaWJlZEFQSXMiOltdL" + + "CJjb25zdW1lcktleSI6IlhnTzM5NklIRks3ZUZZeWRycVFlNEhLR3oxa2EiLCJleHAiOjE1OTAzNDIzMTMsImlhdCI6MTU5MDMzO" + + "DcxMywianRpIjoiYjg5Mzg3NjgtMjNmZC00ZGVjLThiNzAtYmVkNDVlYjdjMzNkIn0." + signature; + JWTValidationInfo jwtValidationInfo = new JWTValidationInfo(); + jwtValidationInfo.setValid(true); + jwtValidationInfo.setExpiryTime(System.currentTimeMillis() + 5000L); + jwtValidationInfo.setConsumerKey(UUID.randomUUID().toString()); + jwtValidationInfo.setUser("user1"); + jwtValidationInfo.setKeyManager("Default"); + jwtValidationInfo.setToken(jwt); + jwtValidationInfo.setIdentifier(signature); + + JWTConfigurationDto jwtConfigurationDto = new JWTConfigurationDto(); + JWTAuthenticator jwtAuthenticator = new JWTAuthenticator(jwtConfigurationDto, true); + RequestContext requestContext = Mockito.mock(RequestContext.class); + + ArrayList resourceConfigs = new ArrayList<>(); + ResourceConfig resourceConfig = Mockito.mock(ResourceConfig.class); + AuthenticationConfig authenticationConfig = new AuthenticationConfig(); + JWTAuthenticationConfig jwtAuthenticationConfig = new JWTAuthenticationConfig(); + jwtAuthenticationConfig.setHeader("Authorization"); + authenticationConfig.setJwtAuthenticationConfig(jwtAuthenticationConfig); + Mockito.when(resourceConfig.getAuthenticationConfig()).thenReturn(authenticationConfig); + Mockito.when(resourceConfig.getMethod()).thenReturn(ResourceConfig.HttpMethods.GET); + resourceConfigs.add(resourceConfig); + Mockito.when(requestContext.getMatchedResourcePaths()).thenReturn(resourceConfigs); + Map headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + jwt); + Mockito.when(requestContext.getHeaders()).thenReturn(headers); + Mockito.when(requestContext.getAuthenticationContext()).thenReturn(new AuthenticationContext()); + APIConfig apiConfig = Mockito.mock(APIConfig.class); + Mockito.when(apiConfig.getName()).thenReturn("api1"); + Mockito.when(apiConfig.getOrganizationId()).thenReturn(organization); + Mockito.when(requestContext.getMatchedAPI()).thenReturn(apiConfig); + CacheProvider cacheProvider = Mockito.mock(CacheProvider.class); + LoadingCache gatewayKeyCache = Mockito.mock(LoadingCache.class); + Mockito.when(cacheProvider.getGatewayKeyCache()).thenReturn(gatewayKeyCache); + Mockito.when(gatewayKeyCache.getIfPresent(signature)).thenReturn(jwtValidationInfo); + Mockito.when(CacheProviderUtil.getOrganizationCache(organization)).thenReturn(cacheProvider); + + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + SubscriptionDataStoreImpl subscriptionDataStore = Mockito.mock(SubscriptionDataStoreImpl.class); + Mockito.when(SubscriptionDataStoreImpl.getInstance()).thenReturn(subscriptionDataStore); + Mockito.when(subscriptionDataStore.getJWTValidatorByIssuer(issuer, + organization)).thenReturn(jwtValidator); + Mockito.when(jwtValidator.validateToken(Mockito.eq(jwt), Mockito.any())).thenReturn(jwtValidationInfo); + + Mockito.when(KeyValidator.validateScopes(Mockito.any())).thenReturn(true); + AuthenticationContext authenticate = jwtAuthenticator.authenticate(requestContext); + + Assert.assertNotNull(authenticate); + Assert.assertEquals(authenticate.getConsumerKey(), jwtValidationInfo.getConsumerKey()); + Mockito.verify(gatewayKeyCache, Mockito.atLeast(1)).getIfPresent(signature); + } + + @Test + public void testNonJTIJWTValidator() throws APISecurityException, EnforcerException { + String organization = "org1"; + String issuer = "https://localhost:9443/oauth2/token"; + String signature = "SSQyg_VTxF5drIogztn2SyEK2wRE07wG6OW3tufD3vo"; + String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" + + ".eyJpc3MiOiJodHRwczovL2xvY2FsaG9zdCIsImlhdCI6MTU5OTU0ODE3NCwiZXhwIjoxNjMxMDg0MTc0LC" + + "JhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiR2l2ZW5OYW1l" + + "IjoiSm9obm55IiwiU3VybmFtZSI6IlJvY2tldCIsIkVtYWlsIjoianJvY2tldEBleGFtcGxlLmNvbSIsIl" + + "JvbGUiOlsiTWFuYWdlciIsIlByb2plY3QgQWRtaW5pc3RyYXRvciJdfQ." + signature; + JWTValidationInfo jwtValidationInfo = new JWTValidationInfo(); + jwtValidationInfo.setValid(true); + jwtValidationInfo.setExpiryTime(System.currentTimeMillis() + 5000L); + jwtValidationInfo.setConsumerKey(UUID.randomUUID().toString()); + jwtValidationInfo.setUser("user1"); + jwtValidationInfo.setKeyManager("Default"); + jwtValidationInfo.setToken(jwt); + jwtValidationInfo.setIdentifier(signature); + + JWTConfigurationDto jwtConfigurationDto = new JWTConfigurationDto(); + JWTAuthenticator jwtAuthenticator = new JWTAuthenticator(jwtConfigurationDto, true); + RequestContext requestContext = Mockito.mock(RequestContext.class); + + ArrayList resourceConfigs = new ArrayList<>(); + ResourceConfig resourceConfig = Mockito.mock(ResourceConfig.class); + AuthenticationConfig authenticationConfig = new AuthenticationConfig(); + JWTAuthenticationConfig jwtAuthenticationConfig = new JWTAuthenticationConfig(); + jwtAuthenticationConfig.setHeader("Authorization"); + authenticationConfig.setJwtAuthenticationConfig(jwtAuthenticationConfig); + Mockito.when(resourceConfig.getAuthenticationConfig()).thenReturn(authenticationConfig); + Mockito.when(resourceConfig.getMethod()).thenReturn(ResourceConfig.HttpMethods.GET); + resourceConfigs.add(resourceConfig); + Mockito.when(requestContext.getMatchedResourcePaths()).thenReturn(resourceConfigs); + Map headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + jwt); + Mockito.when(requestContext.getHeaders()).thenReturn(headers); + Mockito.when(requestContext.getAuthenticationContext()).thenReturn(new AuthenticationContext()); + APIConfig apiConfig = Mockito.mock(APIConfig.class); + Mockito.when(apiConfig.getName()).thenReturn("api1"); + Mockito.when(apiConfig.getOrganizationId()).thenReturn(organization); + Mockito.when(requestContext.getMatchedAPI()).thenReturn(apiConfig); + CacheProvider cacheProvider = Mockito.mock(CacheProvider.class); + LoadingCache gatewayKeyCache = Mockito.mock(LoadingCache.class); + Mockito.when(cacheProvider.getGatewayKeyCache()).thenReturn(gatewayKeyCache); + Mockito.when(gatewayKeyCache.getIfPresent(signature)).thenReturn(jwtValidationInfo); + Mockito.when(CacheProviderUtil.getOrganizationCache(organization)).thenReturn(cacheProvider); + + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + SubscriptionDataStoreImpl subscriptionDataStore = Mockito.mock(SubscriptionDataStoreImpl.class); + Mockito.when(SubscriptionDataStoreImpl.getInstance()).thenReturn(subscriptionDataStore); + Mockito.when(subscriptionDataStore.getJWTValidatorByIssuer(issuer, + organization)).thenReturn(jwtValidator); + Mockito.when(jwtValidator.validateToken(Mockito.eq(jwt), Mockito.any())).thenReturn(jwtValidationInfo); + + Mockito.when(KeyValidator.validateScopes(Mockito.any())).thenReturn(true); + AuthenticationContext authenticate = jwtAuthenticator.authenticate(requestContext); + + Assert.assertNotNull(authenticate); + Assert.assertEquals(authenticate.getConsumerKey(), jwtValidationInfo.getConsumerKey()); + Mockito.verify(gatewayKeyCache, Mockito.atLeast(1)).getIfPresent(signature); + } + + @Test + public void testExpiredJWTValidator() { + String organization = "org1"; + String issuer = "https://localhost:9443/oauth2/token"; + String signature = "sBgeoqJn0log5EZflj_G7ADvm6B3KQ9bdfFCEFVQS1U3oY9" + + "-cqPwAPyOLLh95pdfjYjakkf1UtjPZjeIupwXnzg0SffIc704RoVlZocAx9Ns2XihjU6Imx2MbXq9ARmQxQkyGVkJUMTwZ8" + + "-SfOnprfrhX2cMQQS8m2Lp7hcsvWFRGKxAKIeyUrbY4ihRIA5vOUrMBWYUx9Di1N7qdKA4S3e8O4KQX2VaZPBzN594c9TG" + + "riiH8AuuqnrftfvidSnlRLaFJmko8-QZo8jDepwacaFhtcaPVVJFG4uYP-_-N6sqfxLw3haazPN0_xU0T1zJLPRLC5HPfZMJDMGp" + + "EuSe9w"; + String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5UZG1aak00WkRrM05qWTBZemM1T" + + "W1abU9EZ3dNVEUzTVdZd05ERTVNV1JsWkRnNE56YzRaQT09In0" + + ".eyJhdWQiOiJodHRwOlwvXC9vcmcud3NvMi5hcGltZ3RcL2dhdGV" + + "3YXkiLCJzdWIiOiJhZG1pbkBjYXJib24uc3VwZXIiLCJhcHBsaWNhdGlvbiI6eyJvd25lciI6ImFkbWluIiwidGllclF1b3RhVHlwZ" + + "SI6InJlcXVlc3RDb3VudCIsInRpZXIiOiJVbmxpbWl0ZWQiLCJuYW1lIjoiRGVmYXVsdEFwcGxpY2F0aW9uIiwiaWQiOjEsInV1aWQ" + + "iOm51bGx9LCJzY29wZSI6ImFtX2FwcGxpY2F0aW9uX3Njb3BlIGRlZmF1bHQiLCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0" + + "NDNcL29hdXRoMlwvdG9rZW4iLCJ0aWVySW5mbyI6e30sImtleXR5cGUiOiJQUk9EVUNUSU9OIiwic3Vic2NyaWJlZEFQSXMiOltdL" + + "CJjb25zdW1lcktleSI6IlhnTzM5NklIRks3ZUZZeWRycVFlNEhLR3oxa2EiLCJleHAiOjE1OTAzNDIzMTMsImlhdCI6MTU5MDMzO" + + "DcxMywianRpIjoiYjg5Mzg3NjgtMjNmZC00ZGVjLThiNzAtYmVkNDVlYjdjMzNkIn0." + signature; + JWTValidationInfo jwtValidationInfo = new JWTValidationInfo(); + jwtValidationInfo.setValid(true); + jwtValidationInfo.setExpiryTime(System.currentTimeMillis() - 5000L); + jwtValidationInfo.setConsumerKey(UUID.randomUUID().toString()); + jwtValidationInfo.setUser("user1"); + jwtValidationInfo.setKeyManager("Default"); + jwtValidationInfo.setToken(jwt); + jwtValidationInfo.setIdentifier(signature); + + JWTConfigurationDto jwtConfigurationDto = new JWTConfigurationDto(); + JWTAuthenticator jwtAuthenticator = new JWTAuthenticator(jwtConfigurationDto, true); + RequestContext requestContext = Mockito.mock(RequestContext.class); + + ArrayList resourceConfigs = new ArrayList<>(); + ResourceConfig resourceConfig = Mockito.mock(ResourceConfig.class); + AuthenticationConfig authenticationConfig = new AuthenticationConfig(); + JWTAuthenticationConfig jwtAuthenticationConfig = new JWTAuthenticationConfig(); + jwtAuthenticationConfig.setHeader("Authorization"); + authenticationConfig.setJwtAuthenticationConfig(jwtAuthenticationConfig); + Mockito.when(resourceConfig.getAuthenticationConfig()).thenReturn(authenticationConfig); + Mockito.when(resourceConfig.getMethod()).thenReturn(ResourceConfig.HttpMethods.GET); + resourceConfigs.add(resourceConfig); + Mockito.when(requestContext.getMatchedResourcePaths()).thenReturn(resourceConfigs); + Map headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + jwt); + Mockito.when(requestContext.getHeaders()).thenReturn(headers); + Mockito.when(requestContext.getAuthenticationContext()).thenReturn(new AuthenticationContext()); + APIConfig apiConfig = Mockito.mock(APIConfig.class); + Mockito.when(apiConfig.getName()).thenReturn("api1"); + Mockito.when(apiConfig.getOrganizationId()).thenReturn(organization); + Mockito.when(requestContext.getMatchedAPI()).thenReturn(apiConfig); + CacheProvider cacheProvider = Mockito.mock(CacheProvider.class); + LoadingCache gatewayKeyCache = Mockito.mock(LoadingCache.class); + LoadingCache invalidTokenCache = Mockito.mock(LoadingCache.class); + Mockito.when(cacheProvider.getGatewayKeyCache()).thenReturn(gatewayKeyCache); + Mockito.when(cacheProvider.getInvalidTokenCache()).thenReturn(invalidTokenCache); + Mockito.when(gatewayKeyCache.getIfPresent(signature)).thenReturn(jwtValidationInfo); + Mockito.when(invalidTokenCache.getIfPresent(signature)).thenReturn(null); + Mockito.when(CacheProviderUtil.getOrganizationCache(organization)).thenReturn(cacheProvider); + + try { + Mockito.when(KeyValidator.validateScopes(Mockito.any())).thenReturn(true); + } catch (APISecurityException e) { + Assert.fail("Unexpected exception occurred while validating scopes"); + } + try { + jwtAuthenticator.authenticate(requestContext); + Assert.fail("Authentication should fail for expired tokens"); + } catch (APISecurityException e) { + Assert.assertEquals(e.getMessage(), e.getMessage(), APISecurityConstants.API_AUTH_ACCESS_TOKEN_EXPIRED_MESSAGE); + Mockito.verify(gatewayKeyCache, Mockito.atLeast(1)).getIfPresent(signature); + Mockito.verify(invalidTokenCache, Mockito.atLeast(1)).put(signature, true); + } + } + + @Test + public void testNoCacheExpiredJWTValidator() throws EnforcerException { + String organization = "org1"; + String issuer = "https://localhost:9443/oauth2/token"; + String signature = "sBgeoqJn0log5EZflj_G7ADvm6B3KQ9bdfFCEFVQS1U3oY9" + + "-cqPwAPyOLLh95pdfjYjakkf1UtjPZjeIupwXnzg0SffIc704RoVlZocAx9Ns2XihjU6Imx2MbXq9ARmQxQkyGVkJUMTwZ8" + + "-SfOnprfrhX2cMQQS8m2Lp7hcsvWFRGKxAKIeyUrbY4ihRIA5vOUrMBWYUx9Di1N7qdKA4S3e8O4KQX2VaZPBzN594c9TG" + + "riiH8AuuqnrftfvidSnlRLaFJmko8-QZo8jDepwacaFhtcaPVVJFG4uYP-_-N6sqfxLw3haazPN0_xU0T1zJLPRLC5HPfZMJDMGp" + + "EuSe9w"; + String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5UZG1aak00WkRrM05qWTBZemM1T" + + "W1abU9EZ3dNVEUzTVdZd05ERTVNV1JsWkRnNE56YzRaQT09In0" + + ".eyJhdWQiOiJodHRwOlwvXC9vcmcud3NvMi5hcGltZ3RcL2dhdGV" + + "3YXkiLCJzdWIiOiJhZG1pbkBjYXJib24uc3VwZXIiLCJhcHBsaWNhdGlvbiI6eyJvd25lciI6ImFkbWluIiwidGllclF1b3RhVHlwZ" + + "SI6InJlcXVlc3RDb3VudCIsInRpZXIiOiJVbmxpbWl0ZWQiLCJuYW1lIjoiRGVmYXVsdEFwcGxpY2F0aW9uIiwiaWQiOjEsInV1aWQ" + + "iOm51bGx9LCJzY29wZSI6ImFtX2FwcGxpY2F0aW9uX3Njb3BlIGRlZmF1bHQiLCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0" + + "NDNcL29hdXRoMlwvdG9rZW4iLCJ0aWVySW5mbyI6e30sImtleXR5cGUiOiJQUk9EVUNUSU9OIiwic3Vic2NyaWJlZEFQSXMiOltdL" + + "CJjb25zdW1lcktleSI6IlhnTzM5NklIRks3ZUZZeWRycVFlNEhLR3oxa2EiLCJleHAiOjE1OTAzNDIzMTMsImlhdCI6MTU5MDMzO" + + "DcxMywianRpIjoiYjg5Mzg3NjgtMjNmZC00ZGVjLThiNzAtYmVkNDVlYjdjMzNkIn0." + signature; + JWTValidationInfo jwtValidationInfo = new JWTValidationInfo(); + jwtValidationInfo.setValid(false); + jwtValidationInfo.setExpiryTime(System.currentTimeMillis() - 100); + jwtValidationInfo.setConsumerKey(UUID.randomUUID().toString()); + jwtValidationInfo.setValidationCode(APISecurityConstants.API_AUTH_ACCESS_TOKEN_EXPIRED); + jwtValidationInfo.setUser("user1"); + jwtValidationInfo.setKeyManager("Default"); + jwtValidationInfo.setToken(jwt); + jwtValidationInfo.setIdentifier(signature); + + JWTConfigurationDto jwtConfigurationDto = new JWTConfigurationDto(); + JWTAuthenticator jwtAuthenticator = new JWTAuthenticator(jwtConfigurationDto, true); + RequestContext requestContext = Mockito.mock(RequestContext.class); + + ArrayList resourceConfigs = new ArrayList<>(); + ResourceConfig resourceConfig = Mockito.mock(ResourceConfig.class); + AuthenticationConfig authenticationConfig = new AuthenticationConfig(); + JWTAuthenticationConfig jwtAuthenticationConfig = new JWTAuthenticationConfig(); + jwtAuthenticationConfig.setHeader("Authorization"); + authenticationConfig.setJwtAuthenticationConfig(jwtAuthenticationConfig); + Mockito.when(resourceConfig.getAuthenticationConfig()).thenReturn(authenticationConfig); + Mockito.when(resourceConfig.getMethod()).thenReturn(ResourceConfig.HttpMethods.GET); + resourceConfigs.add(resourceConfig); + Mockito.when(requestContext.getMatchedResourcePaths()).thenReturn(resourceConfigs); + Map headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + jwt); + Mockito.when(requestContext.getHeaders()).thenReturn(headers); + Mockito.when(requestContext.getAuthenticationContext()).thenReturn(new AuthenticationContext()); + APIConfig apiConfig = Mockito.mock(APIConfig.class); + Mockito.when(apiConfig.getName()).thenReturn("api1"); + Mockito.when(apiConfig.getOrganizationId()).thenReturn(organization); + Mockito.when(requestContext.getMatchedAPI()).thenReturn(apiConfig); + CacheProvider cacheProvider = Mockito.mock(CacheProvider.class); + LoadingCache gatewayKeyCache = Mockito.mock(LoadingCache.class); + LoadingCache invalidTokenCache = Mockito.mock(LoadingCache.class); + Mockito.when(cacheProvider.getGatewayKeyCache()).thenReturn(gatewayKeyCache); + Mockito.when(cacheProvider.getInvalidTokenCache()).thenReturn(invalidTokenCache); + Mockito.when(gatewayKeyCache.getIfPresent(signature)).thenReturn(null); + Mockito.when(invalidTokenCache.getIfPresent(signature)).thenReturn(null); + Mockito.when(CacheProviderUtil.getOrganizationCache(organization)).thenReturn(cacheProvider); + + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + SubscriptionDataStoreImpl subscriptionDataStore = Mockito.mock(SubscriptionDataStoreImpl.class); + Mockito.when(SubscriptionDataStoreImpl.getInstance()).thenReturn(subscriptionDataStore); + Mockito.when(subscriptionDataStore.getJWTValidatorByIssuer(issuer, + organization)).thenReturn(jwtValidator); + Mockito.when(jwtValidator.validateToken(Mockito.eq(jwt), Mockito.any())).thenReturn(jwtValidationInfo); + + try { + Mockito.when(KeyValidator.validateScopes(Mockito.any())).thenReturn(true); + } catch (APISecurityException e) { + Assert.fail("Unexpected exception occurred while validating scopes"); + } + try { + jwtAuthenticator.authenticate(requestContext); + Assert.fail("Authentication should fail for expired tokens"); + } catch (APISecurityException e) { + Assert.assertEquals(e.getMessage(), APISecurityConstants.API_AUTH_ACCESS_TOKEN_EXPIRED_MESSAGE); + Mockito.verify(invalidTokenCache, Mockito.atLeast(1)).put(signature, true); + } + } + + @Test + public void testTamperedPayloadJWTValidator() throws EnforcerException { + String organization = "org1"; + String issuer = "https://localhost:9443/oauth2/token"; + String signature = "sBgeoqJn0log5EZflj_G7ADvm6B3KQ9bdfFCEFVQS1U3oY9" + + "-cqPwAPyOLLh95pdfjYjakkf1UtjPZjeIupwXnzg0SffIc704RoVlZocAx9Ns2XihjU6Imx2MbXq9ARmQxQkyGVkJUMTwZ8" + + "-SfOnprfrhX2cMQQS8m2Lp7hcsvWFRGKxAKIeyUrbY4ihRIA5vOUrMBWYUx9Di1N7qdKA4S3e8O4KQX2VaZPBzN594c9TG" + + "riiH8AuuqnrftfvidSnlRLaFJmko8-QZo8jDepwacaFhtcaPVVJFG4uYP-_-N6sqfxLw3haazPN0_xU0T1zJLPRLC5HPfZMJDMGp" + + "EuSe9w"; + String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5UZG1aak00WkRrM05qWTBZemM1T" + + "W1abU9EZ3dNVEUzTVdZd05ERTVNV1JsWkRnNE56YzRaQT09In0" + + ".eyJhdWQiOiJodHRwOlwvXC9vcmcud3NvMi5hcGltZ3RcL2dhdGV" + + "3YXkiLCJzdWIiOiJhZG1pbkBjYXJib24uc3VwZXIiLCJhcHBsaWNhdGlvbiI6eyJvd25lciI6ImFkbWluIiwidGllclF1b3RhVHlwZ" + + "SI6InJlcXVlc3RDb3VudCIsInRpZXIiOiJVbmxpbWl0ZWQiLCJuYW1lIjoiRGVmYXVsdEFwcGxpY2F0aW9uIiwiaWQiOjEsInV1aWQ" + + "iOm51bGx9LCJzY29wZSI6ImFtX2FwcGxpY2F0aW9uX3Njb3BlIGRlZmF1bHQiLCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0" + + "NDNcL29hdXRoMlwvdG9rZW4iLCJ0aWVySW5mbyI6e30sImtleXR5cGUiOiJQUk9EVUNUSU9OIiwic3Vic2NyaWJlZEFQSXMiOltdL" + + "CJjb25zdW1lcktleSI6IlhnTzM5NklIRks3ZUZZeWRycVFlNEhLR3oxa2EiLCJleHAiOjE1OTAzNDIzMTMsImlhdCI6MTU5MDMzO" + + "DcxMywianRpIjoiYjg5Mzg3NjgtMjNmZC00ZGVjLThiNzAtYmVkNDVlYjdjMzNkIn0." + signature; + String tamperedJWT = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5UZG1aak00WkRrM05qWTBZemM1T" + + "W1abU9EZ3dNVEUzTVdZd05ERTVNV1JsWkRnNE56YzRaQT09In0" + + ".ewogICJhdWQiOiAiaHR0cDovL29yZy53c28yLmFwaW1ndC9nYXRld2F5IiwKICAic3ViIjogImFkbWluQGNhcm" + + "Jvbi5zdXBlciIsCiAgImFwcGxpY2F0aW9uIjogewogICAgIm93bmVyIjogImFkbWluIiwKICAgICJ0aWVyUXVvd" + + "GFUeXBlIjogInJlcXVlc3RDb3VudCIsCiAgICAidGllciI6ICJVbmxpbWl0ZWQiLAogICAgIm5hbWUiOiAiRGVm" + + "YXVsdEFwcGxpY2F0aW9uMiIsCiAgICAiaWQiOiAyLAogICAgInV1aWQiOiBudWxsCiAgfSwKICAic2NvcGUiOiA" + + "iYW1fYXBwbGljYXRpb25fc2NvcGUgZGVmYXVsdCIsCiAgImlzcyI6ICJodHRwczovL2xvY2FsaG9zdDo5NDQzL2" + + "9hdXRoMi90b2tlbiIsCiAgInRpZXJJbmZvIjoge30sCiAgImtleXR5cGUiOiAiUFJPRFVDVElPTiIsCiAgInN1Y" + + "nNjcmliZWRBUElzIjogW10sCiAgImNvbnN1bWVyS2V5IjogIlhnTzM5NklIRks3ZUZZeWRycVFlNEhLR3oxa2Ei" + + "LAogICJleHAiOiAxNTkwMzQyMzEzLAogICJpYXQiOiAxNTkwMzM4NzEzLAogICJqdGkiOiAiYjg5Mzg3NjgtMjN" + + "mZC00ZGVjLThiNzAtYmVkNDVlYjdjMzNkIgp9." + signature; + + JWTValidationInfo jwtValidationInfo = new JWTValidationInfo(); + jwtValidationInfo.setValid(false); + jwtValidationInfo.setExpiryTime(System.currentTimeMillis() - 100); + jwtValidationInfo.setConsumerKey(UUID.randomUUID().toString()); + jwtValidationInfo.setUser("user1"); + jwtValidationInfo.setKeyManager("Default"); + jwtValidationInfo.setToken(jwt); + jwtValidationInfo.setIdentifier(signature); + + JWTConfigurationDto jwtConfigurationDto = new JWTConfigurationDto(); + JWTAuthenticator jwtAuthenticator = new JWTAuthenticator(jwtConfigurationDto, true); + RequestContext requestContext = Mockito.mock(RequestContext.class); + + ArrayList resourceConfigs = new ArrayList<>(); + ResourceConfig resourceConfig = Mockito.mock(ResourceConfig.class); + AuthenticationConfig authenticationConfig = new AuthenticationConfig(); + JWTAuthenticationConfig jwtAuthenticationConfig = new JWTAuthenticationConfig(); + jwtAuthenticationConfig.setHeader("Authorization"); + authenticationConfig.setJwtAuthenticationConfig(jwtAuthenticationConfig); + Mockito.when(resourceConfig.getAuthenticationConfig()).thenReturn(authenticationConfig); + Mockito.when(resourceConfig.getMethod()).thenReturn(ResourceConfig.HttpMethods.GET); + resourceConfigs.add(resourceConfig); + Mockito.when(requestContext.getMatchedResourcePaths()).thenReturn(resourceConfigs); + Map headers = new HashMap<>(); + headers.put("Authorization", "Bearer " + tamperedJWT); + Mockito.when(requestContext.getHeaders()).thenReturn(headers); + Mockito.when(requestContext.getAuthenticationContext()).thenReturn(new AuthenticationContext()); + APIConfig apiConfig = Mockito.mock(APIConfig.class); + Mockito.when(apiConfig.getName()).thenReturn("api1"); + Mockito.when(apiConfig.getOrganizationId()).thenReturn(organization); + Mockito.when(requestContext.getMatchedAPI()).thenReturn(apiConfig); + CacheProvider cacheProvider = Mockito.mock(CacheProvider.class); + LoadingCache gatewayKeyCache = Mockito.mock(LoadingCache.class); + LoadingCache invalidTokenCache = Mockito.mock(LoadingCache.class); + Mockito.when(cacheProvider.getGatewayKeyCache()).thenReturn(gatewayKeyCache); + Mockito.when(cacheProvider.getInvalidTokenCache()).thenReturn(invalidTokenCache); + Mockito.when(gatewayKeyCache.getIfPresent(signature)).thenReturn(jwtValidationInfo); + Mockito.when(invalidTokenCache.getIfPresent(signature)).thenReturn(null); + Mockito.when(CacheProviderUtil.getOrganizationCache(organization)).thenReturn(cacheProvider); + + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + SubscriptionDataStoreImpl subscriptionDataStore = Mockito.mock(SubscriptionDataStoreImpl.class); + Mockito.when(SubscriptionDataStoreImpl.getInstance()).thenReturn(subscriptionDataStore); + Mockito.when(subscriptionDataStore.getJWTValidatorByIssuer(issuer, + organization)).thenReturn(jwtValidator); + Mockito.when(jwtValidator.validateToken(Mockito.eq(jwt), Mockito.any())).thenReturn(jwtValidationInfo); + + try { + Mockito.when(KeyValidator.validateScopes(Mockito.any())).thenReturn(true); + } catch (APISecurityException e) { + Assert.fail("Unexpected exception occurred while validating scopes"); + } + try { + jwtAuthenticator.authenticate(requestContext); + Assert.fail("Authentication should fail for tampered tokens"); + } catch (APISecurityException e) { + Assert.assertEquals(e.getMessage(), "Invalid JWT token"); + Mockito.verify(invalidTokenCache, Mockito.never()).put(signature, true); + Mockito.verify(gatewayKeyCache, Mockito.never()).put(signature, true); + Mockito.verify(gatewayKeyCache, Mockito.never()).invalidate(signature); + } + } +}