Skip to content

Commit

Permalink
Implement a testcase for OPTIONS backend traffic (#13615)
Browse files Browse the repository at this point in the history
  • Loading branch information
dakshina99 authored Jan 3, 2025
1 parent 8676e83 commit 101ec72
Show file tree
Hide file tree
Showing 22 changed files with 243 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public class APIMIntegrationConstants {

public static final String HTTP_VERB_GET = "GET";
public static final String HTTP_VERB_POST = "POST";
public static final String HTTP_VERB_OPTIONS = "OPTIONS";

public static final String API_DOCUMENT_TYPE_HOW_TO = "How To";
public static final String API_DOCUMENT_SOURCE_INLINE = "Inline";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ public void configureEnvironment() throws Exception {
loadSynapseConfigurationFromClasspath("artifacts" + File.separator + "AM"
+ File.separator + "synapseconfigs" + File.separator + "rest"
+ File.separator + "BackEndSecurity.xml", gatewayContextMgt, gatewaySessionCookie);
loadSynapseConfigurationFromClasspath("artifacts" + File.separator + "AM"
+ File.separator + "synapseconfigs" + File.separator + "rest"
+ File.separator + "BackendCORS.xml", gatewayContextMgt, gatewaySessionCookie);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.am.integration.tests.header;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.HttpClientBuilder;
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.APIOperationsDTO;
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.clients.store.api.v1.dto.SubscriptionListDTO;
import org.wso2.am.integration.test.utils.base.APIMIntegrationConstants;
import org.wso2.am.integration.test.utils.bean.APIRequest;
import org.wso2.am.integration.tests.api.lifecycle.APIManagerLifecycleBaseTest;
import org.wso2.carbon.automation.engine.FrameworkConstants;
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 java.net.URL;
import java.util.ArrayList;
import java.util.List;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;

/**
* Test CORS backend routing functionality
*/
@SetEnvironment(executionEnvironments = {ExecutionEnvironment.ALL })
public class CORSBackendTrafficRouteTestCase extends APIManagerLifecycleBaseTest {

private static final String API_VERSION = "1.0.0";
private static final String DESCRIPTION = "This is test API create by API manager integration test";

private static final String API_NAME = "CorsBackendTestAPI";
private static final String APPLICATION_NAME2 = "CorsBackendTestApp";
private static final String API_CONTEXT2 = "corsBackendTestAPI";
private static final String TAGS2 = "cors, backend, test";

private static final String ACCESS_CONTROL_ALLOW_ORIGIN_HEADER = "Access-Control-Allow-Origin";
private static final String ACCESS_CONTROL_ALLOW_ORIGIN_HEADER_VALUE_BACKEND = "http://localhost";
private static final String ACCESS_CONTROL_ALLOW_METHODS_HEADER = "Access-Control-Allow-Methods";
private static final String ACCESS_CONTROL_ALLOW_METHODS_HEADER_VALUE_BACKEND = "GET, POST, OPTIONS";
private static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers";
private static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER_VALUE_BACKEND = "authorization,Access-Control-Allow-Origin";
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials";

private String applicationId;
private String apiId;
private ApplicationKeyDTO applicationKeyDTO;

Log log = LogFactory.getLog(CORSBackendTrafficRouteTestCase.class);

@BeforeClass(alwaysRun = true)
public void setEnvironment() throws Exception {
super.init(userMode);

//Create application
org.wso2.carbon.automation.test.utils.http.client.HttpResponse applicationResponse =
restAPIStore.createApplication(APPLICATION_NAME2,
"This is a test application for CORS backend routing test",
APIMIntegrationConstants.APPLICATION_TIER.UNLIMITED,
ApplicationDTO.TokenTypeEnum.JWT);
applicationId = applicationResponse.getData();

//get access token
ArrayList<String> grantTypes = new ArrayList<>();
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.PASSWORD);
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.CLIENT_CREDENTIAL);
applicationKeyDTO = restAPIStore.generateKeys(applicationId, "36000", "",
ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, null, grantTypes);
}

@Test(groups = {"wso2.am"}, description = "Check CORS headers in OPTIONS response from Backend for a OPTIONS resource defined API")
public void CheckCORSHeadersInOptionsResponseFromBackend() throws Exception {
APIRequest apiRequest = new APIRequest(API_NAME, API_CONTEXT2,
new URL(gatewayUrlsWrk.getWebAppURLNhttp() + "backend-cors"));
apiRequest.setTags(TAGS2);
apiRequest.setVersion(API_VERSION);
apiRequest.setVisibility("public");
apiRequest.setDescription(DESCRIPTION);
apiRequest.setTiersCollection(TIER_UNLIMITED);
apiRequest.setProvider(publisherContext.getContextTenant().getContextUser().getUserName());

//Add api resource
APIOperationsDTO apiOperationsDTO1 = new APIOperationsDTO();
apiOperationsDTO1.setVerb(APIMIntegrationConstants.HTTP_VERB_OPTIONS);
apiOperationsDTO1.setTarget("/cors");
apiOperationsDTO1.setAuthType(APIMIntegrationConstants.RESOURCE_AUTH_TYPE_APPLICATION_AND_APPLICATION_USER);
apiOperationsDTO1.setThrottlingPolicy(APIMIntegrationConstants.RESOURCE_TIER.UNLIMITED);

List<APIOperationsDTO> operationsDTOS = new ArrayList<>();
operationsDTOS.add(apiOperationsDTO1);
apiRequest.setOperationsDTOS(operationsDTOS);

apiId = createPublishAndSubscribeToAPIUsingRest(apiRequest, restAPIPublisher, restAPIStore, applicationId,
APIMIntegrationConstants.APPLICATION_TIER.UNLIMITED);

HttpClient httpclient = HttpClientBuilder.create().build();
String uri;
if (gatewayContextWrk.getContextTenant().getDomain().equals(FrameworkConstants.SUPER_TENANT_DOMAIN_NAME)) {
uri = gatewayUrlsWrk.getWebAppURLNhttp() + API_CONTEXT2 + "/" + API_VERSION + "/cors";
} else {
uri = gatewayUrlsWrk.getWebAppURLNhttp() + "t/" + gatewayContextWrk.getContextTenant()
.getDomain() + "/" + API_CONTEXT2 + "/" + API_VERSION + "/cors";
}

HttpUriRequest option = new HttpOptions(uri);
option.addHeader("Authorization", "Bearer " + applicationKeyDTO.getToken().getAccessToken());
HttpResponse response = httpclient.execute(option);

assertEquals(response.getStatusLine().getStatusCode(), HTTP_RESPONSE_CODE_OK, "Response code mismatch.");

Header[] responseHeaders = response.getAllHeaders();

log.info("Response Headers: CheckCORSHeadersInOptionsResponseFromBackend");
for (Header header : responseHeaders) {
log.info(header.getName() + " : " + header.getValue());
}

Header header = pickHeader(responseHeaders, ACCESS_CONTROL_ALLOW_ORIGIN_HEADER);
assertNotNull(header, ACCESS_CONTROL_ALLOW_ORIGIN_HEADER + " header is not available in the response.");
assertEquals(header.getValue(), ACCESS_CONTROL_ALLOW_ORIGIN_HEADER_VALUE_BACKEND,
ACCESS_CONTROL_ALLOW_ORIGIN_HEADER + " header value mismatch.");

header = pickHeader(responseHeaders, ACCESS_CONTROL_ALLOW_METHODS_HEADER);
assertNotNull(header, ACCESS_CONTROL_ALLOW_METHODS_HEADER + " header is not available in the response.");
assertEquals(header.getValue(), ACCESS_CONTROL_ALLOW_METHODS_HEADER_VALUE_BACKEND, ACCESS_CONTROL_ALLOW_METHODS_HEADER + " header value mismatch.");

header = pickHeader(responseHeaders, ACCESS_CONTROL_ALLOW_HEADERS_HEADER);
assertNotNull(header, ACCESS_CONTROL_ALLOW_HEADERS_HEADER + " header is not available in the response.");
assertEquals(header.getValue(), ACCESS_CONTROL_ALLOW_HEADERS_HEADER_VALUE_BACKEND,
ACCESS_CONTROL_ALLOW_HEADERS_HEADER + " header value mismatch.");

assertNull(pickHeader(responseHeaders, ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER),
ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER + " header is available in the response, " +
"but it should not be.");
}


@AfterClass(alwaysRun = true)
public void destroy() throws Exception {
SubscriptionListDTO subsDTO = restAPIStore.getAllSubscriptionsOfApplication(applicationId);
for (SubscriptionDTO subscriptionDTO: subsDTO.getList()){
restAPIStore.removeSubscription(subscriptionDTO);
}
restAPIStore.deleteApplication(applicationId);
undeployAndDeleteAPIRevisionsUsingRest(apiId, restAPIPublisher);
restAPIPublisher.deleteAPI(apiId);

super.cleanUp();
}

@DataProvider
public static Object[][] userModeDataProvider() {
return new Object[][] { new Object[] { TestUserMode.SUPER_TENANT_ADMIN },
new Object[] { TestUserMode.TENANT_ADMIN },
};
}

@Factory(dataProvider = "userModeDataProvider")
public CORSBackendTrafficRouteTestCase(TestUserMode userMode) {
this.userMode = userMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,4 @@ description="External Reference Id"

[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"]
"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", "BackendCORS.xml"]
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@ 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"]
"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", "BackendCORS.xml"]
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ password = "${admin.password}"
[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"]
"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", "BackendCORS.xml"]

[oauth]
show_display_name_in_consent_page = true
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ password = "${admin.password}"

[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"]
"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", "BackendCORS.xml"]

[apimgt.mutual_ssl]
enable_certificate_chain_validation = true
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,4 @@ apis = ["admin--git2231head_v1.0.0.xml","admin--PizzaShackAPI_v1.0.0.xml","admin
"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"]
"status_code_204_API.xml","stockquote.xml","XML_API.xml","Version1.xml","Version2.xml","schemaValidationAPI.xml", "BackendCORS.xml"]
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ password = "${admin.password}"
[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"]
"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", "BackendCORS.xml"]

[apim.jwt]
enable = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,4 @@ password = "${admin.password}"

[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"]
"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", "BackendCORS.xml"]
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,4 @@ password = "${admin.password}"

[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"]
"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", "BackendCORS.xml"]
Loading

0 comments on commit 101ec72

Please sign in to comment.