diff --git a/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/AllowedScopesTestCase.java b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/AllowedScopesTestCase.java index 96a08a3caa..dd1cca350e 100644 --- a/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/AllowedScopesTestCase.java +++ b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/AllowedScopesTestCase.java @@ -18,7 +18,9 @@ package org.wso2.am.integration.tests.other; import com.google.gson.Gson; +import org.apache.axis2.AxisFault; import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.json.JSONException; import org.json.JSONObject; @@ -30,6 +32,7 @@ import org.wso2.am.integration.clients.publisher.api.v1.dto.ScopeDTO; import org.wso2.am.integration.clients.store.api.ApiException; import org.wso2.am.integration.clients.store.api.v1.dto.*; +import org.wso2.am.integration.test.Constants; import org.wso2.am.integration.test.impl.RestAPIPublisherImpl; import org.wso2.am.integration.test.impl.RestAPIStoreImpl; import org.wso2.am.integration.test.utils.APIManagerIntegrationTestException; @@ -43,9 +46,12 @@ import org.wso2.carbon.automation.test.utils.http.client.HttpResponse; import org.wso2.carbon.integration.common.admin.client.UserManagementClient; import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import javax.xml.xpath.XPathExpressionException; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.net.URL; import java.util.ArrayList; @@ -60,9 +66,17 @@ public class AllowedScopesTestCase extends APIManagerLifecycleBaseTest { private String apiEndPointUrl; private final String API_END_POINT_POSTFIX_URL = "jaxrs_basic/services/customers/customerservice/"; private final String ALLOWED_SCOPES_API = "allowedScopesAPI"; + private final String EXAMPLE_API_CONTEXT = "exampleapi"; private String apiId; + private String apiImportId; private String applicationId; + private String applicationImportId; private final String API_END_POINT_METHOD = "/customers/123"; + private final String PRODUCTS_CATALOG_1_METHOD = "/products/catalog/1"; + private final String PRODUCTS_POPULAR_METHOD = "/products/popular"; + private final String PRODUCTS_WILDCARD = "/products/noexactmatch"; + private final String ORDERS = "/orders"; + private final String WILDCARD = "/noexactmatch"; @Factory(dataProvider = "userModeDataProvider") public AllowedScopesTestCase(TestUserMode userMode) { @@ -149,6 +163,8 @@ public void setEnvironment() throws Exception { APIMIntegrationConstants.IS_API_NOT_EXISTS); waitForAPIDeploymentSync(apiRequest.getProvider(), apiRequest.getName(), apiRequest.getVersion(), APIMIntegrationConstants.IS_API_EXISTS); + + importApiDefinitionAndDeploy(); } @Test(description = "Generate access token for white listed scopes and invoke APIs") @@ -268,11 +284,199 @@ public void testGenerateAccessTokenWithWhiteListedScopes() throws Exception { assertEquals(apiResponse5.getResponseCode(), HttpStatus.SC_FORBIDDEN); } + @Test(description = "Generate access token for white listed scopes and invoke APIs") + public void testGenerateAccessTokenAndInvokeExampleAPIForScopesValidation() throws Exception { + // Create application + HttpResponse applicationResponse = restAPIStore.createApplication("TestAppScopeExampleAPI", + "Test Application", APIMIntegrationConstants.APPLICATION_TIER.UNLIMITED, + ApplicationDTO.TokenTypeEnum.JWT); + applicationImportId = applicationResponse.getData(); + + // Subscribe to API + HttpResponse subscribeResponse = subscribeToAPIUsingRest(apiImportId, applicationImportId, + APIMIntegrationConstants.API_TIER.UNLIMITED, restAPIStore); + assertEquals(subscribeResponse.getResponseCode(), HTTP_RESPONSE_CODE_OK, + "Subscribe of import API version request not successful " + + " API Name: ExampleAPI API Version: 1_0_0 API Provider Name :" + user.getUserName()); + + // Generate Keys + ApplicationKeyDTO applicationKeyDTO = generateKeysForApplication(applicationImportId); + + // Get Consumer Key and Consumer Secret + String consumerKey = applicationKeyDTO.getConsumerKey(); + String consumerSecret = applicationKeyDTO.getConsumerSecret(); + + // Generate token for Scope A + Map requestHeadersWithScopeA = generateAccessTokenHeaderForScope( + "ScopeA", consumerKey, consumerSecret); + + // Invoke API using token of Scope A + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeA, + HttpStatus.SC_OK); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeA, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeA, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeA, HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeA, HttpStatus.SC_FORBIDDEN); + + // Generate token for Scope B + Map requestHeadersWithScopeB = generateAccessTokenHeaderForScope( + "ScopeB", consumerKey, consumerSecret); + + // Invoke API using token of Scope B + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeB, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeB, + HttpStatus.SC_OK); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeB, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeB, HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeB, HttpStatus.SC_FORBIDDEN); + + // Generate token for Scope C + Map requestHeadersWithScopeC = generateAccessTokenHeaderForScope( + "ScopeC", consumerKey, consumerSecret); + + // Invoke API using token of Scope C + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeC, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeC, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeC, + HttpStatus.SC_OK); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeC, HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeC, HttpStatus.SC_FORBIDDEN); + + // Generate token for Scope D + Map requestHeadersWithScopeD = generateAccessTokenHeaderForScope( + "ScopeD", consumerKey, consumerSecret); + + // Invoke API using token of Scope D + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeD, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeD, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeD, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeD, HttpStatus.SC_OK); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeD, HttpStatus.SC_FORBIDDEN); + + // Generate token for Scope E + Map requestHeadersWithScopeE = generateAccessTokenHeaderForScope( + "ScopeE", consumerKey, consumerSecret); + + // Invoke API using token of Scope E + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeE, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeE, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeE, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeE, HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeE, HttpStatus.SC_OK); + } + @AfterClass(alwaysRun = true) public void destroy() throws Exception { restAPIStore.deleteApplication(applicationId); + restAPIStore.deleteApplication(applicationImportId); restAPIPublisher.deleteAPI(apiId); + restAPIPublisher.deleteAPI(apiImportId); serverConfigurationManager.restoreToLastConfiguration(); } + private void importApiDefinitionAndDeploy() throws Exception { + String context = determineApiContext(); + String additionalProperties = loadApiAdditionalProperties(context); + + File definitionFile = getTempFileWithContent(loadApiDefinition()); + APIDTO apidtoOAS = restAPIPublisher.importOASDefinition(definitionFile, additionalProperties); + apiImportId = apidtoOAS.getId(); + + createAPIRevisionAndDeployUsingRest(apiImportId, restAPIPublisher); + restAPIPublisher.changeAPILifeCycleStatusToPublish(apiImportId, false); + waitForAPIDeploymentSync(apidtoOAS.getProvider(), apidtoOAS.getName(), apidtoOAS.getVersion(), + APIMIntegrationConstants.IS_API_NOT_EXISTS); + waitForAPIDeploymentSync(apidtoOAS.getProvider(), apidtoOAS.getName(), apidtoOAS.getVersion(), + APIMIntegrationConstants.IS_API_EXISTS); + } + + private String determineApiContext() { + String context = EXAMPLE_API_CONTEXT; + if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(user.getUserDomain())) { + context = "/t/" + user.getUserDomain() + context; + } + return context; + } + + private String loadApiAdditionalProperties(String context) throws IOException, JSONException { + + String resourcePath = "oas/v3/scope-validation"; + String additionalPropertiesJson = + IOUtils.toString(getClass().getClassLoader().getResourceAsStream(resourcePath + + "/additionalProperties.json"), "UTF-8"); + JSONObject additionalPropertiesObj = new JSONObject(additionalPropertiesJson); + additionalPropertiesObj.put("provider", user.getUserName()); + additionalPropertiesObj.put("context", context); + return additionalPropertiesObj.toString(); + } + + private String loadApiDefinition() throws IOException { + + String resourcePath = "oas/v3/scope-validation"; + return IOUtils.toString(getClass().getClassLoader() + .getResourceAsStream(resourcePath + "/oas_import.json"), "UTF-8"); + } + + private ApplicationKeyDTO generateKeysForApplication(String appId) throws Exception { + ArrayList grantTypes = new ArrayList<>(); + grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.PASSWORD); + grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.CLIENT_CREDENTIAL); + return restAPIStore.generateKeys(appId, "36000", "", + ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, null, grantTypes); + } + + public Map generateAccessTokenHeaderForScope(String scopeName, String consumerKey, String consumerSecret) + throws Exception { + URL tokenEndpointURL = new URL(keyManagerHTTPSURL + "oauth2/token"); + String requestBody = "grant_type=password&username=" + user.getUserName() + + "&password=" + user.getPassword() + "&scope=" + scopeName; + JSONObject accessTokenGenerationResponse = new JSONObject(restAPIStore.generateUserAccessKey( + consumerKey, consumerSecret, requestBody, tokenEndpointURL).getData()); + + // Validate access token + Assert.assertNotNull(accessTokenGenerationResponse); + Assert.assertTrue(accessTokenGenerationResponse.getString("scope").contains(scopeName)); + Assert.assertTrue(accessTokenGenerationResponse.getString("expires_in").equals("3600")); + + String accessTokenWithScope = accessTokenGenerationResponse.getString("access_token"); + + Map requestHeadersWithScope = new HashMap(); + requestHeadersWithScope.put("Authorization", "Bearer " + accessTokenWithScope); + requestHeadersWithScope.put("accept", "*/*"); + return requestHeadersWithScope; + } + + public void invokeAPI(String apiContext, String apiVersion, String method, + Map requestHeaders, int expectedResponseCode) throws Exception { + // Invoke API + HttpResponse apiResponse = HttpRequestUtil.doGet( + getAPIInvocationURLHttps(apiContext, apiVersion) + method, requestHeaders); + + // Validate response + assertEquals(apiResponse.getResponseCode(), expectedResponseCode, + "API invocation failed for " + method + " with expected status code " + expectedResponseCode); + + } + + private File getTempFileWithContent(String swagger) throws Exception { + + File temp = File.createTempFile("swagger", ".json"); + temp.deleteOnExit(); + BufferedWriter out = new BufferedWriter(new FileWriter(temp)); + out.write(swagger); + out.close(); + return temp; + } } diff --git a/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/AllowedScopesTestWithCorsDisabled.java b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/AllowedScopesTestWithCorsDisabled.java new file mode 100644 index 0000000000..0b004e54f4 --- /dev/null +++ b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/other/AllowedScopesTestWithCorsDisabled.java @@ -0,0 +1,291 @@ +/* + *Copyright (c) 2024, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + *WSO2 Inc. 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.am.integration.tests.other; + +import org.apache.axis2.AxisFault; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.io.IOUtils; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Assert; +import org.testng.annotations.*; +import org.wso2.am.integration.clients.publisher.api.v1.dto.APIDTO; +import org.wso2.am.integration.clients.store.api.v1.dto.*; +import org.wso2.am.integration.test.utils.base.APIMIntegrationConstants; +import org.wso2.am.integration.tests.api.lifecycle.APIManagerLifecycleBaseTest; +import org.wso2.carbon.automation.engine.context.TestUserMode; +import org.wso2.carbon.automation.test.utils.http.client.HttpRequestUtil; +import org.wso2.carbon.automation.test.utils.http.client.HttpResponse; +import org.wso2.carbon.integration.common.admin.client.UserManagementClient; +import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.xpath.XPathExpressionException; + +import static org.testng.Assert.assertEquals; + +public class AllowedScopesTestWithCorsDisabled extends APIManagerLifecycleBaseTest { + private static final String EXAMPLE_API_CONTEXT = "exampleapi"; + private static final String PRODUCTS_CATALOG_1_METHOD = "/products/catalog/1"; + private static final String PRODUCTS_POPULAR_METHOD = "/products/popular"; + private static final String PRODUCTS_WILDCARD = "/products/noexactmatch"; + private static final String ORDERS = "/orders"; + private static final String WILDCARD = "/noexactmatch"; + + private ServerConfigurationManager serverConfigurationManager; + private String apiImportId; + private String applicationImportId; + + @Factory(dataProvider = "userModeDataProvider") + public AllowedScopesTestWithCorsDisabled(TestUserMode userMode) { + this.userMode = userMode; + } + + @DataProvider + public static Object[][] userModeDataProvider() { + + return new Object[][]{ + new Object[]{TestUserMode.SUPER_TENANT_ADMIN}, + }; + } + + @BeforeClass(alwaysRun = true) + public void setUp() throws Exception { + super.init(userMode); + initializeServerConfiguration(); + initializeUserManagementClient(); + importApiDefinitionAndDeploy(); + } + + @Test(description = "Generate access token for white listed scopes and invoke APIs") + public void testGenerateAccessTokenAndInvokeExampleAPIForScopesValidation() throws Exception { + // Create application + HttpResponse applicationResponse = restAPIStore.createApplication("TestAppScopeExampleAPI", + "Test Application", APIMIntegrationConstants.APPLICATION_TIER.UNLIMITED, + ApplicationDTO.TokenTypeEnum.JWT); + applicationImportId = applicationResponse.getData(); + + // Subscribe to API + HttpResponse subscribeResponse = subscribeToAPIUsingRest(apiImportId, applicationImportId, + APIMIntegrationConstants.API_TIER.UNLIMITED, restAPIStore); + assertEquals(subscribeResponse.getResponseCode(), HTTP_RESPONSE_CODE_OK, + "Subscribe of import API version request not successful " + + " API Name: ExampleAPI API Version: 1_0_0 API Provider Name :" + user.getUserName()); + + // Generate Keys + ApplicationKeyDTO applicationKeyDTO = generateKeysForApplication(applicationImportId); + + // Get Consumer Key and Consumer Secret + String consumerKey = applicationKeyDTO.getConsumerKey(); + String consumerSecret = applicationKeyDTO.getConsumerSecret(); + + // Generate token for Scope A + Map requestHeadersWithScopeA = generateAccessTokenHeaderForScope( + "ScopeA", consumerKey, consumerSecret); + + // Invoke API using token of Scope A + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeA, + HttpStatus.SC_OK); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeA, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeA, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeA, HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeA, HttpStatus.SC_FORBIDDEN); + + // Generate token for Scope B + Map requestHeadersWithScopeB = generateAccessTokenHeaderForScope( + "ScopeB", consumerKey, consumerSecret); + + // Invoke API using token of Scope B + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeB, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeB, + HttpStatus.SC_OK); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeB, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeB, HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeB, HttpStatus.SC_FORBIDDEN); + + // Generate token for Scope C + Map requestHeadersWithScopeC = generateAccessTokenHeaderForScope( + "ScopeC", consumerKey, consumerSecret); + + // Invoke API using token of Scope C + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeC, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeC, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeC, + HttpStatus.SC_OK); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeC, HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeC, HttpStatus.SC_FORBIDDEN); + + // Generate token for Scope D + Map requestHeadersWithScopeD = generateAccessTokenHeaderForScope( + "ScopeD", consumerKey, consumerSecret); + + // Invoke API using token of Scope D + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeD, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeD, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeD, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeD, HttpStatus.SC_OK); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeD, HttpStatus.SC_FORBIDDEN); + + // Generate token for Scope E + Map requestHeadersWithScopeE = generateAccessTokenHeaderForScope( + "ScopeE", consumerKey, consumerSecret); + + // Invoke API using token of Scope E + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_CATALOG_1_METHOD, requestHeadersWithScopeE, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_POPULAR_METHOD, requestHeadersWithScopeE, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, PRODUCTS_WILDCARD, requestHeadersWithScopeE, + HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, ORDERS, requestHeadersWithScopeE, HttpStatus.SC_FORBIDDEN); + invokeAPI(EXAMPLE_API_CONTEXT, API_VERSION_1_0_0, WILDCARD, requestHeadersWithScopeE, HttpStatus.SC_OK); + } + + @AfterClass(alwaysRun = true) + public void destroy() throws Exception { + restAPIStore.deleteApplication(applicationImportId); + restAPIPublisher.deleteAPI(apiImportId); + serverConfigurationManager.restoreToLastConfiguration(); + super.cleanUp(); + } + + private void initializeServerConfiguration() throws Exception { + serverConfigurationManager = new ServerConfigurationManager(gatewayContextWrk); + File configFile = new File(getAMResourceLocation() + + "/configFiles/allowedScopesWithCorsDisabled/deployment.toml"); + serverConfigurationManager.applyConfiguration(configFile); + } + + private void initializeUserManagementClient() throws AxisFault, XPathExpressionException { + String backEndUrl = keyManagerContext.getContextUrls().getBackEndUrl(); + String username = keyManagerContext.getContextTenant().getTenantAdmin().getUserName(); + String password = keyManagerContext.getContextTenant().getTenantAdmin().getPassword(); + userManagementClient = new UserManagementClient(backEndUrl, username, password); + } + + private void importApiDefinitionAndDeploy() throws Exception { + String context = determineApiContext(); + String additionalProperties = loadApiAdditionalProperties(context); + + File definitionFile = getTempFileWithContent(loadApiDefinition()); + APIDTO apidtoOAS = restAPIPublisher.importOASDefinition(definitionFile, additionalProperties); + apiImportId = apidtoOAS.getId(); + + createAPIRevisionAndDeployUsingRest(apiImportId, restAPIPublisher); + restAPIPublisher.changeAPILifeCycleStatusToPublish(apiImportId, false); + waitForAPIDeploymentSync(apidtoOAS.getProvider(), apidtoOAS.getName(), apidtoOAS.getVersion(), + APIMIntegrationConstants.IS_API_NOT_EXISTS); + waitForAPIDeploymentSync(apidtoOAS.getProvider(), apidtoOAS.getName(), apidtoOAS.getVersion(), + APIMIntegrationConstants.IS_API_EXISTS); + } + + private String determineApiContext() { + String context = EXAMPLE_API_CONTEXT; + if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(user.getUserDomain())) { + context = "/t/" + user.getUserDomain() + context; + } + return context; + } + + private String loadApiAdditionalProperties(String context) throws IOException, JSONException { + + String resourcePath = "oas/v3/scope-validation"; + String additionalPropertiesJson = + IOUtils.toString(getClass().getClassLoader().getResourceAsStream(resourcePath + + "/additionalProperties.json"), "UTF-8"); + JSONObject additionalPropertiesObj = new JSONObject(additionalPropertiesJson); + additionalPropertiesObj.put("provider", user.getUserName()); + additionalPropertiesObj.put("context", context); + return additionalPropertiesObj.toString(); + } + + private String loadApiDefinition() throws IOException { + + String resourcePath = "oas/v3/scope-validation"; + return IOUtils.toString(getClass().getClassLoader() + .getResourceAsStream(resourcePath + "/oas_import.json"), "UTF-8"); + } + + private ApplicationKeyDTO generateKeysForApplication(String appId) throws Exception { + ArrayList grantTypes = new ArrayList<>(); + grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.PASSWORD); + grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.CLIENT_CREDENTIAL); + return restAPIStore.generateKeys(appId, "36000", "", + ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, null, grantTypes); + } + + public Map generateAccessTokenHeaderForScope(String scopeName, String consumerKey, String consumerSecret) + throws Exception { + URL tokenEndpointURL = new URL(keyManagerHTTPSURL + "oauth2/token"); + String requestBody = "grant_type=password&username=" + user.getUserName() + + "&password=" + user.getPassword() + "&scope=" + scopeName; + JSONObject accessTokenGenerationResponse = new JSONObject(restAPIStore.generateUserAccessKey( + consumerKey, consumerSecret, requestBody, tokenEndpointURL).getData()); + + // Validate access token + Assert.assertNotNull(accessTokenGenerationResponse); + Assert.assertTrue(accessTokenGenerationResponse.getString("scope").contains(scopeName)); + Assert.assertTrue(accessTokenGenerationResponse.getString("expires_in").equals("3600")); + + String accessTokenWithScope = accessTokenGenerationResponse.getString("access_token"); + + Map requestHeadersWithScope = new HashMap(); + requestHeadersWithScope.put("Authorization", "Bearer " + accessTokenWithScope); + requestHeadersWithScope.put("accept", "*/*"); + return requestHeadersWithScope; + } + + public void invokeAPI(String apiContext, String apiVersion, String method, + Map requestHeaders, int expectedResponseCode) throws Exception { + // Invoke API + HttpResponse apiResponse = HttpRequestUtil.doGet( + getAPIInvocationURLHttps(apiContext, apiVersion) + method, requestHeaders); + + // Validate response + assertEquals(apiResponse.getResponseCode(), expectedResponseCode, + "API invocation failed for " + method + " with expected status code " + expectedResponseCode); + + } + + private File getTempFileWithContent(String swagger) throws Exception { + File temp = File.createTempFile("swagger", ".json"); + temp.deleteOnExit(); + BufferedWriter out = new BufferedWriter(new FileWriter(temp)); + out.write(swagger); + out.close(); + return temp; + } +} diff --git a/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPIScopeTestCase.java b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPIScopeTestCase.java new file mode 100644 index 0000000000..11c61cd906 --- /dev/null +++ b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/am/integration/tests/websocket/WebSocketAPIScopeTestCase.java @@ -0,0 +1,578 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.am.integration.tests.websocket; + +import com.google.gson.Gson; +import io.netty.handler.codec.http.HttpHeaders; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; +import org.eclipse.jetty.websocket.client.WebSocketClient; +import org.eclipse.jetty.websocket.server.WebSocketHandler; +import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; +import org.json.JSONObject; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import org.wso2.am.integration.clients.publisher.api.v1.dto.APIDTO; +import org.wso2.am.integration.clients.publisher.api.v1.dto.APIListDTO; +import org.wso2.am.integration.clients.publisher.api.v1.dto.APIOperationsDTO; +import org.wso2.am.integration.clients.publisher.api.v1.dto.APIScopeDTO; +import org.wso2.am.integration.clients.publisher.api.v1.dto.ScopeDTO; +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.ApplicationKeyGenerateRequestDTO; +import org.wso2.am.integration.clients.store.api.v1.dto.SubscriptionDTO; +import org.wso2.am.integration.test.utils.APIManagerIntegrationTestException; +import org.wso2.am.integration.test.utils.base.APIMIntegrationBaseTest; +import org.wso2.am.integration.test.utils.base.APIMIntegrationConstants; +import org.wso2.am.integration.test.utils.bean.APILifeCycleAction; +import org.wso2.am.integration.test.utils.bean.APIRequest; +import org.wso2.am.integration.test.utils.clients.APIPublisherRestClient; +import org.wso2.am.integration.test.utils.generic.APIMTestCaseUtils; +import org.wso2.am.integration.tests.websocket.client.WebSocketClientImpl; +import org.wso2.am.integration.tests.websocket.server.WebSocketServerImpl; +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.TestUserMode; +import org.wso2.carbon.automation.engine.frameworkutils.FrameworkPathUtil; +import org.wso2.carbon.automation.test.utils.common.TestConfigurationProvider; +import org.wso2.carbon.automation.test.utils.http.client.HttpResponse; +import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager; +import org.wso2.carbon.utils.xml.StringUtils; + +import java.io.File; +import java.net.InetAddress; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +@SetEnvironment(executionEnvironments = {ExecutionEnvironment.STANDALONE}) +public class WebSocketAPIScopeTestCase extends APIMIntegrationBaseTest { + + private final Log log = LogFactory.getLog(WebSocketAPIScopeTestCase.class); + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + private final String apiName = "WebSocketAPI"; + private final String applicationJWTName = "WebSocketJWTTypeApplication"; + private final String testMessage = "Web Socket Test Message"; + private final String PRODUCTS_CATALOG_1_METHOD = "/products/catalog/1"; + private final String PRODUCTS_POPULAR_METHOD = "/products/popular"; + private final String ORDERS = "/orders"; + private final String WILDCARD = "/noexactmatch"; + private String appJWTId; + private ApplicationKeyDTO applicationKeyDTO; + private String apiEndPoint; + private APIPublisherRestClient apiPublisher; + private String provider; + private String consumerKey; + private String consumerSecret; + private APIRequest apiRequest; + private int webSocketServerPort; + private String webSocketServerHost; + private ServerConfigurationManager serverConfigurationManager; + private String wsEventPublisherSource = TestConfigurationProvider.getResourceLocation() + File.separator + + "artifacts" + + File.separator + "AM" + File.separator + "configFiles" + File.separator + "webSocketTest" + + File.separator; + private String wsEventPublisherTarget = FrameworkPathUtil.getCarbonHome() + File.separator + "repository" + + File.separator + "deployment" + File.separator + "server" + File.separator + "eventpublishers" + + File.separator; + private String wsRequestEventPublisherSource = "WS_Req_Logger.xml"; + private String wsThrottleOutEventPublisherSource = "WS_Throttle_Out_Logger.xml"; + private String websocketAPIID; + private URL tokenEndpointURL; + @Factory(dataProvider = "userModeDataProvider") + public WebSocketAPIScopeTestCase(TestUserMode userMode) { + + this.userMode = userMode; + } + + @DataProvider + public static Object[][] userModeDataProvider() { + + // Removing Tenant_ADMIN due to https://github.com/wso2/product-apim/issues/10183 + return new Object[][]{ + new Object[]{TestUserMode.SUPER_TENANT_ADMIN}, + new Object[]{TestUserMode.TENANT_ADMIN} + }; + } + + @BeforeClass(alwaysRun = true) + public void setEnvironment() throws Exception { + + super.init(userMode); + serverConfigurationManager = new ServerConfigurationManager(gatewayContextWrk); + serverConfigurationManager.applyConfigurationWithoutRestart + (new File(wsEventPublisherSource + wsRequestEventPublisherSource), + new File(wsEventPublisherTarget + wsRequestEventPublisherSource), false); + serverConfigurationManager.applyConfigurationWithoutRestart + (new File(wsEventPublisherSource + wsThrottleOutEventPublisherSource), + new File(wsEventPublisherTarget + wsThrottleOutEventPublisherSource), false); + webSocketServerHost = InetAddress.getLocalHost().getHostName(); + int lowerPortLimit = 9950; + int upperPortLimit = 9999; + webSocketServerPort = getAvailablePort(lowerPortLimit, upperPortLimit); + if (webSocketServerPort == -1) { + throw new APIManagerIntegrationTestException("No available port in the range " + + lowerPortLimit + "-" + upperPortLimit + " was found"); + } + log.info("Selected port " + webSocketServerPort + " to start backend server"); + startWebSocketServer(webSocketServerPort); + } + + @Test(description = "Publish WebSocket API") + public void publishWebSocketAPI() throws Exception { + + provider = user.getUserName(); + String apiContext = "echo"; + String apiVersion = "1.0.0"; + + URI endpointUri = new URI("ws://" + webSocketServerHost + ":" + webSocketServerPort); + + //Create the api creation request object + apiRequest = new APIRequest(apiName, apiContext, endpointUri, endpointUri); + apiRequest.setVersion(apiVersion); + apiRequest.setTiersCollection(APIMIntegrationConstants.API_TIER.ASYNC_UNLIMITED); + apiRequest.setProvider(provider); + apiRequest.setType("WS"); + apiRequest.setApiTier(APIMIntegrationConstants.API_TIER.UNLIMITED); + HttpResponse addAPIResponse = restAPIPublisher.addAPI(apiRequest); + websocketAPIID = addAPIResponse.getData(); + HttpResponse createdApiResponse = restAPIPublisher.getAPI(websocketAPIID); + Gson g = new Gson(); + APIDTO apidto = g.fromJson(createdApiResponse.getData(), APIDTO.class); + + // Adding admin role + List role = new ArrayList(); + role.add("admin"); + //Adding Scope A + ScopeDTO scopeObjectA = new ScopeDTO(); + scopeObjectA.setName("ScopeA"); + scopeObjectA.setBindings(role); + APIScopeDTO apiScopeADTO = new APIScopeDTO(); + apiScopeADTO.setScope(scopeObjectA); + //Adding Scope B + ScopeDTO scopeObjectB = new ScopeDTO(); + scopeObjectB.setName("ScopeB"); + scopeObjectB.setBindings(role); + APIScopeDTO apiScopeBDTO = new APIScopeDTO(); + apiScopeBDTO.setScope(scopeObjectB); + //Adding Scope C + ScopeDTO scopeObjectC = new ScopeDTO(); + scopeObjectC.setName("ScopeC"); + scopeObjectC.setBindings(role); + APIScopeDTO apiScopeCDTO = new APIScopeDTO(); + apiScopeCDTO.setScope(scopeObjectC); + //Adding Scope D + ScopeDTO scopeObjectD = new ScopeDTO(); + scopeObjectD.setName("ScopeD"); + scopeObjectD.setBindings(role); + APIScopeDTO apiScopeDDTO = new APIScopeDTO(); + apiScopeDDTO.setScope(scopeObjectD); + // Adding scopes to API + List apiScopeList = new ArrayList(); + apiScopeList.add(apiScopeADTO); + apiScopeList.add(apiScopeBDTO); + apiScopeList.add(apiScopeCDTO); + apiScopeList.add(apiScopeDDTO); + apidto.setScopes(apiScopeList); + + // Adding Operation with scopes + List operations = new ArrayList<>(); + + // Add PRODUCTS_CATALOG_1_METHOD + List scopesA = new ArrayList<>(); + scopesA.add("ScopeA"); + APIOperationsDTO apiOperationsDTOA = new APIOperationsDTO(); + apiOperationsDTOA.setVerb("SUBSCRIBE"); + apiOperationsDTOA.setTarget("/products/catalog/{catalog-id}"); + apiOperationsDTOA.setAuthType("Application & Application User"); + apiOperationsDTOA.setThrottlingPolicy("Unlimited"); + apiOperationsDTOA.setScopes(scopesA); + operations.add(apiOperationsDTOA); + + // Add PRODUCTS_POPULAR_METHOD + List scopesB = new ArrayList<>(); + scopesB.add("ScopeB"); + APIOperationsDTO apiOperationsDTOB = new APIOperationsDTO(); + apiOperationsDTOB.setVerb("SUBSCRIBE"); + apiOperationsDTOB.setTarget("/products/popular"); + apiOperationsDTOB.setAuthType("Application & Application User"); + apiOperationsDTOB.setThrottlingPolicy("Unlimited"); + apiOperationsDTOB.setScopes(scopesB); + operations.add(apiOperationsDTOB); + + // Add ORDERS + List scopesC = new ArrayList<>(); + scopesC.add("ScopeC"); + APIOperationsDTO apiOperationsDTOC = new APIOperationsDTO(); + apiOperationsDTOC.setVerb("SUBSCRIBE"); + apiOperationsDTOC.setTarget("/orders"); + apiOperationsDTOC.setAuthType("Application & Application User"); + apiOperationsDTOC.setThrottlingPolicy("Unlimited"); + apiOperationsDTOC.setScopes(scopesC); + operations.add(apiOperationsDTOC); + + // Add ORDERS + List scopesD = new ArrayList<>(); + scopesD.add("ScopeD"); + APIOperationsDTO apiOperationsDTOD = new APIOperationsDTO(); + apiOperationsDTOD.setVerb("SUBSCRIBE"); + apiOperationsDTOD.setTarget("/*"); + apiOperationsDTOD.setAuthType("Application & Application User"); + apiOperationsDTOD.setThrottlingPolicy("Unlimited"); + apiOperationsDTOD.setScopes(scopesD); + operations.add(apiOperationsDTOD); + + apidto.operations(operations); + + // Update the API + restAPIPublisher.updateAPI(apidto); + + createAPIRevisionAndDeployUsingRest(websocketAPIID, restAPIPublisher); + restAPIPublisher + .changeAPILifeCycleStatus(websocketAPIID, APILifeCycleAction.PUBLISH.getAction(), null); + waitForAPIDeploymentSync(user.getUserName(), apiName, apiVersion, + APIMIntegrationConstants.IS_API_EXISTS); + + APIIdentifier apiIdentifierWebSocket = new APIIdentifier(provider, apiName, apiVersion); + + // replace port with inbound endpoint port + + if (TestUserMode.SUPER_TENANT_ADMIN.equals(userMode) || TestUserMode.SUPER_TENANT_USER.equals(userMode)) { + apiEndPoint = getWebSocketAPIInvocationURL(apiContext, apiVersion); + } else { + apiEndPoint = getWebSocketTenantAPIInvocationURL(apiContext, apiVersion, user.getUserDomain()); + } + log.info("API Endpoint URL" + apiEndPoint); + APIListDTO apiPublisherAllAPIs = restAPIPublisher.getAllAPIs(); + assertTrue(APIMTestCaseUtils.isAPIAvailable(apiIdentifierWebSocket, apiPublisherAllAPIs), + "Published API is visible in API Publisher."); + org.wso2.am.integration.clients.store.api.v1.dto.APIListDTO restAPIStoreAllAPIs; + if (TestUserMode.SUPER_TENANT_ADMIN == userMode) { + restAPIStoreAllAPIs = restAPIStore.getAllAPIs(); + } else { + restAPIStoreAllAPIs = restAPIStore.getAllAPIs(user.getUserDomain()); + } + assertTrue(APIMTestCaseUtils.isAPIAvailableInStore(apiIdentifierWebSocket, restAPIStoreAllAPIs), + "Published API is visible in API Store."); + } + + @Test(description = "Create JWT Type Application and subscribe", dependsOnMethods = "publishWebSocketAPI") + public void testWebSocketAPIJWTApplicationSubscription() throws Exception { + + HttpResponse applicationResponse = restAPIStore.createApplication(applicationJWTName, + "", APIMIntegrationConstants.API_TIER.UNLIMITED, ApplicationDTO.TokenTypeEnum.JWT); + appJWTId = applicationResponse.getData(); + SubscriptionDTO subscriptionDTO = restAPIStore.subscribeToAPI(websocketAPIID, appJWTId, + APIMIntegrationConstants.API_TIER.ASYNC_UNLIMITED); + //Validate Subscription of the API + Assert.assertEquals(subscriptionDTO.getStatus(), SubscriptionDTO.StatusEnum.UNBLOCKED); + } + + @Test(description = "Invoke API using token", dependsOnMethods = "testWebSocketAPIJWTApplicationSubscription") + public void testWebSocketAPIGenerateKeys() throws Exception { + + ArrayList grantTypes = new ArrayList(); + grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.PASSWORD); + grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.REFRESH_CODE); + grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.CLIENT_CREDENTIAL); + applicationKeyDTO = restAPIStore.generateKeys(appJWTId, "3600", null, + ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, null, grantTypes); + consumerKey = applicationKeyDTO.getConsumerKey(); + consumerSecret = applicationKeyDTO.getConsumerSecret(); + tokenEndpointURL = new URL(keyManagerHTTPSURL + "oauth2/token"); + } + + @Test(description = "Invoke API PRODUCTS_CATALOG_1_METHOD endpoint using token", dependsOnMethods = + "testWebSocketAPIGenerateKeys") + public void testWebSocketAPIInvocation_PRODUCTS_CATALOG_1_METHOD() throws Exception { + + String requestBodyForScope = + "grant_type=password&username=" + user.getUserName() + "&password=" + user.getPassword() + "&scope" + + "=ScopeA"; + JSONObject accessTokenGenerationResponseScope = new JSONObject( + restAPIStore.generateUserAccessKey(consumerKey, consumerSecret, requestBodyForScope, tokenEndpointURL) + .getData()); + // Validate access token + org.junit.Assert.assertNotNull(accessTokenGenerationResponseScope); + org.junit.Assert.assertTrue(accessTokenGenerationResponseScope.getString("scope").contains("ScopeA")); + org.junit.Assert.assertTrue(accessTokenGenerationResponseScope.getString("expires_in").equals("3600")); + String accessTokenScope = accessTokenGenerationResponseScope.getString("access_token"); + WebSocketClient client = new WebSocketClient(); + try { + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + PRODUCTS_CATALOG_1_METHOD, true); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + PRODUCTS_POPULAR_METHOD, false); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + ORDERS, false); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + WILDCARD, false); + } 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 PRODUCTS_POPULAR_METHOD endpoint using token", dependsOnMethods = + "testWebSocketAPIGenerateKeys") + public void testWebSocketAPIInvocation_PRODUCTS_POPULAR_METHOD() throws Exception { + + String requestBodyForScope = + "grant_type=password&username=" + user.getUserName() + "&password=" + user.getPassword() + "&scope" + + "=ScopeB"; + JSONObject accessTokenGenerationResponseScope = new JSONObject( + restAPIStore.generateUserAccessKey(consumerKey, consumerSecret, requestBodyForScope, tokenEndpointURL) + .getData()); + // Validate access token + org.junit.Assert.assertNotNull(accessTokenGenerationResponseScope); + org.junit.Assert.assertTrue(accessTokenGenerationResponseScope.getString("scope").contains("ScopeB")); + org.junit.Assert.assertTrue(accessTokenGenerationResponseScope.getString("expires_in").equals("3600")); + String accessTokenScope = accessTokenGenerationResponseScope.getString("access_token"); + WebSocketClient client = new WebSocketClient(); + try { + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + PRODUCTS_POPULAR_METHOD, true); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + PRODUCTS_CATALOG_1_METHOD, false); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + ORDERS, false); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + WILDCARD, false); + } 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 ORDERS endpoint using token", dependsOnMethods = "testWebSocketAPIGenerateKeys") + public void testWebSocketAPIInvocation_ORDERS() throws Exception { + + String requestBodyForScope = + "grant_type=password&username=" + user.getUserName() + "&password=" + user.getPassword() + "&scope" + + "=ScopeC"; + JSONObject accessTokenGenerationResponseScope = new JSONObject( + restAPIStore.generateUserAccessKey(consumerKey, consumerSecret, requestBodyForScope, tokenEndpointURL) + .getData()); + // Validate access token + org.junit.Assert.assertNotNull(accessTokenGenerationResponseScope); + org.junit.Assert.assertTrue(accessTokenGenerationResponseScope.getString("scope").contains("ScopeC")); + org.junit.Assert.assertTrue(accessTokenGenerationResponseScope.getString("expires_in").equals("3600")); + String accessTokenScope = accessTokenGenerationResponseScope.getString("access_token"); + WebSocketClient client = new WebSocketClient(); + try { + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + ORDERS, true); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + PRODUCTS_CATALOG_1_METHOD, false); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + PRODUCTS_POPULAR_METHOD, false); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + WILDCARD, false); + } 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 WILDCARD endpoint using token", dependsOnMethods = "testWebSocketAPIGenerateKeys") + public void testWebSocketAPIInvocation_WILDCARD() throws Exception { + + String requestBodyForScope = + "grant_type=password&username=" + user.getUserName() + "&password=" + user.getPassword() + "&scope" + + "=ScopeD"; + JSONObject accessTokenGenerationResponseScope = new JSONObject( + restAPIStore.generateUserAccessKey(consumerKey, consumerSecret, requestBodyForScope, tokenEndpointURL) + .getData()); + // Validate access token + org.junit.Assert.assertNotNull(accessTokenGenerationResponseScope); + org.junit.Assert.assertTrue(accessTokenGenerationResponseScope.getString("scope").contains("ScopeD")); + org.junit.Assert.assertTrue(accessTokenGenerationResponseScope.getString("expires_in").equals("3600")); + String accessTokenScope = accessTokenGenerationResponseScope.getString("access_token"); + WebSocketClient client = new WebSocketClient(); + try { + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + WILDCARD, true); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + PRODUCTS_CATALOG_1_METHOD, false); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + PRODUCTS_POPULAR_METHOD, false); + invokeAPI( + client, accessTokenScope, AUTH_IN.HEADER, null, + apiEndPoint + ORDERS, false); + } catch (Exception e) { + log.error("Exception in connecting to server", e); + Assert.fail("Client cannot connect to server"); + } finally { + client.stop(); + } + } + + /** + * Wait for client to receive reply from the server + * + * @param clientSocket WebSocket Client Object + */ + private void waitForReply(WebSocketClientImpl clientSocket) { + + long currentTime = System.currentTimeMillis(); + long WAIT_TIME = 30 * 1000; + long waitTime = currentTime + WAIT_TIME; + while (StringUtils.isEmpty(clientSocket.getResponseMessage()) && waitTime > System.currentTimeMillis()) { + try { + log.info("Waiting for reply from server:"); + Thread.sleep(1000); + } catch (InterruptedException ignored) { + } + } + log.info("Client received :" + clientSocket.getResponseMessage()); + } + + /** + * Starts backend web socket server in given port + * + * @param serverPort Port that WebSocket Server starts + */ + private void startWebSocketServer(final int serverPort) { + + executorService.execute(new Runnable() { + public void run() { + + WebSocketHandler wsHandler = new WebSocketHandler() { + @Override + public void configure(WebSocketServletFactory factory) { + + factory.register(WebSocketServerImpl.class); + } + }; + Server server = new Server(serverPort); + server.setHandler(wsHandler); + try { + server.start(); + log.info("WebSocket backend server started at port: " + serverPort); + } catch (InterruptedException ignore) { + } catch (Exception e) { + log.error("Error while starting backend server at port: " + serverPort, e); + Assert.fail("Cannot start WebSocket server"); + } + } + + }); + } + + /** + * Invoke deployed API via WebSocketClient and wait for reply + * + * @param client WebSocketClient object + * @param accessToken API access Token + * @param in location of the Auth header. {@code query} or {@code header} + * @param apiEndPoint Endpoint URI + * @throws Exception If an error occurs while invoking WebSocket API + */ + private void invokeAPI(WebSocketClient client, String accessToken, AUTH_IN in, HttpHeaders optionalRequestHeaders, + String apiEndPoint, boolean isValidToken) throws Exception { + + WebSocketClientImpl socket = new WebSocketClientImpl(); + client.start(); + ClientUpgradeRequest request = new ClientUpgradeRequest(); + URI echoUri = null; + + if (AUTH_IN.HEADER == in) { + request.setHeader("Authorization", "Bearer " + accessToken); + echoUri = new URI(apiEndPoint); + } else if (AUTH_IN.QUERY == in) { + echoUri = new URI(apiEndPoint + "?access_token=" + accessToken); + } + + if (optionalRequestHeaders != null) { + for (Map.Entry headerEntry : optionalRequestHeaders.entries()) { + request.setHeader(headerEntry.getKey(), headerEntry.getValue()); + } + } + + client.connect(socket, echoUri, request); + boolean isConnected = socket.getLatch().await(30, TimeUnit.SECONDS); + if (isConnected && isValidToken) { + socket.sendMessage(testMessage); + waitForReply(socket); + if (StringUtils.isEmpty(socket.getResponseMessage())) { + throw new APIManagerIntegrationTestException("Unable to create client connection"); + } + assertEquals(StringUtils.isEmpty(socket.getResponseMessage()), false, + "Client did not receive response from server"); + assertEquals(socket.getResponseMessage(), testMessage.toUpperCase(), + "Received response in not matching"); + socket.setResponseMessage(null); + } else if (!isConnected && !isValidToken) { + assertEquals(isConnected, isValidToken, "Client received response from server for invalid token"); + } + else { + throw new APIManagerIntegrationTestException("Unable to create client connection"); + } + } + + @AfterClass(alwaysRun = true) + public void destroy() throws Exception { + restAPIStore.deleteApplication(appJWTId); + restAPIPublisher.deleteAPI(websocketAPIID); + serverConfigurationManager.restoreToLastConfiguration(false); + executorService.shutdownNow(); + super.cleanUp(); + } + + enum AUTH_IN { + HEADER, + QUERY + } +} diff --git a/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/configFiles/allowedScopesWithCorsDisabled/deployment.toml b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/configFiles/allowedScopesWithCorsDisabled/deployment.toml new file mode 100644 index 0000000000..61e39f5a21 --- /dev/null +++ b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/artifacts/AM/configFiles/allowedScopesWithCorsDisabled/deployment.toml @@ -0,0 +1,100 @@ +[server] +hostname = "localhost" +node_ip = "127.0.0.1" +#offset=0 +mode = "single" #single or ha +base_path = "${carbon.protocol}://${carbon.host}:${carbon.management.port}" +server_role = "default" +enable_shutdown_from_api = true +enable_restart_from_api = true + +[super_admin] +username = "admin" +password = "admin" +create_admin_account = true + +[user_store] +type = "database_unique_id" + +[database.apim_db] +driver = "$env{API_MANAGER_DATABASE_DRIVER}" +url = "$env{API_MANAGER_DATABASE_URL}" +username = "$env{API_MANAGER_DATABASE_USERNAME}" +password = "$env{API_MANAGER_DATABASE_PASSWORD}" +validationQuery = "$env{API_MANAGER_DATABASE_VALIDATION_QUERY}" + +[database.shared_db] +driver = "$env{SHARED_DATABASE_DRIVER}" +url = "$env{SHARED_DATABASE_URL}" +username = "$env{SHARED_DATABASE_USERNAME}" +password = "$env{SHARED_DATABASE_PASSWORD}" +validationQuery = "$env{SHARED_DATABASE_VALIDATION_QUERY}" + +[keystore.tls] +file_name = "wso2carbon.jks" +type = "JKS" +password = "wso2carbon" +alias = "wso2carbon" +key_password = "wso2carbon" + +[[apim.gateway.environment]] +name = "Default" +type = "hybrid" +provider = "wso2" +display_in_api_console = true +description = "This is a hybrid gateway that handles both production and sandbox token traffic." +show_as_token_endpoint_url = true +service_url = "https://localhost:${mgt.transport.https.port}/services/" +username = "admin" +password = "admin" +ws_endpoint = "ws://localhost:9099" +http_endpoint = "http://localhost:${http.nio.port}" +https_endpoint = "https://localhost:${https.nio.port}" + +[[apim.gateway.environment]] +name = "devportalEnv" +display_name = "Developer portal Test Environment" +type = "hybrid" +display_in_api_console = false +description = "development api gateway broker" +provider = "solace" +service_url = "http://localhost:9960" +username = "testUser" +ws_endpoint = "ws://localhost:9960/" +wss_endpoint = "wss://localhost:9960/" +http_endpoint = "http://localhost:9960" +https_endpoint = "https://localhost:9960/" +password = "testPassword" +show_as_token_endpoint_url = false + +[apim.gateway.environment.properties] +Organization = "TestWSO2" +DisplayName = "Developer portal Test Environment" +DevAccountName = "devPortTestEnv" + +[apim.cors] +enable = false +allow_origins = "*" +allow_methods = ["GET","PUT","POST","DELETE","PATCH","OPTIONS"] +allow_headers = ["authorization","Access-Control-Allow-Origin","Content-Type","SOAPAction"] +allow_credentials = false + +[[event_handler]] +name="userPostSelfRegistration" +subscriptions=["POST_ADD_USER"] +[transport] +passthru_https.listener.ssl_profile_interval = 6000 + +[apim.certificate_reloader] +period = "1m" + +[database.local] +url = "jdbc:h2:./repository/database/WSO2CARBON_DB;DB_CLOSE_ON_EXIT=FALSE" + +[oauth] +allowed_scopes = ["^device_.*", "openid","scope1", "scope2"] + +[apim.sync_runtime_artifacts.gateway.skip_list] +apis = ["admin--git2231head_v1.0.0.xml","admin--PizzaShackAPI_v1.0.0.xml","admin--ScriptMediatorAPI_v1.0.xml", +"APIThrottleBackendAPI.xml","BackEndSecurity.xml","DigestAuth_API.xml","git2231.xml","HttpPATCHSupport_API.xml", + "JWKS-Backend.xml","JWTBackendAPI.xml","multiVSR_v1.0.0.xml","Response_API_1.xml","Response_API_2.xml","Response_Custom_API.xml","Response_Error_API.xml","Response_Loc_API.xml","SpecialCRN_v1.0.0.xml","status_code_204_API.xml","stockquote.xml","XML_API.xml","Version1.xml","Version2.xml","schemaValidationAPI.xml"] diff --git a/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/scope-validation/additionalProperties.json b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/scope-validation/additionalProperties.json new file mode 100644 index 0000000000..eda56a49c1 --- /dev/null +++ b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/scope-validation/additionalProperties.json @@ -0,0 +1,291 @@ +{ + "id": "d595ebf1-6cba-426d-b219-2de8a5ca53f0", + "name": "ExampleAPI", + "description": "API with meaningful resources following the specified template.", + "context": "/exampleapi", + "version": "1.0.0", + "provider": "admin", + "lifeCycleStatus": "CREATED", + "wsdlInfo": null, + "wsdlUrl": null, + "responseCachingEnabled": false, + "cacheTimeout": 300, + "hasThumbnail": false, + "isDefaultVersion": false, + "isRevision": false, + "revisionedApiId": null, + "revisionId": 0, + "enableSchemaValidation": false, + "enableSubscriberVerification": false, + "type": "HTTP", + "audience": null, + "transport": [ + "http", + "https" + ], + "tags": [], + "policies": [ + "Unlimited" + ], + "apiThrottlingPolicy": null, + "authorizationHeader": "Authorization", + "securityScheme": [ + "oauth2", + "oauth_basic_auth_api_key_mandatory" + ], + "maxTps": null, + "visibility": "PUBLIC", + "visibleRoles": [], + "visibleTenants": [], + "mediationPolicies": [], + "apiPolicies": null, + "subscriptionAvailability": "CURRENT_TENANT", + "subscriptionAvailableTenants": [], + "additionalProperties": [], + "additionalPropertiesMap": {}, + "monetization": null, + "accessControl": "NONE", + "accessControlRoles": [], + "businessInformation": { + "businessOwner": null, + "businessOwnerEmail": null, + "technicalOwner": null, + "technicalOwnerEmail": null + }, + "corsConfiguration": { + "corsConfigurationEnabled": false, + "accessControlAllowOrigins": [ + "*" + ], + "accessControlAllowCredentials": false, + "accessControlAllowHeaders": [ + "authorization", + "Access-Control-Allow-Origin", + "Content-Type", + "SOAPAction", + "apikey", + "Internal-Key" + ], + "accessControlAllowMethods": [ + "GET", + "PUT", + "POST", + "DELETE", + "PATCH", + "OPTIONS" + ] + }, + "websubSubscriptionConfiguration": { + "enable": false, + "secret": "", + "signingAlgorithm": "SHA1", + "signatureHeader": "x-hub-signature" + }, + "workflowStatus": null, + "createdTime": "1732096780841", + "lastUpdatedTimestamp": "1732257477566", + "lastUpdatedTime": "2024-11-22 12:07:57.566", + "endpointConfig": { + "endpoint_type": "http", + "sandbox_endpoints": { + "config": null, + "url": "http://localhost" + }, + "production_endpoints": { + "config": null, + "url": "http://localhost" + } + }, + "endpointImplementationType": "INLINE", + "scopes": [ + { + "scope": { + "id": null, + "name": "ScopeA", + "displayName": "ScopeA", + "description": "", + "bindings": [ + "admin" + ], + "usageCount": null + }, + "shared": false + }, + { + "scope": { + "id": null, + "name": "ScopeB", + "displayName": "ScopeB", + "description": "", + "bindings": [ + "admin" + ], + "usageCount": null + }, + "shared": false + }, + { + "scope": { + "id": null, + "name": "ScopeC", + "displayName": "ScopeC", + "description": "", + "bindings": [ + "admin" + ], + "usageCount": null + }, + "shared": false + }, + { + "scope": { + "id": null, + "name": "ScopeD", + "displayName": "ScopeD", + "description": "", + "bindings": [ + "admin" + ], + "usageCount": null + }, + "shared": false + }, + { + "scope": { + "id": null, + "name": "ScopeE", + "displayName": "ScopeE", + "description": "", + "bindings": [ + "admin" + ], + "usageCount": null + }, + "shared": false + } + ], + "operations": [ + { + "id": "", + "target": "/products/catalog/{categoryId}", + "verb": "GET", + "authType": "Application & Application User", + "throttlingPolicy": "Unlimited", + "scopes": [ + "ScopeA" + ], + "usedProductIds": [], + "amznResourceName": null, + "amznResourceTimeout": null, + "amznResourceContentEncode": null, + "payloadSchema": null, + "uriMapping": null, + "operationPolicies": { + "request": [], + "response": [], + "fault": [] + } + }, + { + "id": "", + "target": "/products/popular", + "verb": "GET", + "authType": "Application & Application User", + "throttlingPolicy": "Unlimited", + "scopes": [ + "ScopeB" + ], + "usedProductIds": [], + "amznResourceName": null, + "amznResourceTimeout": null, + "amznResourceContentEncode": null, + "payloadSchema": null, + "uriMapping": null, + "operationPolicies": { + "request": [], + "response": [], + "fault": [] + } + }, + { + "id": "", + "target": "/products/*", + "verb": "GET", + "authType": "Application & Application User", + "throttlingPolicy": "Unlimited", + "scopes": [ + "ScopeC" + ], + "usedProductIds": [], + "amznResourceName": null, + "amznResourceTimeout": null, + "amznResourceContentEncode": null, + "payloadSchema": null, + "uriMapping": null, + "operationPolicies": { + "request": [], + "response": [], + "fault": [] + } + }, + { + "id": "", + "target": "/orders", + "verb": "GET", + "authType": "Application & Application User", + "throttlingPolicy": "Unlimited", + "scopes": [ + "ScopeD" + ], + "usedProductIds": [], + "amznResourceName": null, + "amznResourceTimeout": null, + "amznResourceContentEncode": null, + "payloadSchema": null, + "uriMapping": null, + "operationPolicies": { + "request": [], + "response": [], + "fault": [] + } + }, + { + "id": "", + "target": "/*", + "verb": "GET", + "authType": "Application & Application User", + "throttlingPolicy": "Unlimited", + "scopes": [ + "ScopeE" + ], + "usedProductIds": [], + "amznResourceName": null, + "amznResourceTimeout": null, + "amznResourceContentEncode": null, + "payloadSchema": null, + "uriMapping": null, + "operationPolicies": { + "request": [], + "response": [], + "fault": [] + } + } + ], + "threatProtectionPolicies": null, + "categories": [], + "keyManagers": [ + "all" + ], + "serviceInfo": null, + "advertiseInfo": { + "advertised": false, + "apiExternalProductionEndpoint": null, + "apiExternalSandboxEndpoint": null, + "originalDevPortalUrl": null, + "apiOwner": "admin", + "vendor": "WSO2" + }, + "gatewayVendor": "wso2", + "gatewayType": "wso2/synapse", + "asyncTransportProtocols": [] +} diff --git a/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/scope-validation/oas_import.json b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/scope-validation/oas_import.json new file mode 100644 index 0000000000..3633c86ce5 --- /dev/null +++ b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/oas/v3/scope-validation/oas_import.json @@ -0,0 +1,262 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "ExampleAPI", + "description": "API with meaningful resources following the specified template.", + "version": "1.0.0" + }, + "servers": [ + { + "url": "/" + } + ], + "security": [ + { + "default": [] + } + ], + "paths": { + "/products/catalog/{categoryId}": { + "get": { + "summary": "Get products by category", + "parameters": [ + { + "name": "categoryId", + "in": "path", + "description": "The ID of the product category.", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "List of products in the specified category." + }, + "404": { + "description": "Category not found." + } + }, + "security": [ + { + "default": [ + "ScopeA" + ] + } + ], + "x-auth-type": "Application & Application User", + "x-throttling-tier": "Unlimited", + "x-mediation-script": "mc.setProperty('CONTENT_TYPE', 'application/json');\nmc.setPayloadJSON('{ \"data\" : \"sample JSON\"}');", + "x-wso2-application-security": { + "security-types": [ + "oauth2" + ], + "optional": false + } + } + }, + "/products/popular": { + "get": { + "summary": "Get popular products", + "responses": { + "200": { + "description": "List of popular products retrieved successfully." + } + }, + "security": [ + { + "default": [ + "ScopeB" + ] + } + ], + "x-auth-type": "Application & Application User", + "x-throttling-tier": "Unlimited", + "x-mediation-script": "mc.setProperty('CONTENT_TYPE', 'application/json');\nmc.setPayloadJSON('{ \"data\" : \"sample JSON\"}');", + "x-wso2-application-security": { + "security-types": [ + "oauth2" + ], + "optional": false + } + } + }, + "/products/*": { + "get": { + "summary": "Retrieve product details with wildcard path", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "Optional query string to filter products by name or attributes.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Products retrieved successfully." + }, + "404": { + "description": "Product not found." + } + }, + "security": [ + { + "default": [ + "ScopeC" + ] + } + ], + "x-auth-type": "Application & Application User", + "x-throttling-tier": "Unlimited", + "x-mediation-script": "mc.setProperty('CONTENT_TYPE', 'application/json');\nmc.setPayloadJSON('{ \"data\" : \"sample JSON\"}');", + "x-wso2-application-security": { + "security-types": [ + "oauth2" + ], + "optional": false + } + } + }, + "/orders": { + "get": { + "summary": "Retrieve all orders", + "responses": { + "200": { + "description": "List of orders retrieved successfully." + } + }, + "security": [ + { + "default": [ + "ScopeD" + ] + } + ], + "x-auth-type": "Application & Application User", + "x-throttling-tier": "Unlimited", + "x-mediation-script": "mc.setProperty('CONTENT_TYPE', 'application/json');\nmc.setPayloadJSON('{ \"data\" : \"sample JSON\"}');", + "x-wso2-application-security": { + "security-types": [ + "oauth2" + ], + "optional": false + } + } + }, + "/*": { + "get": { + "summary": "Catch-all route", + "responses": { + "200": { + "description": "Fallback response for undefined routes." + }, + "404": { + "description": "Resource not found." + } + }, + "security": [ + { + "default": [ + "ScopeE" + ] + } + ], + "x-auth-type": "Application & Application User", + "x-throttling-tier": "Unlimited", + "x-mediation-script": "mc.setProperty('CONTENT_TYPE', 'application/json');\nmc.setPayloadJSON('{ \"data\" : \"sample JSON\"}');", + "x-wso2-application-security": { + "security-types": [ + "oauth2" + ], + "optional": false + } + } + } + }, + "components": { + "securitySchemes": { + "default": { + "type": "oauth2", + "flows": { + "implicit": { + "authorizationUrl": "https://test.com", + "scopes": { + "ScopeA": "", + "ScopeC": "", + "ScopeB": "", + "ScopeD": "", + "ScopeE": "" + }, + "x-scopes-bindings": { + "ScopeA": "admin", + "ScopeC": "admin", + "ScopeB": "admin", + "ScopeE": "admin", + "ScopeD": "admin" + } + } + } + } + } + }, + "x-wso2-auth-header": "Authorization", + "x-wso2-cors": { + "corsConfigurationEnabled": false, + "accessControlAllowOrigins": [ + "*" + ], + "accessControlAllowCredentials": false, + "accessControlAllowHeaders": [ + "authorization", + "Access-Control-Allow-Origin", + "Content-Type", + "SOAPAction", + "apikey", + "Internal-Key" + ], + "accessControlAllowMethods": [ + "GET", + "PUT", + "POST", + "DELETE", + "PATCH", + "OPTIONS" + ] + }, + "x-wso2-production-endpoints": { + "urls": [ + "http://localhost" + ], + "type": "http" + }, + "x-wso2-sandbox-endpoints": { + "urls": [ + "http://localhost" + ], + "type": "http" + }, + "x-wso2-basePath": "/exampleapi/1.0.0", + "x-wso2-transports": [ + "http", + "https" + ], + "x-wso2-application-security": { + "security-types": [ + "oauth2" + ], + "optional": false + }, + "x-wso2-response-cache": { + "enabled": false, + "cacheTimeoutInSeconds": 300 + } +} diff --git a/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml index f4c91dd042..ea05a6e1ee 100644 --- a/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml +++ b/all-in-one-apim/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml @@ -146,6 +146,7 @@ + @@ -340,6 +341,7 @@ +