diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/InboundWebSocketProcessor.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/InboundWebSocketProcessor.java index c721908c8ea4..8a3601de4628 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/InboundWebSocketProcessor.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/InboundWebSocketProcessor.java @@ -96,7 +96,7 @@ public InboundWebSocketProcessor() { * @return InboundProcessorResponseDTO with handshake processing response */ public InboundProcessorResponseDTO handleHandshake(FullHttpRequest req, ChannelHandlerContext ctx, - InboundMessageContext inboundMessageContext) throws APIManagementException { + InboundMessageContext inboundMessageContext) { InboundProcessorResponseDTO inboundProcessorResponseDTO; try { diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/ApiKeyAuthenticator.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/ApiKeyAuthenticator.java index 4a9f2732e9ab..ebdcd391e616 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/ApiKeyAuthenticator.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/ApiKeyAuthenticator.java @@ -47,17 +47,16 @@ import java.util.Map; import java.util.HashMap; -public class ApiKeyAuthenticator implements Authenticator { - - private static final Log log = LogFactory.getLog(org.wso2.carbon.apimgt.gateway.inbound.websocket.utils.ApiKeyAuthenticator.class); +public class ApiKeyAuthenticator { + private static final Log log = LogFactory.getLog(ApiKeyAuthenticator.class); private Boolean jwtGenerationEnabled = null; private AbstractAPIMgtGatewayJWTGenerator apiMgtGatewayJWTGenerator = null; private ExtendedJWTConfigurationDto jwtConfigurationDto = null; private Boolean isGatewayTokenCacheEnabled = null; private static volatile long ttl = -1L; - public InboundProcessorResponseDTO authenticate(InboundMessageContext inboundMessageContext, String authenticationType) throws APISecurityException { + public InboundProcessorResponseDTO authenticate(InboundMessageContext inboundMessageContext) throws APISecurityException { InboundProcessorResponseDTO inboundProcessorResponseDTO = new InboundProcessorResponseDTO(); @@ -75,12 +74,12 @@ public InboundProcessorResponseDTO authenticate(InboundMessageContext inboundMes ServiceReferenceHolder.getInstance().getAPIManagerConfiguration().getJwtConfigurationDto(); } - if (jwtGenerationEnabled == null) { + if (jwtGenerationEnabled == null && jwtConfigurationDto != null) { jwtGenerationEnabled = jwtConfigurationDto.isEnabled(); } - if (apiMgtGatewayJWTGenerator == null) { + if (apiMgtGatewayJWTGenerator == null && jwtConfigurationDto != null) { apiMgtGatewayJWTGenerator = ServiceReferenceHolder.getInstance().getApiMgtGatewayJWTGenerator() .get(jwtConfigurationDto.getGatewayJWTGeneratorImpl()); } @@ -88,7 +87,7 @@ public InboundProcessorResponseDTO authenticate(InboundMessageContext inboundMes String tenantDomain = GatewayUtils.getTenantDomain(); int tenantId = APIUtil.getTenantIdFromTenantDomain(tenantDomain); - if (jwtGenerationEnabled) { + if (jwtGenerationEnabled != null && jwtGenerationEnabled) { // Set certificate to jwtConfigurationDto if (jwtConfigurationDto.isTenantBasedSigningEnabled()) { this.jwtConfigurationDto.setPublicCert(SigningUtil.getPublicCertificate(tenantId)); @@ -516,7 +515,7 @@ private String removeApiKeyFromQueryParameters(String queryParam, String apiKey) return queryParam; } - public boolean validateAuthenticationContext(InboundMessageContext inboundMessageContext, AuthenticationContext authenticationContext, String contextHeader) { + private boolean validateAuthenticationContext(InboundMessageContext inboundMessageContext, AuthenticationContext authenticationContext, String contextHeader) { if (authenticationContext == null || !authenticationContext.isAuthenticated()) { return false; @@ -561,7 +560,7 @@ public boolean validateAuthenticationContext(InboundMessageContext inboundMessag * @param payload The payload of the JWT token * @return returns true if the JWT token is expired */ - private static boolean isJwtTokenExpired(JWTClaimsSet payload) { + private boolean isJwtTokenExpired(JWTClaimsSet payload) { int timestampSkew = (int) OAuthServerConfiguration.getInstance().getTimeStampSkewInSeconds(); @@ -590,7 +589,7 @@ private JWTValidationInfo getJwtValidationInfo(SignedJWTInfo signedJWTInfo) { return jwtValidationInfo; } - public String getContextHeader() { + private String getContextHeader() { APIManagerConfiguration apimConf = ServiceReferenceHolder.getInstance().getAPIManagerConfiguration(); JWTConfigurationDto jwtConfigDto = apimConf.getJwtConfigurationDto(); return jwtConfigDto.getJwtHeader(); diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/Authenticator.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/Authenticator.java deleted file mode 100644 index bd93d8267168..000000000000 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/Authenticator.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.wso2.carbon.apimgt.gateway.inbound.websocket.utils; - -import org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException; -import org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext; -import org.wso2.carbon.apimgt.gateway.inbound.websocket.InboundProcessorResponseDTO; - -public interface Authenticator { - - InboundProcessorResponseDTO authenticate(InboundMessageContext inboundMessageContext, String authenticationType) throws APISecurityException; -} diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/InboundWebsocketProcessorUtil.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/InboundWebsocketProcessorUtil.java index 0da27237f552..cda72d86ac4c 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/InboundWebsocketProcessorUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/InboundWebsocketProcessorUtil.java @@ -58,7 +58,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.ArrayList; import java.util.TreeMap; /** @@ -327,12 +326,14 @@ public static InboundProcessorResponseDTO authenticateToken(InboundMessageContex return authenticateToken(inboundMessageContext, APIConstants.WEBSOCKET_FRAME); } - public static InboundProcessorResponseDTO authenticateToken(InboundMessageContext inboundMessageContext, String authenticationType) throws APISecurityException { + public static InboundProcessorResponseDTO authenticateToken(InboundMessageContext inboundMessageContext, + String authenticationType) throws APISecurityException { if (inboundMessageContext.getRequestHeaders().get(WebsocketUtil.authorizationHeader) != null) { return new OAuthAuthenticator().authenticate(inboundMessageContext, authenticationType); - } else if (inboundMessageContext.getRequestHeaders().get(APIConstants.API_KEY_HEADER_QUERY_PARAM) != null || inboundMessageContext.getApiKeyFromQueryParams() != null) { - return new ApiKeyAuthenticator().authenticate(inboundMessageContext, authenticationType); + } else if (inboundMessageContext.getRequestHeaders().get(APIConstants.API_KEY_HEADER_QUERY_PARAM) != null || + inboundMessageContext.getApiKeyFromQueryParams() != null) { + return new ApiKeyAuthenticator().authenticate(inboundMessageContext); } else { throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE); diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/OAuthAuthenticator.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/OAuthAuthenticator.java index aecc42abcd39..1a04d2005abd 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/OAuthAuthenticator.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/OAuthAuthenticator.java @@ -25,14 +25,13 @@ import java.text.ParseException; import java.util.List; -public class OAuthAuthenticator implements Authenticator { +public class OAuthAuthenticator { private static final Log log = LogFactory.getLog(OAuthAuthenticator.class); public OAuthAuthenticator() { } - @Override public InboundProcessorResponseDTO authenticate(InboundMessageContext inboundMessageContext, String authenticationType) throws APISecurityException { InboundProcessorResponseDTO inboundProcessorResponseDTO = new InboundProcessorResponseDTO(); @@ -99,8 +98,9 @@ public InboundProcessorResponseDTO authenticate(InboundMessageContext inboundMes } validateScopes = !APIConstants.GRAPHQL_API.equals(inboundMessageContext.getElectedAPI().getApiType()); } else { - inboundProcessorResponseDTO.setError(true); - return inboundProcessorResponseDTO; + return InboundWebsocketProcessorUtil.getFrameErrorDTO( + WebSocketApiConstants.FrameErrorConstants.API_AUTH_INVALID_CREDENTIALS, + APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE, true); } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/ApiKeyAuthenticatorTest.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/ApiKeyAuthenticatorTest.java new file mode 100644 index 000000000000..a2cfda2b5488 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/ApiKeyAuthenticatorTest.java @@ -0,0 +1,314 @@ +package org.wso2.carbon.apimgt.gateway.inbound.websocket.utils; + +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +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.testng.Assert; +import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.gateway.handlers.WebsocketUtil; +import org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationContext; +import org.wso2.carbon.apimgt.gateway.handlers.security.jwt.JWTValidator; +import org.wso2.carbon.apimgt.gateway.inbound.InboundMessageContext; +import org.wso2.carbon.apimgt.gateway.internal.DataHolder; +import org.wso2.carbon.apimgt.gateway.internal.ServiceReferenceHolder; +import org.wso2.carbon.apimgt.gateway.utils.GatewayUtils; +import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.APIManagerConfiguration; +import org.wso2.carbon.apimgt.impl.caching.CacheProvider; +import org.wso2.carbon.apimgt.impl.dto.ExtendedJWTConfigurationDto; +import org.wso2.carbon.apimgt.impl.jwt.JWTValidationService; +import org.wso2.carbon.apimgt.impl.utils.APIUtil; +import org.wso2.carbon.apimgt.keymgt.model.entity.API; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; + +import javax.cache.Cache; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({PrivilegedCarbonContext.class, + ServiceReferenceHolder.class, WebsocketUtil.class, APIUtil.class, DataHolder.class, + ApiKeyAuthenticator.class, CacheProvider.class, GatewayUtils.class, JWTClaimsSet.class}) + +public class ApiKeyAuthenticatorTest { + + private DataHolder dataHolder; + List keyManagers; + String apiKey; + + @Before + public void init() throws APIManagementException { + System.setProperty("carbon.home", "jhkjn"); + PowerMockito.mockStatic(PrivilegedCarbonContext.class); + PowerMockito.mockStatic(ServiceReferenceHolder.class); + PrivilegedCarbonContext privilegedCarbonContext = Mockito.mock(PrivilegedCarbonContext.class); + dataHolder = Mockito.mock(DataHolder.class); + ServiceReferenceHolder serviceReferenceHolder = Mockito.mock(ServiceReferenceHolder.class); + JWTValidationService jwtValidationService = Mockito.mock(JWTValidationService.class); + PowerMockito.when(PrivilegedCarbonContext.getThreadLocalCarbonContext()).thenReturn(privilegedCarbonContext); + PowerMockito.when(ServiceReferenceHolder.getInstance()).thenReturn(serviceReferenceHolder); + PowerMockito.when(serviceReferenceHolder.getJwtValidationService()).thenReturn(jwtValidationService); + Mockito.when(jwtValidationService.getKeyManagerNameIfJwtValidatorExist(Mockito.anyObject())) + .thenReturn("KeyManager"); + APIManagerConfiguration apiManagerConfiguration = Mockito.mock(APIManagerConfiguration.class); + PowerMockito.when(serviceReferenceHolder.getAPIManagerConfiguration()).thenReturn(apiManagerConfiguration); + PowerMockito.mockStatic(APIUtil.class); + PowerMockito.mockStatic(WebsocketUtil.class); + PowerMockito.mockStatic(DataHolder.class); + Mockito.when(DataHolder.getInstance()).thenReturn(dataHolder); + keyManagers = Collections.singletonList(APIConstants.KeyManager.API_LEVEL_ALL_KEY_MANAGERS); + apiKey = "eyJ4NXQiOiJPREUzWTJaaE1UQmpNRE00WlRCbU1qQXlZemxpWVRJMllqUmhZVFpsT0dJeVptVXhOV0UzWVE9PSIsImtpZCI" + + "6ImdhdGV3YXlfY2VydGlmaWNhdGVfYWxpYXMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbkBjYXJib24uc" + + "3VwZXIiLCJhcHBsaWNhdGlvbiI6eyJvd25lciI6ImFkbWluIiwidGllclF1b3RhVHlwZSI6bnVsbCwidGllciI6IlVubGltaXRlZCIs" + + "Im5hbWUiOiJEZWZhdWx0QXBwbGljYXRpb24iLCJpZCI6MSwidXVpZCI6IjA2MzRkMGI0LWRmMGEtNGMzZS04ZmY2LWRmODNhOTAzYTl" + + "mNiJ9LCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0NDNcL29hdXRoMlwvdG9rZW4iLCJ0aWVySW5mbyI6eyJBc3luY1VubGltaX" + + "RlZCI6eyJ0aWVyUXVvdGFUeXBlIjoiZXZlbnRDb3VudCIsImdyYXBoUUxNYXhDb21wbGV4aXR5IjowLCJncmFwaFFMTWF4RGVwdGgiO" + + "jAsInN0b3BPblF1b3RhUmVhY2giOnRydWUsInNwaWtlQXJyZXN0TGltaXQiOjAsInNwaWtlQXJyZXN0VW5pdCI6bnVsbH19LCJrZXl0" + + "eXBlIjoiU0FOREJPWCIsInBlcm1pdHRlZFJlZmVyZXIiOiIiLCJzdWJzY3JpYmVkQVBJcyI6W3sic3Vic2NyaWJlclRlbmFudERvbWF" + + "pbiI6ImNhcmJvbi5zdXBlciIsIm5hbWUiOiJDaGF0cyIsImNvbnRleHQiOiJcL2NoYXRzXC8xLjAuMCIsInB1Ymxpc2hlciI6ImFkbW" + + "luIiwidmVyc2lvbiI6IjEuMC4wIiwic3Vic2NyaXB0aW9uVGllciI6IkFzeW5jVW5saW1pdGVkIn1dLCJ0b2tlbl90eXBlIjoiYXBpS" + + "2V5IiwicGVybWl0dGVkSVAiOiIiLCJpYXQiOjE2OTM5OTk3MDcsImp0aSI6IjhjY2M1YzBlLWFlODMtNGM4MS1hN2JmLTVjMmNiYTc0" + + "ZmM1OCJ9.VYkMrt6vs82V1cVJ-ChFcgBfej3m8P22lmnG0_Q1g_fox0ZeJklWhjtsI8dxyTJ0tRx57dg1dOFQD-VbRTnoxOmWDnZdxB" + + "_cGQfrn-2A72HBTMx-lAaMGAi0Gi9OjXBa8J2ilc7qBgL4au4HVfSyOxpAJIDgwPnjIYjDovnYQPMhZemaOfKTbfReU3g_w8MBKLN20" + + "hjZT02gKpwyak1LnXG4ulKi-A0qZlm2VSArpwF73x9vK0rIiWT17UR43IJNoDAmXjG76lwmNeIIiDhyqRBLDdRwmxFLlac6KsqeESMh" + + "xoklqH1_0x4VyUG-JYlJMQVFd5FmWmnjjF4eJZwSaQ=="; + } + + @Test + public void authenticationForAPIKeyAsRequestHeader() throws Exception { + + ApiKeyAuthenticator apiKeyAuthenticator = PowerMockito.spy(new ApiKeyAuthenticator()); + InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); + inboundMessageContext.getRequestHeaders().put(APIConstants.API_KEY_HEADER_QUERY_PARAM, apiKey); + Mockito.when(dataHolder.getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid())) + .thenReturn(keyManagers); + Mockito.when(ServiceReferenceHolder.getInstance().getAPIManagerConfiguration().getJwtConfigurationDto()) + .thenReturn(new ExtendedJWTConfigurationDto()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "isGatewayTokenCacheEnabled")) + .toReturn(true); + Cache internalKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyCache()).thenReturn(internalKeyCache); + Mockito.when(internalKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "verifyTokenSignature", SignedJWT.class, + String.class)).toReturn(true); + Cache invalidGatewayApiKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getInvalidGatewayApiKeyCache()).thenReturn(invalidGatewayApiKeyCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + PowerMockito.whenNew(JWTValidator.class).withAnyArguments().thenReturn(jwtValidator); + PowerMockito.doReturn(false).when(apiKeyAuthenticator, "isJwtTokenExpired", Mockito.any(JWTClaimsSet.class)); + Cache gatewayApiKeyDataCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyDataCache()).thenReturn(gatewayApiKeyDataCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "validateAPISubscription", String.class, + String.class, JWTClaimsSet.class, String[].class, boolean.class)).toReturn(new net.minidev.json.JSONObject()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "generateAuthenticationContext", String.class, + JWTClaimsSet.class, net.minidev.json.JSONObject.class, String.class, String.class, + org.apache.synapse.MessageContext.class)).toReturn(new AuthenticationContext()); + PowerMockito.stub(PowerMockito.method(ApiKeyAuthenticator.class, "validateAuthenticationContext")) + .toReturn(true); + Assert.assertFalse(apiKeyAuthenticator.authenticate(inboundMessageContext).isError()); + } + + @Test + public void authenticationForAPIKeyAsQueryParam() throws Exception { + + ApiKeyAuthenticator apiKeyAuthenticator = PowerMockito.spy(new ApiKeyAuthenticator()); + InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); + inboundMessageContext.setApiKeyFromQueryParams(apiKey); + inboundMessageContext.setFullRequestPath("ws://localhost:9099/chats/1.0.0/notifications?apikey=" + apiKey); + Mockito.when(dataHolder.getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid())) + .thenReturn(keyManagers); + Mockito.when(ServiceReferenceHolder.getInstance().getAPIManagerConfiguration().getJwtConfigurationDto()) + .thenReturn(new ExtendedJWTConfigurationDto()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "isGatewayTokenCacheEnabled")) + .toReturn(true); + Cache internalKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyCache()).thenReturn(internalKeyCache); + Mockito.when(internalKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "verifyTokenSignature", SignedJWT.class, + String.class)).toReturn(true); + Cache invalidGatewayApiKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getInvalidGatewayApiKeyCache()).thenReturn(invalidGatewayApiKeyCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + PowerMockito.whenNew(JWTValidator.class).withAnyArguments().thenReturn(jwtValidator); + PowerMockito.doReturn(false).when(apiKeyAuthenticator, "isJwtTokenExpired", Mockito.any(JWTClaimsSet.class)); + Cache gatewayApiKeyDataCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyDataCache()).thenReturn(gatewayApiKeyDataCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "validateAPISubscription", String.class, + String.class, JWTClaimsSet.class, String[].class, boolean.class)).toReturn(new net.minidev.json.JSONObject()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "generateAuthenticationContext", String.class, + JWTClaimsSet.class, net.minidev.json.JSONObject.class, String.class, String.class, + org.apache.synapse.MessageContext.class)).toReturn(new AuthenticationContext()); + PowerMockito.stub(PowerMockito.method(ApiKeyAuthenticator.class, "validateAuthenticationContext")) + .toReturn(true); + Assert.assertFalse(apiKeyAuthenticator.authenticate(inboundMessageContext).isError()); + } + + @Test + public void authenticationTestForExpiredAPIKey() throws Exception { + + ApiKeyAuthenticator apiKeyAuthenticator = PowerMockito.spy(new ApiKeyAuthenticator()); + InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); + inboundMessageContext.getRequestHeaders().put(APIConstants.API_KEY_HEADER_QUERY_PARAM, apiKey); + Mockito.when(dataHolder.getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid())) + .thenReturn(keyManagers); + Mockito.when(ServiceReferenceHolder.getInstance().getAPIManagerConfiguration().getJwtConfigurationDto()) + .thenReturn(new ExtendedJWTConfigurationDto()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "isGatewayTokenCacheEnabled")) + .toReturn(true); + Cache internalKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyCache()).thenReturn(internalKeyCache); + Mockito.when(internalKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "verifyTokenSignature", SignedJWT.class, + String.class)).toReturn(true); + Cache invalidGatewayApiKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getInvalidGatewayApiKeyCache()).thenReturn(invalidGatewayApiKeyCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + PowerMockito.whenNew(JWTValidator.class).withAnyArguments().thenReturn(jwtValidator); + PowerMockito.doReturn(true).when(apiKeyAuthenticator, "isJwtTokenExpired", Mockito.any(JWTClaimsSet.class)); + Cache gatewayApiKeyDataCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyDataCache()).thenReturn(gatewayApiKeyDataCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "validateAPISubscription", String.class, + String.class, JWTClaimsSet.class, String[].class, boolean.class)).toReturn(new net.minidev.json.JSONObject()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "generateAuthenticationContext", String.class, + JWTClaimsSet.class, net.minidev.json.JSONObject.class, String.class, String.class, + org.apache.synapse.MessageContext.class)).toReturn(new AuthenticationContext()); + PowerMockito.stub(PowerMockito.method(ApiKeyAuthenticator.class, "validateAuthenticationContext")) + .toReturn(true); + Assert.assertTrue(apiKeyAuthenticator.authenticate(inboundMessageContext).isError()); + } + + @Test + public void authenticationTestForRestrictedIP() throws Exception { + //Following APIKey has been generated by providing allowed IP as 192.168.1.1 + String apiKey = "eyJ4NXQiOiJPREUzWTJaaE1UQmpNRE00WlRCbU1qQXlZemxpWVRJMllqUmhZVFpsT0dJeVptVXhOV0UzWVE9PSIsImtpZCI" + + "6ImdhdGV3YXlfY2VydGlmaWNhdGVfYWxpYXMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbkBjYXJib24uc" + + "3VwZXIiLCJhcHBsaWNhdGlvbiI6eyJvd25lciI6ImFkbWluIiwidGllclF1b3RhVHlwZSI6bnVsbCwidGllciI6IlVubGltaXRlZCIs" + + "Im5hbWUiOiJEZWZhdWx0QXBwbGljYXRpb24iLCJpZCI6MSwidXVpZCI6IjA1M2IzNjEwLTI5MGEtNDM0OC05Zjc4LWMyODM4OTc3NGE" + + "2NiJ9LCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0NDNcL29hdXRoMlwvdG9rZW4iLCJ0aWVySW5mbyI6eyJBc3luY1VubGltaX" + + "RlZCI6eyJ0aWVyUXVvdGFUeXBlIjoiZXZlbnRDb3VudCIsImdyYXBoUUxNYXhDb21wbGV4aXR5IjowLCJncmFwaFFMTWF4RGVwdGgiO" + + "jAsInN0b3BPblF1b3RhUmVhY2giOnRydWUsInNwaWtlQXJyZXN0TGltaXQiOjAsInNwaWtlQXJyZXN0VW5pdCI6bnVsbH19LCJrZXl0" + + "eXBlIjoiU0FOREJPWCIsInBlcm1pdHRlZFJlZmVyZXIiOiIiLCJzdWJzY3JpYmVkQVBJcyI6W3sic3Vic2NyaWJlclRlbmFudERvbWF" + + "pbiI6ImNhcmJvbi5zdXBlciIsIm5hbWUiOiJDaGF0cyIsImNvbnRleHQiOiJcL2NoYXRzXC8xLjAuMCIsInB1Ymxpc2hlciI6ImFkbW" + + "luIiwidmVyc2lvbiI6IjEuMC4wIiwic3Vic2NyaXB0aW9uVGllciI6IkFzeW5jVW5saW1pdGVkIn1dLCJ0b2tlbl90eXBlIjoiYXBpS" + + "2V5IiwicGVybWl0dGVkSVAiOiIxOTIuMTY4LjEuMiIsImlhdCI6MTY5NDAxOTgzNywianRpIjoiYmJhNWM3MWYtZjc0NS00NDQzLTkz" + + "OGEtODI1YzNhMmYyMmU2In0=.vywflR4UEKA7awycXGYFqFTn0AgUSZLSL9ob6kZLEMaei6PTktsVmGT9kLjRK5sJTmaSvr9JoUtvKL" + + "kVhkUusL9rWp8Wikj0fPE-BkmYjGQYnRdzSS-M8z_ajS1MekjWvedcl5m-ID_8iMJEilDPPJNkmE1ujeUc1Pliw9KvM2L9kuogq9j5R" + + "7s-E8jI-2oI_xdHc4hEXkU81GGUJtjfDkXbM2OrfOUAd-OWmFmgyp3p1tdbux2GbwBnuTcrF3kgxuQRHTv86hyxz_0Ik70ypNbpJ0qs" + + "5z8qDyU4jSMoid7gyeCoOOJxyCAwCNjGNxc-6YsQpknQjXVd3cMfbOqneQ=="; + + ApiKeyAuthenticator apiKeyAuthenticator = PowerMockito.spy(new ApiKeyAuthenticator()); + InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); + inboundMessageContext.setApiKeyFromQueryParams(apiKey); + inboundMessageContext.setFullRequestPath("ws://localhost:9099/chats/1.0.0/notifications?apikey=" + apiKey); + inboundMessageContext.setUserIP("192.168.1.1"); + Mockito.when(dataHolder.getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid())) + .thenReturn(keyManagers); + Mockito.when(ServiceReferenceHolder.getInstance().getAPIManagerConfiguration().getJwtConfigurationDto()) + .thenReturn(new ExtendedJWTConfigurationDto()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "isGatewayTokenCacheEnabled")) + .toReturn(true); + Cache internalKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyCache()).thenReturn(internalKeyCache); + Mockito.when(internalKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "verifyTokenSignature", SignedJWT.class, + String.class)).toReturn(true); + Cache invalidGatewayApiKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getInvalidGatewayApiKeyCache()).thenReturn(invalidGatewayApiKeyCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + PowerMockito.whenNew(JWTValidator.class).withAnyArguments().thenReturn(jwtValidator); + PowerMockito.doReturn(false).when(apiKeyAuthenticator, "isJwtTokenExpired", Mockito.any(JWTClaimsSet.class)); + Cache gatewayApiKeyDataCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyDataCache()).thenReturn(gatewayApiKeyDataCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "validateAPISubscription", String.class, + String.class, JWTClaimsSet.class, String[].class, boolean.class)).toReturn(new net.minidev.json.JSONObject()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "generateAuthenticationContext", String.class, + JWTClaimsSet.class, net.minidev.json.JSONObject.class, String.class, String.class, + org.apache.synapse.MessageContext.class)).toReturn(new AuthenticationContext()); + PowerMockito.stub(PowerMockito.method(ApiKeyAuthenticator.class, "validateAuthenticationContext")) + .toReturn(true); + Assert.assertTrue(apiKeyAuthenticator.authenticate(inboundMessageContext).isError()); + } + + @Test + public void authenticationTestForRestrictedWebSites() throws Exception { + //Following APIKey has been generated by providing allowed URL as www.wso2.com + String apiKey = "eyJ4NXQiOiJPREUzWTJaaE1UQmpNRE00WlRCbU1qQXlZemxpWVRJMllqUmhZVFpsT0dJeVptVXhOV0UzWVE9PSIsImtpZCI" + + "6ImdhdGV3YXlfY2VydGlmaWNhdGVfYWxpYXMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbkBjYXJib24uc" + + "3VwZXIiLCJhcHBsaWNhdGlvbiI6eyJvd25lciI6ImFkbWluIiwidGllclF1b3RhVHlwZSI6bnVsbCwidGllciI6IlVubGltaXRlZCIs" + + "Im5hbWUiOiJEZWZhdWx0QXBwbGljYXRpb24iLCJpZCI6MSwidXVpZCI6IjA1M2IzNjEwLTI5MGEtNDM0OC05Zjc4LWMyODM4OTc3NGE" + + "2NiJ9LCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0NDNcL29hdXRoMlwvdG9rZW4iLCJ0aWVySW5mbyI6eyJVbmxpbWl0ZWQiOn" + + "sidGllclF1b3RhVHlwZSI6InJlcXVlc3RDb3VudCIsImdyYXBoUUxNYXhDb21wbGV4aXR5IjowLCJncmFwaFFMTWF4RGVwdGgiOjAsI" + + "nN0b3BPblF1b3RhUmVhY2giOnRydWUsInNwaWtlQXJyZXN0TGltaXQiOjAsInNwaWtlQXJyZXN0VW5pdCI6bnVsbH0sIkFzeW5jVW5s" + + "aW1pdGVkIjp7InRpZXJRdW90YVR5cGUiOiJldmVudENvdW50IiwiZ3JhcGhRTE1heENvbXBsZXhpdHkiOjAsImdyYXBoUUxNYXhEZXB" + + "0aCI6MCwic3RvcE9uUXVvdGFSZWFjaCI6dHJ1ZSwic3Bpa2VBcnJlc3RMaW1pdCI6MCwic3Bpa2VBcnJlc3RVbml0IjpudWxsfX0sIm" + + "tleXR5cGUiOiJTQU5EQk9YIiwicGVybWl0dGVkUmVmZXJlciI6Ind3dy53c28yLmNvbSIsInN1YnNjcmliZWRBUElzIjpbeyJzdWJzY" + + "3JpYmVyVGVuYW50RG9tYWluIjoiY2FyYm9uLnN1cGVyIiwibmFtZSI6IkNoYXRzIiwiY29udGV4dCI6IlwvY2hhdHNcLzEuMC4wIiwi" + + "cHVibGlzaGVyIjoiYWRtaW4iLCJ2ZXJzaW9uIjoiMS4wLjAiLCJzdWJzY3JpcHRpb25UaWVyIjoiQXN5bmNVbmxpbWl0ZWQifSx7InN" + + "1YnNjcmliZXJUZW5hbnREb21haW4iOiJjYXJib24uc3VwZXIiLCJuYW1lIjoiUGl6emFTaGFja0FQSSIsImNvbnRleHQiOiJcL3Bpen" + + "phc2hhY2tcLzEuMC4wIiwicHVibGlzaGVyIjoiYWRtaW4iLCJ2ZXJzaW9uIjoiMS4wLjAiLCJzdWJzY3JpcHRpb25UaWVyIjoiVW5sa" + + "W1pdGVkIn1dLCJ0b2tlbl90eXBlIjoiYXBpS2V5IiwicGVybWl0dGVkSVAiOiIiLCJpYXQiOjE2OTQwMjExMDEsImp0aSI6Ijc1MDkx" + + "MDZkLWIxYTItNGIxOS05YmY2LTM0MjY5Yzg1YTJmZSJ9.RZoEI57qNBKlHR8BhHFEBlYcqkZUyXuIoh4MB1jFlk6TQK4VgGvTiTpNs1" + + "9igd4sU2cmTN_F7CQQnwru7QZjRsbOHlxjhxSva1w0GjOZPg8IfX4NnNV0ThZDDwwDdtvxd-nxkoYCbRozvtk2VYjorCxVOQHsw97Jl" + + "VDt-vRAfuchtaKTS2AlKwIzajael-3-88RWsI9i6LpboDB0VGyFzvHjP2uTp_Hg7cI5xTyaYvcbcIz71kyPc4PwCCkpyJAwvmE6EHLw" + + "HdYQK3_K3j8B0W1TWq4aTOTluTf2KTJd1Bp36zT9KkVYuMdcCguacA3-ZJ_HhEb7AvSVNv9nC5flHw=="; + + ApiKeyAuthenticator apiKeyAuthenticator = PowerMockito.spy(new ApiKeyAuthenticator()); + InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); + inboundMessageContext.setApiKeyFromQueryParams(apiKey); + inboundMessageContext.setFullRequestPath("ws://localhost:9099/chats/1.0.0/notifications?apikey=" + apiKey); + inboundMessageContext.getRequestHeaders().put("Referer", "www.example.com"); + Mockito.when(dataHolder.getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid())) + .thenReturn(keyManagers); + Mockito.when(ServiceReferenceHolder.getInstance().getAPIManagerConfiguration().getJwtConfigurationDto()) + .thenReturn(new ExtendedJWTConfigurationDto()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "isGatewayTokenCacheEnabled")) + .toReturn(true); + Cache internalKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyCache()).thenReturn(internalKeyCache); + Mockito.when(internalKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "verifyTokenSignature", SignedJWT.class, + String.class)).toReturn(true); + Cache invalidGatewayApiKeyCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getInvalidGatewayApiKeyCache()).thenReturn(invalidGatewayApiKeyCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + PowerMockito.whenNew(JWTValidator.class).withAnyArguments().thenReturn(jwtValidator); + PowerMockito.doReturn(false).when(apiKeyAuthenticator, "isJwtTokenExpired", Mockito.any(JWTClaimsSet.class)); + Cache gatewayApiKeyDataCache = Mockito.mock(Cache.class); + PowerMockito.when(CacheProvider.getGatewayApiKeyDataCache()).thenReturn(gatewayApiKeyDataCache); + Mockito.when(invalidGatewayApiKeyCache.get(Mockito.anyString())).thenReturn(null); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "validateAPISubscription", String.class, + String.class, JWTClaimsSet.class, String[].class, boolean.class)).toReturn(new net.minidev.json.JSONObject()); + PowerMockito.stub(PowerMockito.method(GatewayUtils.class, "generateAuthenticationContext", String.class, + JWTClaimsSet.class, net.minidev.json.JSONObject.class, String.class, String.class, + org.apache.synapse.MessageContext.class)).toReturn(new AuthenticationContext()); + PowerMockito.stub(PowerMockito.method(ApiKeyAuthenticator.class, "validateAuthenticationContext")) + .toReturn(true); + Assert.assertTrue(apiKeyAuthenticator.authenticate(inboundMessageContext).isError()); + } + + private InboundMessageContext createWebSocketApiMessageContext() { + API websocketAPI = new API(UUID.randomUUID().toString(), 1, "admin", "WSAPI", "1.0.0", "/wscontext", + "Unlimited", APIConstants.API_TYPE_WS, APIConstants.PUBLISHED_STATUS, false); + InboundMessageContext inboundMessageContext = new InboundMessageContext(); + inboundMessageContext.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); + inboundMessageContext.setElectedAPI(websocketAPI); + return inboundMessageContext; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/InboundWebsocketProcessorUtilTest.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/InboundWebsocketProcessorUtilTest.java index df3fda3ed13a..997baee3e5de 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/InboundWebsocketProcessorUtilTest.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/test/java/org/wso2/carbon/apimgt/gateway/inbound/websocket/utils/InboundWebsocketProcessorUtilTest.java @@ -17,6 +17,7 @@ */ package org.wso2.carbon.apimgt.gateway.inbound.websocket.utils; +import com.nimbusds.jwt.JWTClaimsSet; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; @@ -41,8 +42,10 @@ import org.wso2.carbon.apimgt.gateway.internal.DataHolder; import org.wso2.carbon.apimgt.gateway.internal.ServiceReferenceHolder; import org.wso2.carbon.apimgt.gateway.throttling.publisher.ThrottleDataPublisher; +import org.wso2.carbon.apimgt.gateway.utils.GatewayUtils; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.APIManagerConfiguration; +import org.wso2.carbon.apimgt.impl.caching.CacheProvider; import org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO; import org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO; import org.wso2.carbon.apimgt.impl.jwt.JWTValidationService; @@ -57,15 +60,16 @@ import java.util.UUID; @RunWith(PowerMockRunner.class) -@PrepareForTest({ InboundWebsocketProcessorUtil.class, PrivilegedCarbonContext.class, +@PrepareForTest({InboundWebsocketProcessorUtil.class, PrivilegedCarbonContext.class, ServiceReferenceHolder.class, WebsocketUtil.class, ThrottleDataPublisher.class, APIUtil.class, DataHolder.class, - InboundWebsocketProcessorUtil.class, OAuthAuthenticator.class }) + OAuthAuthenticator.class, ApiKeyAuthenticator.class, CacheProvider.class, GatewayUtils.class, JWTClaimsSet.class}) public class InboundWebsocketProcessorUtilTest { private DataPublisher dataPublisher; private DataHolder dataHolder; List keyManagers; String authenticationHeader; + String apiKey; @Before public void init() throws APIManagementException { @@ -104,6 +108,21 @@ public void init() throws APIManagementException { + "cReHIYTC7kHmozvGGSBl2aul_c7-ND1twPF8N3cXfdJMrdlL0i-fE5D39BUS4RkLstbrLVPNDJ-HQAJ8AR0UN7dDEnQYwiaTXTMM" + "EgIGtk-PF1o8a9Rao_HPdiM0v9xiuZUXWBVqGPgnJkXH2tq_EZwY3sFzuvW_jBE84cvyD9w_wU0f89sIC8RHhc0L17riSA-21yKO" + "6twHWjeAgZe_Kdg"; + apiKey = "eyJ4NXQiOiJPREUzWTJaaE1UQmpNRE00WlRCbU1qQXlZemxpWVRJMllqUmhZVFpsT0dJeVptVXhOV0UzWVE9PSIsImtpZCI" + + "6ImdhdGV3YXlfY2VydGlmaWNhdGVfYWxpYXMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbkBjYXJib24uc" + + "3VwZXIiLCJhcHBsaWNhdGlvbiI6eyJvd25lciI6ImFkbWluIiwidGllclF1b3RhVHlwZSI6bnVsbCwidGllciI6IlVubGltaXRlZCIs" + + "Im5hbWUiOiJEZWZhdWx0QXBwbGljYXRpb24iLCJpZCI6MSwidXVpZCI6IjA2MzRkMGI0LWRmMGEtNGMzZS04ZmY2LWRmODNhOTAzYTl" + + "mNiJ9LCJpc3MiOiJodHRwczpcL1wvbG9jYWxob3N0Ojk0NDNcL29hdXRoMlwvdG9rZW4iLCJ0aWVySW5mbyI6eyJBc3luY1VubGltaX" + + "RlZCI6eyJ0aWVyUXVvdGFUeXBlIjoiZXZlbnRDb3VudCIsImdyYXBoUUxNYXhDb21wbGV4aXR5IjowLCJncmFwaFFMTWF4RGVwdGgiO" + + "jAsInN0b3BPblF1b3RhUmVhY2giOnRydWUsInNwaWtlQXJyZXN0TGltaXQiOjAsInNwaWtlQXJyZXN0VW5pdCI6bnVsbH19LCJrZXl0" + + "eXBlIjoiU0FOREJPWCIsInBlcm1pdHRlZFJlZmVyZXIiOiIiLCJzdWJzY3JpYmVkQVBJcyI6W3sic3Vic2NyaWJlclRlbmFudERvbWF" + + "pbiI6ImNhcmJvbi5zdXBlciIsIm5hbWUiOiJDaGF0cyIsImNvbnRleHQiOiJcL2NoYXRzXC8xLjAuMCIsInB1Ymxpc2hlciI6ImFkbW" + + "luIiwidmVyc2lvbiI6IjEuMC4wIiwic3Vic2NyaXB0aW9uVGllciI6IkFzeW5jVW5saW1pdGVkIn1dLCJ0b2tlbl90eXBlIjoiYXBpS" + + "2V5IiwicGVybWl0dGVkSVAiOiIiLCJpYXQiOjE2OTM5OTk3MDcsImp0aSI6IjhjY2M1YzBlLWFlODMtNGM4MS1hN2JmLTVjMmNiYTc0" + + "ZmM1OCJ9.VYkMrt6vs82V1cVJ-ChFcgBfej3m8P22lmnG0_Q1g_fox0ZeJklWhjtsI8dxyTJ0tRx57dg1dOFQD-VbRTnoxOmWDnZdxB" + + "_cGQfrn-2A72HBTMx-lAaMGAi0Gi9OjXBa8J2ilc7qBgL4au4HVfSyOxpAJIDgwPnjIYjDovnYQPMhZemaOfKTbfReU3g_w8MBKLN20" + + "hjZT02gKpwyak1LnXG4ulKi-A0qZlm2VSArpwF73x9vK0rIiWT17UR43IJNoDAmXjG76lwmNeIIiDhyqRBLDdRwmxFLlac6KsqeESMh" + + "xoklqH1_0x4VyUG-JYlJMQVFd5FmWmnjjF4eJZwSaQ=="; } @Test @@ -196,7 +215,7 @@ public void testDoThrottleFail() throws ParseException { } @Test - public void isAuthenticatedJWT() throws Exception { + public void isAuthenticatedJWTForOAuth() throws Exception { InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); Mockito.when(dataHolder.getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid())) .thenReturn(keyManagers); @@ -210,7 +229,7 @@ public void isAuthenticatedJWT() throws Exception { } @Test - public void isAuthenticatedOpaque() throws Exception { + public void isAuthenticatedOpaqueForOAuth() throws Exception { String apiKey = "5ccc069c403ebaf9f0171e9517f40e41"; String authenticationHeader = "Bearer " + apiKey; InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); @@ -230,7 +249,7 @@ public void isAuthenticatedOpaque() throws Exception { } @Test - public void authenticateToken() throws Exception { + public void authenticateTokenForOAuth() throws Exception { InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); inboundMessageContext.setJWTToken(true); inboundMessageContext.getRequestHeaders().put(WebsocketUtil.authorizationHeader, authenticationHeader); @@ -244,7 +263,7 @@ public void authenticateToken() throws Exception { } @Test - public void authenticateTokenFailure() throws Exception { + public void authenticateTokenFailureForOAuth() throws Exception { InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); inboundMessageContext.setJWTToken(true); inboundMessageContext.getRequestHeaders().put(WebsocketUtil.authorizationHeader, authenticationHeader); @@ -257,6 +276,42 @@ public void authenticateTokenFailure() throws Exception { Assert.assertTrue(responseDTO.isError()); } + @Test + public void isAuthenticatedForAPIKeyAsRequestHeader() throws Exception { + InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); + InboundProcessorResponseDTO InboundProcessorResponseDTO = new InboundProcessorResponseDTO(); + Mockito.when(dataHolder.getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid())) + .thenReturn(keyManagers); + inboundMessageContext.getRequestHeaders().put(APIConstants.API_KEY_HEADER_QUERY_PARAM, apiKey); + PowerMockito.stub(PowerMockito.method(ApiKeyAuthenticator.class, "authenticate", InboundMessageContext.class)) + .toReturn(InboundProcessorResponseDTO); + Assert.assertTrue(InboundWebsocketProcessorUtil.isAuthenticated(inboundMessageContext)); + } + + @Test + public void isAuthenticatedForAPIKeyAsQueryParam() throws Exception { + InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); + InboundProcessorResponseDTO InboundProcessorResponseDTO = new InboundProcessorResponseDTO(); + Mockito.when(dataHolder.getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid())) + .thenReturn(keyManagers); + inboundMessageContext.setApiKeyFromQueryParams(apiKey); + JWTValidator jwtValidator = Mockito.mock(JWTValidator.class); + PowerMockito.whenNew(JWTValidator.class).withAnyArguments().thenReturn(jwtValidator); + PowerMockito.stub(PowerMockito.method(ApiKeyAuthenticator.class, "authenticate", InboundMessageContext.class)) + .toReturn(InboundProcessorResponseDTO); + Assert.assertTrue(InboundWebsocketProcessorUtil.isAuthenticated(inboundMessageContext)); + } + + @Test + public void isAuthenticatedFailWithUnclassifiedAuthenticationFailure() { + InboundMessageContext inboundMessageContext = createWebSocketApiMessageContext(); + Mockito.when(dataHolder.getKeyManagersFromUUID(inboundMessageContext.getElectedAPI().getUuid())) + .thenReturn(keyManagers); + Assert.assertThrows(APISecurityException.class, () -> { + InboundWebsocketProcessorUtil.isAuthenticated(inboundMessageContext); + }); + } + private InboundMessageContext createWebSocketApiMessageContext() { API websocketAPI = new API(UUID.randomUUID().toString(), 1, "admin", "WSAPI", "1.0.0", "/wscontext", "Unlimited", APIConstants.API_TYPE_WS, APIConstants.PUBLISHED_STATUS, false);