diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPIInvocationWithTracingTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPIInvocationWithTracingTestCase.java index 3f84de3b67..50871d351b 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPIInvocationWithTracingTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPIInvocationWithTracingTestCase.java @@ -219,8 +219,8 @@ public void testWebSocketAPIInvocation() throws Exception { consumerSecret = applicationKeyDTO.getConsumerSecret(); WebSocketClient client = new WebSocketClient(); try { - invokeAPI(client, tokenJti, WebSocketAPITestCase.AUTH_IN.HEADER, null, apiEndPoint); - invokeAPI(client, tokenJti, WebSocketAPITestCase.AUTH_IN.QUERY, null, apiEndPoint); + invokeAPI(client, tokenJti, WebSocketAPITestCase.AUTH_IN.OAUTH_HEADER, null, apiEndPoint); + invokeAPI(client, tokenJti, WebSocketAPITestCase.AUTH_IN.OAUTH_QUERY, null, apiEndPoint); } catch (Exception e) { log.error("Exception in connecting to server", e); Assert.fail("Client cannot connect to server"); @@ -278,10 +278,10 @@ private void invokeAPI(WebSocketClient client, String accessToken, WebSocketAPIT ClientUpgradeRequest request = new ClientUpgradeRequest(); URI echoUri = null; - if (WebSocketAPITestCase.AUTH_IN.HEADER == in) { + if (WebSocketAPITestCase.AUTH_IN.OAUTH_HEADER == in) { request.setHeader("Authorization", "Bearer " + accessToken); echoUri = new URI(apiEndPoint); - } else if (WebSocketAPITestCase.AUTH_IN.QUERY == in) { + } else if (WebSocketAPITestCase.AUTH_IN.OAUTH_QUERY == in) { echoUri = new URI(apiEndPoint + "?access_token=" + accessToken); } diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPITestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPITestCase.java index aa2405017b..12f331af56 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPITestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPITestCase.java @@ -22,7 +22,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import io.netty.handler.codec.http.DefaultHttpHeaders; -import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -48,6 +47,7 @@ import org.wso2.am.integration.clients.publisher.api.v1.dto.APIListDTO; import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationDTO; import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationKeyDTO; +import org.wso2.am.integration.clients.store.api.v1.dto.APIKeyDTO; import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationKeyGenerateRequestDTO; import org.wso2.am.integration.clients.store.api.v1.dto.SubscriptionDTO; import org.wso2.am.integration.test.impl.DtoFactory; @@ -64,7 +64,6 @@ import org.wso2.carbon.apimgt.api.model.APIIdentifier; import org.wso2.carbon.automation.engine.annotations.ExecutionEnvironment; import org.wso2.carbon.automation.engine.annotations.SetEnvironment; -import org.wso2.carbon.automation.engine.context.AutomationContext; import org.wso2.carbon.automation.engine.context.TestUserMode; import org.wso2.carbon.automation.engine.frameworkutils.FrameworkPathUtil; import org.wso2.carbon.automation.test.utils.common.TestConfigurationProvider; @@ -75,15 +74,12 @@ import javax.ws.rs.core.Response; import java.io.File; import java.io.FileInputStream; -import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; -import java.net.Socket; import java.net.URI; import java.net.URL; import java.time.LocalDateTime; import java.util.ArrayList; -import java.util.Calendar; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -98,8 +94,10 @@ public class WebSocketAPITestCase extends APIMIntegrationBaseTest { private final Log log = LogFactory.getLog(WebSocketAPITestCase.class); enum AUTH_IN { - HEADER, - QUERY + OAUTH_HEADER, + OAUTH_QUERY, + APIKEY_HEADER, + APIKEY_QUERY } private final String apiName = "WebSocketAPI"; private final String apiNameWithMalformedContext = "WebSocketAPIWithMalformedContext"; @@ -132,6 +130,8 @@ enum AUTH_IN { long throttleMarkTime = 0; String apiVersion2 = "2.0.0"; String endPointApplication = "EndPointApplication"; + ArrayList securityScheme = new ArrayList<>(); + String apiKey = "api_key"; Server server = null; @Factory(dataProvider = "userModeDataProvider") @@ -231,13 +231,15 @@ public void testWebSocketAPIInvocation() throws Exception { applicationKeyDTO = restAPIStore.generateKeys(appId, "3600", null, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, null, grantTypes); String accessToken = applicationKeyDTO.getToken().getAccessToken(); - String tokenJti = TokenUtils.getJtiOfJwtToken(accessToken); + String opaqueToken = TokenUtils.getJtiOfJwtToken(accessToken); consumerKey = applicationKeyDTO.getConsumerKey(); consumerSecret = applicationKeyDTO.getConsumerSecret(); WebSocketClient client = new WebSocketClient(); try { - invokeAPI(client, tokenJti, AUTH_IN.HEADER, null, apiEndPoint); - invokeAPI(client, tokenJti, AUTH_IN.QUERY, null, apiEndPoint); + invokeAPI(client, accessToken, AUTH_IN.OAUTH_HEADER, null, apiEndPoint); + invokeAPI(client, accessToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint); + invokeAPI(client, opaqueToken, AUTH_IN.OAUTH_HEADER, null, apiEndPoint); + invokeAPI(client, opaqueToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint); } catch (Exception e) { log.error("Exception in connecting to server", e); Assert.fail("Client cannot connect to server"); @@ -268,8 +270,8 @@ public void testWebSocketAPIInvocationWithJWTToken() throws Exception { //consumerSecret = applicationKeyDTO.getConsumerSecret(); WebSocketClient client = new WebSocketClient(); try { - invokeAPI(client, accessToken, AUTH_IN.HEADER, null, apiEndPoint); - invokeAPI(client, accessToken, AUTH_IN.QUERY, null, apiEndPoint); + invokeAPI(client, accessToken, AUTH_IN.OAUTH_HEADER, null, apiEndPoint); + invokeAPI(client, accessToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint); } catch (Exception e) { log.error("Exception in connecting to server", e); Assert.fail("Client cannot connect to server"); @@ -334,8 +336,8 @@ public void testWebSocketAPIRemoveEndpoint() throws Exception { WebSocketClient client0 = new WebSocketClient(); try { - invokeAPI(client0, sandboxAccessToken, AUTH_IN.HEADER, null, apiEndPoint); - invokeAPI(client0, sandboxAccessToken, AUTH_IN.QUERY, null, apiEndPoint); + invokeAPI(client0, sandboxAccessToken, AUTH_IN.OAUTH_HEADER, null, apiEndPoint); + invokeAPI(client0, sandboxAccessToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint); Assert.assertTrue(true, "Client can connect to the sandbox endpoint"); } catch (Exception e) { log.error("Exception in connecting to server", e); @@ -350,7 +352,7 @@ public void testWebSocketAPIRemoveEndpoint() throws Exception { String prodAccessToken = prodApplicationKeyDTO.getToken().getAccessToken(); WebSocketClient client1 = new WebSocketClient(); try { - invokeAPI(client1, prodAccessToken, AUTH_IN.QUERY, null, apiEndPoint); + invokeAPI(client1, prodAccessToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint); Assert.fail("Client can connect to the production endpoint when production endpoint is not configured"); } catch (Exception e) { log.debug("Exception in connecting to server", e); @@ -453,7 +455,8 @@ public void testWebSocketAPIInvalidTokenInvocation() throws Exception { WebSocketClient client = new WebSocketClient(); boolean apiInvocationFailed = false; try { - invokeAPI(client, "00000000-0000-0000-0000-000000000000", AUTH_IN.HEADER, null, apiEndPoint); + invokeAPI(client, "00000000-0000-0000-0000-000000000000", AUTH_IN.OAUTH_HEADER, + null, apiEndPoint); } catch (APIManagerIntegrationTestException e) { log.error("Exception in connecting to server", e); apiInvocationFailed = true; @@ -469,6 +472,201 @@ public void testWebSocketAPIInvalidTokenInvocation() throws Exception { } } + @Test(description = "Invoke API using API key when API Key authentication is not enabled", + dependsOnMethods = "testWebSocketAPIInvalidTokenInvocation") + public void testWebSocketAPIInvocationUsingAPIKeyWhenAPIKeyAuthenticationDisabled() throws Exception { + + APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum. + PRODUCTION.toString(), -1, null, null); + String accessToken = apiKeyDTO.getApikey(); + WebSocketClient client = new WebSocketClient(); + boolean apiInvocationFailed = false; + try { + invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint); + } catch (APIManagerIntegrationTestException e) { + apiInvocationFailed = true; + assertTrue(true, "Exception in connecting to server because API Key authentication is not enabled"); + } catch (Exception e) { + log.error("Exception in connecting to server", e); + Assert.fail("Client cannot connect to server"); + } finally { + if (!apiInvocationFailed) { + Assert.fail("WS API was invoked using API key when API Key authentication is not enabled"); + } + client.stop(); + } + } + + @Test(description = "Invoke API using API key", + dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKeyWhenAPIKeyAuthenticationDisabled") + public void testWebSocketAPIInvocationUsingAPIKey() throws Exception { + + // Update API to enable API Key authentication + HttpResponse response = restAPIPublisher.getAPI(websocketAPIID); + Gson g = new Gson(); + APIDTO apidto = g.fromJson(response.getData(), APIDTO.class); + securityScheme.add(apiKey); + apidto.setSecurityScheme(securityScheme); + restAPIPublisher.updateAPI(apidto); + Thread.sleep(1000); // Delay is needed to propagate changes to the components + APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum. + PRODUCTION.toString(), -1, null, null); + String accessToken = apiKeyDTO.getApikey(); + WebSocketClient client = new WebSocketClient(); + try { + invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint); + invokeAPI(client, accessToken, AUTH_IN.APIKEY_QUERY, null, apiEndPoint); + } catch (Exception e) { + log.error("Exception in connecting to server", e); + Assert.fail("Client cannot connect to server"); + } finally { + client.stop(); + } + } + + @Test(description = "Invoke API using OAuth access token when OAuth authentication is not enabled", + dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKey") + public void testWebSocketAPIInvocationUsingOAuthWhenOAuthAuthenticationDisabled() throws Exception { + + WebSocketClient client = new WebSocketClient(); + boolean apiInvocationFailed = false; + try { + invokeAPI(client, applicationKeyDTO.getToken().getAccessToken(), AUTH_IN.OAUTH_HEADER, + null, apiEndPoint); + } catch (APIManagerIntegrationTestException e) { + apiInvocationFailed = true; + assertTrue(true, "Exception in connecting to server because OAuth authentication is not enabled"); + } catch (Exception e) { + log.error("Exception in connecting to server", e); + Assert.fail("Client cannot connect to server"); + } finally { + if (!apiInvocationFailed) { + Assert.fail("WS API was invoked using OAuth access token when OAuth authentication is not enabled"); + } + client.stop(); + } + } + + @Test(description = "Invoke API using Expired API key", + dependsOnMethods = "testWebSocketAPIInvocationUsingOAuthWhenOAuthAuthenticationDisabled") + public void testWebSocketAPIInvocationUsingExpiredAPIKey() throws Exception { + + APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum. + PRODUCTION.toString(), 1, null, null); + String accessToken = apiKeyDTO.getApikey(); + WebSocketClient client = new WebSocketClient(); + boolean apiInvocationFailed = false; + try { + Thread.sleep(2000); + invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint); + } catch (APIManagerIntegrationTestException e) { + apiInvocationFailed = true; + assertTrue(true, "Exception in connecting to server because the API Key is expired"); + } catch (Exception e) { + log.error("Exception in connecting to server", e); + Assert.fail("Client cannot connect to server"); + } finally { + if (!apiInvocationFailed) { + Assert.fail("WS API was invoked with an expired API key"); + } + client.stop(); + } + } + + @Test(description = "Invoke API using API key generated using IP restrictions", + dependsOnMethods = "testWebSocketAPIInvocationUsingExpiredAPIKey") + public void testWebSocketAPIInvocationUsingAPIKeyGeneratedUsingIPRestrictions() throws Exception { + + APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum. + PRODUCTION.toString(), -1, "192.168.1.2, 152.12.0.0/13, 2002:eb8::2, 1001:ab8::/44," + + " 127.0.0.1", null); + String accessToken = apiKeyDTO.getApikey(); + WebSocketClient client = new WebSocketClient(); + try { + invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint); + } catch (Exception e) { + log.error("Exception in connecting to server", e); + Assert.fail("Client cannot connect to server"); + } finally { + client.stop(); + } + } + + @Test(description = "Invoke API using an API key restricted for another IP", + dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKeyGeneratedUsingIPRestrictions") + public void testWebSocketAPIInvocationUsingAPIKeyRestrictedForAnotherIP() throws Exception { + + APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum. + PRODUCTION.toString(), -1, "192.168.1.2, 152.12.0.0/13, 2002:eb8::2, 1001:ab8::/44," + + " 1.1.1.1", null); + String accessToken = apiKeyDTO.getApikey(); + WebSocketClient client = new WebSocketClient(); + boolean apiInvocationFailed = false; + try { + invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint); + } catch (APIManagerIntegrationTestException e) { + apiInvocationFailed = true; + assertTrue(true, "Client cannot connect to server because the API Key is restricted for another IP"); + } catch (Exception e) { + log.error("Exception in connecting to server", e); + Assert.fail("Client cannot connect to server"); + } finally { + if (!apiInvocationFailed) { + Assert.fail("WS API was invoked using API key restricted for another IP"); + } + client.stop(); + } + } + + @Test(description = "Invoke API using API key generated using Referer restrictions", + dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKeyRestrictedForAnotherIP") + public void testWebSocketAPIInvocationUsingAPIKeyGeneratedUsingRefererRestrictions() throws Exception { + + APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum. + PRODUCTION.toString(), -1, null, "www.example.com/path, " + + "sub.example.com/*, *.example.com/*, www.wso2.com"); + HttpHeaders headers = new DefaultHttpHeaders(); + headers.add("Referer", "www.wso2.com"); + String accessToken = apiKeyDTO.getApikey(); + WebSocketClient client = new WebSocketClient(); + try { + invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, headers, apiEndPoint); + } catch (Exception e) { + log.error("Exception in connecting to server", e); + Assert.fail("Client cannot connect to server"); + } finally { + client.stop(); + } + } + + @Test(description = "Invoke API using API key restricted for another Referer", + dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKeyGeneratedUsingRefererRestrictions") + public void testWebSocketAPIInvocationUsingAPIKeyGeneratedForAnotherReferer() throws Exception { + + APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum. + PRODUCTION.toString(), -1, null, "www.example.com/path, " + + "sub.example.com/*, *.example.com/*, www.wso2.com"); + HttpHeaders headers = new DefaultHttpHeaders(); + headers.add("Referer", "www.wso2.org"); + String accessToken = apiKeyDTO.getApikey(); + WebSocketClient client = new WebSocketClient(); + boolean apiInvocationFailed = false; + try { + invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint); + } catch (APIManagerIntegrationTestException e) { + apiInvocationFailed = true; + assertTrue(true, "Client cannot connect to server because the API Key is restricted for another Referer"); + } catch (Exception e) { + log.error("Exception in connecting to server", e); + Assert.fail("Client cannot connect to server"); + } finally { + if (!apiInvocationFailed) { + Assert.fail("WS API was invoked using API key generated for another Referer"); + } + client.stop(); + } + } + @Test(description = "Create WebSocket API with malformed context", dependsOnMethods = "testWebSocketAPIRemoveEndpoint") public void testCreateWebSocketAPIWithMalformedContext() throws Exception { @@ -603,11 +801,16 @@ private void invokeAPI(WebSocketClient client, String accessToken, AUTH_IN in, H ClientUpgradeRequest request = new ClientUpgradeRequest(); URI echoUri = null; - if (AUTH_IN.HEADER == in) { + if (AUTH_IN.OAUTH_HEADER == in) { request.setHeader("Authorization", "Bearer " + accessToken); echoUri = new URI(apiEndPoint); - } else if (AUTH_IN.QUERY == in) { + } else if (AUTH_IN.OAUTH_QUERY == in) { echoUri = new URI(apiEndPoint + "?access_token=" + accessToken); + } else if (AUTH_IN.APIKEY_HEADER == in) { + request.setHeader("apikey", accessToken); + echoUri = new URI(apiEndPoint); + } else if (AUTH_IN.APIKEY_QUERY == in) { + echoUri = new URI(apiEndPoint + "?apikey=" + accessToken); } if (optionalRequestHeaders != null) {