Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add integration tests for mutual ssl certificate chain validation #13393

Merged
merged 2 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com) 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.api.lifecycle;

import org.apache.commons.httpclient.HttpStatus;
import org.json.JSONException;
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.ApiException;
import org.wso2.am.integration.clients.publisher.api.v1.dto.APIDTO;
import org.wso2.am.integration.clients.publisher.api.v1.dto.APIOperationsDTO;
import org.wso2.am.integration.test.utils.APIManagerIntegrationTestException;
import org.wso2.am.integration.test.utils.base.APIMIntegrationConstants;
import org.wso2.am.integration.test.utils.bean.APIRequest;
import org.wso2.am.integration.test.utils.http.HTTPSClientUtils;
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.test.utils.http.client.HttpResponse;
import org.wso2.carbon.integration.common.utils.exceptions.AutomationUtilException;
import org.wso2.carbon.um.ws.api.stub.RemoteUserStoreManagerServiceUserStoreExceptionException;
import org.wso2.carbon.user.core.UserStoreException;

import javax.xml.xpath.XPathExpressionException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SetEnvironment(executionEnvironments = { ExecutionEnvironment.STANDALONE })
public class APISecurityMutualSSLCertificateChainValidationTestCase extends APIManagerLifecycleBaseTest {

private final String rootCertAPI = "rootCertAPI";
private final String intermediateCertAPI = "intermediateCertAPI";
private final String API_END_POINT_METHOD = "/customers/123";
private final String API_VERSION_1_0_0 = "1.0.0";
private final String API_END_POINT_POSTFIX_URL = "jaxrs_basic/services/customers/customerservice/";
private String apiEndPointUrl;
private String apiId1, apiId2;

@DataProvider
public static Object[][] userModeDataProvider() {

return new Object[][] { new Object[] { TestUserMode.SUPER_TENANT_ADMIN },
new Object[] { TestUserMode.TENANT_ADMIN } };
}

@Factory(dataProvider = "userModeDataProvider")
public APISecurityMutualSSLCertificateChainValidationTestCase(TestUserMode userMode) {

this.userMode = userMode;
}

@BeforeClass(alwaysRun = true)
public void initialize() throws APIManagerIntegrationTestException, IOException, ApiException,
org.wso2.am.integration.clients.store.api.ApiException, XPathExpressionException, AutomationUtilException,
InterruptedException, JSONException, RemoteUserStoreManagerServiceUserStoreExceptionException,
UserStoreException {

super.init(userMode);
apiEndPointUrl = backEndServerUrl.getWebAppURLHttp() + API_END_POINT_POSTFIX_URL;

APIRequest apiRequest1 = new APIRequest(rootCertAPI, rootCertAPI, new URL(apiEndPointUrl));
apiRequest1.setVersion(API_VERSION_1_0_0);
apiRequest1.setTiersCollection(APIMIntegrationConstants.API_TIER.UNLIMITED);
apiRequest1.setTier(APIMIntegrationConstants.API_TIER.UNLIMITED);
apiRequest1.setTags(API_TAGS);
apiRequest1.setVisibility(APIDTO.VisibilityEnum.PUBLIC.getValue());
apiRequest1.setProvider(user.getUserName());
APIOperationsDTO apiOperationsDTO1 = new APIOperationsDTO();
apiOperationsDTO1.setVerb("GET");
apiOperationsDTO1.setTarget("/customers/{id}");
apiOperationsDTO1.setAuthType("Application & Application User");
apiOperationsDTO1.setThrottlingPolicy("Unlimited");

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

List<String> securitySchemes = new ArrayList<>();
securitySchemes.add("mutualssl");
securitySchemes.add("mutualssl_mandatory");
apiRequest1.setSecurityScheme(securitySchemes);
apiRequest1.setDefault_version("true");
apiRequest1.setHttps_checked("https");
apiRequest1.setHttp_checked(null);
apiRequest1.setDefault_version_checked("true");
HttpResponse response1 = restAPIPublisher.addAPI(apiRequest1);
apiId1 = response1.getData();

String rootCertPath = getAMResourceLocation() + File.separator + "lifecycletest" + File.separator + "mutualssl"
+ File.separator + "cert_chain_root.cer";
restAPIPublisher.uploadCertificate(new File(rootCertPath), "cert_chain_root", apiId1,
APIMIntegrationConstants.API_TIER.UNLIMITED);
createAPIRevisionAndDeployUsingRest(apiId1, restAPIPublisher);

APIRequest apiRequest2 = new APIRequest(intermediateCertAPI, intermediateCertAPI, new URL(apiEndPointUrl));
apiRequest2.setVersion(API_VERSION_1_0_0);
apiRequest2.setTiersCollection(APIMIntegrationConstants.API_TIER.UNLIMITED);
apiRequest2.setTier(APIMIntegrationConstants.API_TIER.UNLIMITED);
apiRequest2.setTags(API_TAGS);
apiRequest2.setVisibility(APIDTO.VisibilityEnum.PUBLIC.getValue());
apiRequest2.setProvider(user.getUserName());
apiRequest2.setOperationsDTOS(operationsDTOS);
apiRequest2.setSecurityScheme(securitySchemes);
apiRequest2.setDefault_version("true");
apiRequest2.setHttps_checked("https");
apiRequest2.setHttp_checked(null);
apiRequest2.setDefault_version_checked("true");
HttpResponse response2 = restAPIPublisher.addAPI(apiRequest2);
apiId2 = response2.getData();

String intermediateCertPath = getAMResourceLocation() + File.separator + "lifecycletest" + File.separator + "mutualssl"
+ File.separator + "cert_chain_intermediate.cer";
restAPIPublisher.uploadCertificate(new File(intermediateCertPath), "cert_chain_intermediate", apiId2,
APIMIntegrationConstants.API_TIER.UNLIMITED);
createAPIRevisionAndDeployUsingRest(apiId2, restAPIPublisher);

waitForAPIDeploymentSync(user.getUserName(), rootCertAPI, API_VERSION_1_0_0,
APIMIntegrationConstants.IS_API_EXISTS);
waitForAPIDeploymentSync(user.getUserName(), intermediateCertAPI, API_VERSION_1_0_0,
APIMIntegrationConstants.IS_API_EXISTS);

// wait until certificates loaded
Thread.sleep(120000);
}

@Test(description = "Invoke mutual SSL only API with not supported certificate")
public void testAPIInvocationWithMutualSSLOnlyAPINegative()
throws IOException, XPathExpressionException, NoSuchAlgorithmException, KeyStoreException,
KeyManagementException, UnrecoverableKeyException {

Map<String, String> requestHeaders = new HashMap<>();
requestHeaders.put("accept", "text/xml");
HttpResponse response = HTTPSClientUtils.doMutulSSLGet(
getAMResourceLocation() + File.separator + "lifecycletest" + File.separator + "mutualssl"
+ File.separator + "test.jks",
getAPIInvocationURLHttps(rootCertAPI, API_VERSION_1_0_0) + API_END_POINT_METHOD, requestHeaders);
HttpResponse defaultResponse = HTTPSClientUtils.doMutulSSLGet(
getAMResourceLocation() + File.separator + "lifecycletest" + File.separator + "mutualssl"
+ File.separator + "test.jks", getAPIInvocationURLHttps(rootCertAPI) + API_END_POINT_METHOD,
requestHeaders);
Assert.assertEquals(response.getResponseCode(), HttpStatus.SC_UNAUTHORIZED);
Assert.assertEquals(defaultResponse.getResponseCode(), HttpStatus.SC_UNAUTHORIZED);
}

@Test(description = "API invocation with mutual ssl mandatory", dependsOnMethods = "testAPIInvocationWithMutualSSLOnlyAPINegative")
public void testAPIInvocationWithMutualSSLMandatory()
throws IOException, XPathExpressionException, NoSuchAlgorithmException, KeyStoreException,
KeyManagementException, UnrecoverableKeyException {

Map<String, String> requestHeaders = new HashMap<>();
requestHeaders.put("accept", "text/xml");

// Using root certificate
HttpResponse rootCertResponse = HTTPSClientUtils.doMutulSSLGet(
getAMResourceLocation() + File.separator + "lifecycletest" + File.separator + "mutualssl"
+ File.separator + "cert_chain_root.jks",
getAPIInvocationURLHttps(rootCertAPI, API_VERSION_1_0_0) + API_END_POINT_METHOD, requestHeaders);
Assert.assertEquals(rootCertResponse.getResponseCode(), HttpStatus.SC_OK, "Mutual SSL Authentication has not succeed");

// Using client certificate with certificate chain
HttpResponse clientCertResponse = HTTPSClientUtils.doMutulSSLGet(
getAMResourceLocation() + File.separator + "lifecycletest" + File.separator + "mutualssl"
+ File.separator + "cert_chain_client.jks",
getAPIInvocationURLHttps(rootCertAPI, API_VERSION_1_0_0) + API_END_POINT_METHOD, requestHeaders);
Assert.assertEquals(clientCertResponse.getResponseCode(), HttpStatus.SC_OK, "Mutual SSL Authentication has not succeed");

// Using client certificate with head only exported certificate
HttpResponse headOnlyClientCertResponse = HTTPSClientUtils.doMutulSSLGet(
getAMResourceLocation() + File.separator + "lifecycletest" + File.separator + "mutualssl"
+ File.separator + "cert_chain_client_head_only.jks",
getAPIInvocationURLHttps(rootCertAPI, API_VERSION_1_0_0) + API_END_POINT_METHOD, requestHeaders);
Assert.assertEquals(headOnlyClientCertResponse.getResponseCode(), HttpStatus.SC_OK, "Mutual SSL Authentication has not succeed");

// For default API version with root certificate
HttpResponse defaultRootCertResponse = HTTPSClientUtils.doMutulSSLGet(
getAMResourceLocation() + File.separator + "lifecycletest" + File.separator + "mutualssl"
+ File.separator + "cert_chain_root.jks",
getAPIInvocationURLHttps(rootCertAPI) + API_END_POINT_METHOD, requestHeaders);
Assert.assertEquals(defaultRootCertResponse.getResponseCode(), HttpStatus.SC_OK,
"Mutual SSL Authentication has not succeed");

// For default API version with client certificate
HttpResponse defaultClientCertResponse = HTTPSClientUtils.doMutulSSLGet(
getAMResourceLocation() + File.separator + "lifecycletest" + File.separator + "mutualssl"
+ File.separator + "cert_chain_client.jks",
getAPIInvocationURLHttps(rootCertAPI) + API_END_POINT_METHOD, requestHeaders);
Assert.assertEquals(defaultClientCertResponse.getResponseCode(), HttpStatus.SC_OK,
"Mutual SSL Authentication has not succeed");
}

@AfterClass(alwaysRun = true)
public void cleanUpArtifacts() throws Exception {

restAPIPublisher.deleteAPI(apiId1);
restAPIPublisher.deleteAPI(apiId2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,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"]

[apimgt.mutual_ssl]
enable_certificate_chain_validation = true
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID6DCCAtCgAwIBAgIUfUON+4ekletjetDwaT0BjeU3pVswDQYJKoZIhvcNAQEL
BQAwZzELMAkGA1UEBhMCTEsxDjAMBgNVBAgMBWFiY2RlMQ4wDAYDVQQHDAVhYmNk
ZTEOMAwGA1UECgwFYWJjZGUxDjAMBgNVBAsMBWFiY2RlMRgwFgYDVQQDDA9jZXJ0
LWNoYWluLXJvb3QwHhcNMjQwMjI2MTE0MDQ1WhcNMjgxMjMxMTgyOTU5WjBvMQsw
CQYDVQQGEwJMSzEOMAwGA1UECAwFYWJjZGUxDjAMBgNVBAcMBWFiY2RlMQ4wDAYD
VQQKDAVhYmNkZTEOMAwGA1UECwwFYWJjZGUxIDAeBgNVBAMMF2NlcnQtY2hhaW4t
aW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAur4k
JgUu7Iz3MVNhP/NPVzWBMzUU+/wg4cNcbiZlCnupZ+7O+1EFbKD0ym3GhBYFKX3z
oAfLVd6ul3SbeyvbWwG5Hv9Ahv+CYSsNOBqNfwz4Su+XNsaHukwEgr74YkFe6Uj8
W1paroz07Ra8lqx4iFzKAmsfMxNq2EmpMGPIwFXJde1E8R26J79jYWdYRMYjEKXw
J8hf+GDdTMn70d48EGjh+8q8wz3mf6VfNchXD60kywZjBWn5XwOowffULwR6Xaze
lc4JIsxhMalBNlE6auAI4U9N82tgLaP+YZ0fnsPWAxqVvSCyX0TZIVe/DQ/4cFxW
fM18VBYXHMZ1i7B8IQIDAQABo4GDMIGAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
AQH/BAQDAgGGMB8GA1UdIwQYMBaAFGwbNBqwR2b9p4jR2wQGUAHsFXH8MB0GA1Ud
DgQWBBRGpwm9vwksu7hT45jwfbspwLtbxTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
KwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAMdGNDfSCsycTkxigszBdSOlpQ37
7+Pg2pSuCwSASZALmgIHOCquRrHv8Gb+NM0kfwPXUwKP+nzuVNF89P5kYtKfKpK5
DATe7o5OMQZt7PLqqC4YyTkVl/j55MySM4x7H1s3lZj4L7H8UOOoBAmtftOz2iR0
5s9260QdsUb9HOYBgHvmdbLS4FOiFfiVZByM/Iv3wNtGMDjleEj31EzBRbY1AgC6
VAfRF1Y2Lk+k/ONoEiy5MdFavmIn3SsEsRWDCtHZgS5Bk1uvPJ9s3E1IU7DwBsIE
W25P+PK7D0a+WB3s99CbfxbLm4rh01lbSFraDwv447qIZtILgXSDfqsgjPY=
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID4DCCAsigAwIBAgIUYfJ19DH+gJIjI3XVmDQBjeUu9UQwDQYJKoZIhvcNAQEL
BQAwZzELMAkGA1UEBhMCTEsxDjAMBgNVBAgMBWFiY2RlMQ4wDAYDVQQHDAVhYmNk
ZTEOMAwGA1UECgwFYWJjZGUxDjAMBgNVBAsMBWFiY2RlMRgwFgYDVQQDDA9jZXJ0
LWNoYWluLXJvb3QwHhcNMjQwMjI2MTEzMTE2WhcNMjgwMjI1MTEzMTE2WjBnMQsw
CQYDVQQGEwJMSzEOMAwGA1UECAwFYWJjZGUxDjAMBgNVBAcMBWFiY2RlMQ4wDAYD
VQQKDAVhYmNkZTEOMAwGA1UECwwFYWJjZGUxGDAWBgNVBAMMD2NlcnQtY2hhaW4t
cm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM9eeBl+roj7svOI
hvD4FtUjP2oQMtoRAwiEHGhJ1eKBEYE39qfWJ2A/9+UMmxeO/xblB3euyCj2rGzr
RVXFh8ou4zblf0SrcRl+HG+KG0BjPZS7ptStgVceqAS9sWaLUaGTo/TdEm4MIEcU
c40ef0XLQhIWLRLOgnDhX4ykR7hEU5/Y9cyiDXT4m4nuLQyug0gulEUZPjXlZfxD
R7vpyJINyeqtkbPCv6Nw/oZ03Cd/mYCqFEyBuO4qcpKI+sNTd08RoucsO1lt5mHe
xYo6Dxz8Csi6dibAiGlrqMCJg/xYYyShd0SBeEv3RGHNjoKT4TNndcS2D14R/vp5
mpPsUwUCAwEAAaOBgzCBgDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
hjAfBgNVHSMEGDAWgBRsGzQasEdm/aeI0dsEBlAB7BVx/DAdBgNVHQ4EFgQUbBs0
GrBHZv2niNHbBAZQAewVcfwwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MA0GCSqGSIb3DQEBCwUAA4IBAQCg/Toe27OMLZgD/BPjx7NPKX+01vWwSgQrRJEx
jSjljZJ1wKvv3uiQ6ijrP+gq+OgAXp6PV9QUTCT6rMKbKU0TI4TpPw9gPH8WNFIq
pQ0nrDPmoJkfqOJ5MwrJ0T/VqaUWzsCbCmfEVEf7SOezPRDhOc202jcTXdLfEiHt
sRJTdhAAFjLcpwQUhKLygh3S7t/TDZ/0E6qKlHNYADennx4aQh6WE8magx6x4o2F
0FGlf6gX7pSGpDtFsh/gBYGo54pwx0iabw6qcwK2U4L+a/U4ZYVgTlYnm2Aazjnq
zCtKuvSwJAyfp3kkYwtkjnfKcA0PktAwFWnM9+fseU2kRE1l
-----END CERTIFICATE-----
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@
<classes>
<class name="org.wso2.am.integration.tests.application.groupSharing.ApplicationSharingConfig"/>
<class name="org.wso2.am.integration.tests.application.groupSharing.ApplicationSharingTestCase"/>
<class name="org.wso2.am.integration.tests.api.lifecycle.APISecurityMutualSSLCertificateChainValidationTestCase" />
</classes>
</test>

Expand Down
Loading