diff --git a/.github/workflows/plugin_install.yml b/.github/workflows/plugin_install.yml index 684cfd7451..63f3afdff9 100644 --- a/.github/workflows/plugin_install.yml +++ b/.github/workflows/plugin_install.yml @@ -54,3 +54,6 @@ jobs: opensearch-version: ${{ env.OPENSEARCH_VERSION }} plugin-name: ${{ env.PLUGIN_NAME }} setup-script-name: setup + + - name: Run sanity tests + run: ./gradlew integTestRemote -Dtests.rest.cluster=localhost:9200 -Dtests.cluster=localhost:9200 -Dtests.clustername="opensearch" -Dhttps=true -Duser=admin -Dpassword=admin diff --git a/README.md b/README.md index 2e5488786c..3db363325a 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,16 @@ Run all tests: ./gradlew clean test ``` +Run tests against local cluster: +```bash +./gradlew integTestRemote -Dtests.rest.cluster=localhost:9200 -Dtests.cluster=localhost:9200 -Dtests.clustername=docker-cluster -Dsecurity=true -Dhttps=true -Duser=admin -Dpassword=admin -Dcommon_utils.version="2.2.0.0" +``` +OR +```bash +./scripts/integtest.sh +``` +Note: To run against a remote cluster replace cluster-name and `localhost:9200` with the IPAddress:Port of that cluster. + Build artifacts (zip, deb, rpm): ```bash ./gradlew clean assemble diff --git a/build.gradle b/build.gradle index 2cb5b55fe2..d98ccc7a3e 100644 --- a/build.gradle +++ b/build.gradle @@ -44,10 +44,12 @@ plugins { id "org.gradle.test-retry" version "1.3.1" id "com.github.spotbugs" version "5.0.13" } + import org.gradle.crypto.checksum.Checksum import java.text.SimpleDateFormat +import org.opensearch.gradle.test.RestIntegTestTask repositories { mavenLocal() @@ -64,6 +66,8 @@ ext { opensearch_build = version_tokens[0] + '.0' kafka_version = '3.0.2' + common_utils_version = System.getProperty("common_utils.version", '2.1.0.0') + if (buildVersionQualifier) { opensearch_build += "-${buildVersionQualifier}" opensearch_build_nosnapshot = opensearch_build @@ -73,6 +77,10 @@ ext { } } + +apply plugin: 'opensearch.rest-test' +apply plugin: 'opensearch.testclusters' + configurations.all { resolutionStrategy { force 'commons-codec:commons-codec:1.14' @@ -139,6 +147,7 @@ dependencies { testImplementation "org.apache.kafka:kafka_2.13:${kafka_version}" testImplementation "org.apache.kafka:kafka_2.13:${kafka_version}:test" testImplementation "org.apache.kafka:kafka-clients:${kafka_version}:test" + testImplementation "org.opensearch:common-utils:${common_utils_version}" compileOnly "org.opensearch:opensearch:${opensearch_version}" } @@ -235,6 +244,9 @@ spotbugsTest { } test { + filter { + excludeTestsMatching "org.opensearch.security.sanity.tests.*" + } maxParallelForks = 3 jvmArgs += "-Xmx3072m" if (JavaVersion.current() > JavaVersion.VERSION_1_8) { @@ -402,4 +414,21 @@ task updateVersion { println "Setting version to ${newVersion}." ant.replaceregexp(file:'build.gradle', match: '"opensearch.version", "\\d.*"', replace: '"opensearch.version", "' + newVersion.tokenize('-')[0] + '-SNAPSHOT"', flags:'g', byline:true) } -} +} + +task integTestRemote(type: RestIntegTestTask) { + + systemProperty "tests.security.manager", "false" + systemProperty "user", System.getProperty("user") + systemProperty "password", System.getProperty("password") + systemProperty "https", System.getProperty("https") + systemProperty "security.enabled", "true" + + filter { + setIncludePatterns("org.opensearch.security.sanity.tests.*IT") + } +} + +integTestRemote.enabled = System.getProperty("tests.rest.cluster") != null +// should be updated appropriately, when we add integTests in future +integTest.enabled = false \ No newline at end of file diff --git a/integtest.sh b/integtest.sh new file mode 100755 index 0000000000..961b91299c --- /dev/null +++ b/integtest.sh @@ -0,0 +1,110 @@ +#!/bin/bash + +set -e + +function usage() { + echo "" + echo "This script is used to run integration tests for plugin installed on a remote OpenSearch/Dashboards cluster." + echo "--------------------------------------------------------------------------" + echo "Usage: $0 [args]" + echo "" + echo "Required arguments:" + echo "None" + echo "" + echo "Optional arguments:" + echo -e "-b BIND_ADDRESS\t, defaults to localhost | 127.0.0.1, can be changed to any IP or domain name for the cluster location." + echo -e "-p BIND_PORT\t, defaults to 9200, can be changed to any port for the cluster location." + echo -e "-s SECURITY_ENABLED\t(true | false), defaults to true. Specify the OpenSearch/Dashboards have security enabled or not." + echo -e "-c CREDENTIAL\t(usename:password), no defaults, effective when SECURITY_ENABLED=true." + echo -e "-h\tPrint this message." + echo -e "-v OPENSEARCH_VERSION\t, no defaults" + echo -e "-n SNAPSHOT\t, defaults to false" + echo -e "-m CLUSTER_NAME\t, defaults to docker-cluster" + echo -e "-u COMMON_UTILS_VERSION\t, defaults to 2.2.0.0" + echo "--------------------------------------------------------------------------" +} + +while getopts ":h:b:p:s:c:v:n:t:m:u:" arg; do + case $arg in + h) + usage + exit 1 + ;; + b) + BIND_ADDRESS=$OPTARG + ;; + p) + BIND_PORT=$OPTARG + ;; + t) + TRANSPORT_PORT=$OPTARG + ;; + s) + SECURITY_ENABLED=$OPTARG + ;; + c) + CREDENTIAL=$OPTARG + ;; + m) + CLUSTER_NAME=$OPTARG + ;; + v) + # Do nothing as we're not consuming this param. + ;; + n) + # Do nothing as we're not consuming this param. + ;; + u) + COMMON_UTILS_VERSION=$OPTARG + ;; + :) + echo "-${OPTARG} requires an argument" + usage + exit 1 + ;; + ?) + echo "Invalid option: -${OPTARG}" + exit 1 + ;; + esac +done + + +if [ -z "$BIND_ADDRESS" ] +then + BIND_ADDRESS="localhost" +fi + +if [ -z "$BIND_PORT" ] +then + BIND_PORT="9200" +fi + +if [ -z "$SECURITY_ENABLED" ] +then + SECURITY_ENABLED="true" +fi + +if [ -z "$CREDENTIAL" ] +then + CREDENTIAL="admin:admin" +fi + +if [ -z "$CREDENTIAL" ] +then + CREDENTIAL="admin:admin" +fi + +if [ -z "$CLUSTER_NAME" ] +then + CLUSTER_NAME="docker-cluster" +fi +if [ -z "$COMMON_UTILS_VERSION" ] +then + COMMON_UTILS_VERSION="2.2.0.0" +fi + +USERNAME=`echo $CREDENTIAL | awk -F ':' '{print $1}'` +PASSWORD=`echo $CREDENTIAL | awk -F ':' '{print $2}'` + +./gradlew integTestRemote -Dtests.rest.cluster="$BIND_ADDRESS:$BIND_PORT" -Dtests.cluster="$BIND_ADDRESS:$BIND_PORT" -Dsecurity_enabled=$SECURITY_ENABLED -Dtests.clustername=$CLUSTER_NAME -Dhttps=true -Duser=$USERNAME -Dpassword=$PASSWORD -Dcommon_utils.version=$COMMON_UTILS_VERSION diff --git a/src/test/java/org/opensearch/bootstrap/JarHell.java b/src/test/java/org/opensearch/bootstrap/JarHell.java new file mode 100644 index 0000000000..11978a780c --- /dev/null +++ b/src/test/java/org/opensearch/bootstrap/JarHell.java @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.bootstrap; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; + +/** + * Disable JarHell to unblock test development + * https://github.com/opensearch-project/security/issues/1938 + */ +public class JarHell { + private JarHell() {} + public static void checkJarHell(Consumer output) throws IOException, Exception {} + public static void checkJarHell(Set urls, Consumer output) throws URISyntaxException, IOException {} + public static void checkVersionFormat(String targetVersion) {} + public static void checkJavaVersion(String resource, String targetVersion) {} + public static Set parseClassPath() {return new HashSet();} +} diff --git a/src/test/java/org/opensearch/security/sanity/tests/SecurityRestTestCase.java b/src/test/java/org/opensearch/security/sanity/tests/SecurityRestTestCase.java new file mode 100644 index 0000000000..2418bd2194 --- /dev/null +++ b/src/test/java/org/opensearch/security/sanity/tests/SecurityRestTestCase.java @@ -0,0 +1,99 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.sanity.tests; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Map; + +import org.apache.http.HttpHost; + +import org.opensearch.client.Request; +import org.opensearch.client.Response; +import org.opensearch.client.RestClient; +import org.opensearch.client.RestClientBuilder; +import org.opensearch.common.io.PathUtils; +import org.opensearch.common.settings.Settings; +import org.opensearch.commons.rest.SecureRestClientBuilder; +import org.opensearch.test.rest.OpenSearchRestTestCase; + +import static org.opensearch.commons.ConfigConstants.OPENSEARCH_SECURITY_SSL_HTTP_ENABLED; +import static org.opensearch.commons.ConfigConstants.OPENSEARCH_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH; +import static org.opensearch.commons.ConfigConstants.OPENSEARCH_SECURITY_SSL_HTTP_KEYSTORE_KEYPASSWORD; +import static org.opensearch.commons.ConfigConstants.OPENSEARCH_SECURITY_SSL_HTTP_KEYSTORE_PASSWORD; +import static org.opensearch.commons.ConfigConstants.OPENSEARCH_SECURITY_SSL_HTTP_PEMCERT_FILEPATH; + +/** + * Overrides OpenSearchRestTestCase to fit the use-case for testing + * against remote cluster for Security Plugin. + * + * Modify this test class as needed + */ +@SuppressWarnings("unchecked") +public class SecurityRestTestCase extends OpenSearchRestTestCase { + + private static final String CERT_FILE_DIRECTORY = "sanity-tests/"; + private boolean isHttps() { + return System.getProperty("https").equals("true"); + } + private boolean securityEnabled() { + return System.getProperty("security.enabled").equals("true"); + } + + @Override + protected Settings restAdminSettings(){ + + return Settings + .builder() + .put("http.port", 9200) + .put(OPENSEARCH_SECURITY_SSL_HTTP_ENABLED, isHttps()) + .put(OPENSEARCH_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, CERT_FILE_DIRECTORY + "opensearch-node.pem") + .put("plugins.security.ssl.http.pemkey_filepath", CERT_FILE_DIRECTORY + "opensearch-node-key.pem") + .put("plugins.security.ssl.transport.pemtrustedcas_filepath", CERT_FILE_DIRECTORY + "root-ca.pem") + .put(OPENSEARCH_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH, CERT_FILE_DIRECTORY + "test-kirk.jks") + .put(OPENSEARCH_SECURITY_SSL_HTTP_KEYSTORE_PASSWORD, "changeit") + .put(OPENSEARCH_SECURITY_SSL_HTTP_KEYSTORE_KEYPASSWORD, "changeit") + .build(); + } + + @Override + protected RestClient buildClient(Settings settings, HttpHost[] hosts) throws IOException { + + if(securityEnabled()){ + String keystore = settings.get(OPENSEARCH_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH); + + if(keystore != null){ + // create adminDN (super-admin) client + File file = new File(getClass().getClassLoader().getResource(CERT_FILE_DIRECTORY).getFile()); + Path configPath = PathUtils.get(file.toURI()).getParent().toAbsolutePath(); + return new SecureRestClientBuilder(settings, configPath).setSocketTimeout(60000).build(); + } + + // create client with passed user + String userName = System.getProperty("user"); + String password = System.getProperty("password"); + return new SecureRestClientBuilder(hosts, isHttps(), userName, password).setSocketTimeout(60000).build(); + } + else { + RestClientBuilder builder = RestClient.builder(hosts); + configureClient(builder, settings); + builder.setStrictDeprecationMode(true); + return builder.build(); + } + } + + protected static Map getAsMapByAdmin(final String endpoint) throws IOException { + Response response = adminClient().performRequest(new Request("GET", endpoint)); + return responseAsMap(response); + } +} diff --git a/src/test/java/org/opensearch/security/sanity/tests/SingleClusterSanityIT.java b/src/test/java/org/opensearch/security/sanity/tests/SingleClusterSanityIT.java new file mode 100644 index 0000000000..c327687371 --- /dev/null +++ b/src/test/java/org/opensearch/security/sanity/tests/SingleClusterSanityIT.java @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.sanity.tests; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.hamcrest.MatcherAssert; +import org.junit.Test; + +import static org.hamcrest.Matchers.anEmptyMap; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + + +@SuppressWarnings("unchecked") +public class SingleClusterSanityIT extends SecurityRestTestCase { + + private static final String SECURITY_PLUGIN_NAME = "opensearch-security"; + + @Test + public void testSecurityPluginInstallation() throws Exception { + verifyPluginInstallationOnAllNodes(); + } + + private void verifyPluginInstallationOnAllNodes() throws Exception { + + Map> nodesInCluster = (Map>) getAsMapByAdmin("_nodes").get("nodes"); + + for (Map node : nodesInCluster.values()) { + + List> plugins = (List>) node.get("plugins"); + Set pluginNames = plugins.stream().map(map -> map.get("name")).collect(Collectors.toSet()); + + MatcherAssert.assertThat(pluginNames, contains(SECURITY_PLUGIN_NAME)); + } + MatcherAssert.assertThat(nodesInCluster, is(not(anEmptyMap()))); + } +} diff --git a/src/test/resources/sanity-tests/opensearch-node-key.pem b/src/test/resources/sanity-tests/opensearch-node-key.pem new file mode 100644 index 0000000000..4ac2cb57a7 --- /dev/null +++ b/src/test/resources/sanity-tests/opensearch-node-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCWvn+O+rywfgMC +ud24mAclMDfuNA/IzCKLxl5usIE/PvUm7PPfXQ14LfQhNQXqOuaD9fiVM+HO1BzK +wmN3j4g7eHInR1cxENoNGKFa0Fr9EXnUv8sfwyobPD8NTu9eaH7T+d6f9oow+Q4n +xb9Xin5IRR/pcJ8v7zEjcXpZaZejcSU4iVZ0PR2Di4H9rfe9SEyR5wLrsVBePB3L +jaL1uK4bZF3n/JGgDe3BNy1PgPU+O+FCzQipBBTyJWQCjd4iTRXVbMa01PglAR85 +O9w6NXApBLyWdGRY6dGd8vMC2P4KlhnxlcgPZdglKniGTX+eTzT7Rszq77zjYrou +PLwSh9S7AgMBAAECggEABwiohxFoEIwws8XcdKqTWsbfNTw0qFfuHLuK2Htf7IWR +htlzn66F3F+4jnwc5IsPCoVFriCXnsEC/usHHSMTZkL+gJqxlNaGdin6DXS/aiOQ +nb69SaQfqNmsz4ApZyxVDqsQGkK0vAhDAtQVU45gyhp/nLLmmqP8lPzMirOEodmp +U9bA8t/ttrzng7SVAER42f6IVpW0iTKTLyFii0WZbq+ObViyqib9hVFrI6NJuQS+ +IelcZB0KsSi6rqIjXg1XXyMiIUcSlhq+GfEa18AYgmsbPwMbExate7/8Ci7ZtCbh +lx9bves2+eeqq5EMm3sMHyhdcg61yzd5UYXeZhwJkQKBgQDS9YqrAtztvLY2gMgv +d+wOjb9awWxYbQTBjx33kf66W+pJ+2j8bI/XX2CpZ98w/oq8VhMqbr9j5b8MfsrF +EoQvedA4joUo8sXd4j1mR2qKF4/KLmkgy6YYusNP2UrVSw7sh77bzce+YaVVoO/e +0wIVTHuD/QZ6fG6MasOqcbl6hwKBgQC27cQruaHFEXR/16LrMVAX+HyEEv44KOCZ +ij5OE4P7F0twb+okngG26+OJV3BtqXf0ULlXJ+YGwXCRf6zUZkld3NMy3bbKPgH6 +H/nf3BxqS2tudj7+DV52jKtisBghdvtlKs56oc9AAuwOs37DvhptBKUPdzDDqfys +Qchv5JQdLQKBgERev+pcqy2Bk6xmYHrB6wdseS/4sByYeIoi0BuEfYH4eB4yFPx6 +UsQCbVl6CKPgWyZe3ydJbU37D8gE78KfFagtWoZ56j4zMF2RDUUwsB7BNCDamce/ +OL2bCeG/Erm98cBG3lxufOX+z47I8fTNfkdY2k8UmhzoZwurLm73HJ3RAoGBAKsp +6yamuXF2FbYRhUXgjHsBbTD/vJO72/yO2CGiLRpi/5mjfkjo99269trp0C8sJSub +5PBiSuADXFsoRgUv+HI1UAEGaCTwxFTQWrRWdtgW3d0sE2EQDVWL5kmfT9TwSeat +mSoyAYR5t3tCBNkPJhbgA7pm4mASzHQ50VyxWs25AoGBAKPFx9X2oKhYQa+mW541 +bbqRuGFMoXIIcr/aeM3LayfLETi48o5NDr2NDP11j4yYuz26YLH0Dj8aKpWuehuH +uB27n6j6qu0SVhQi6mMJBe1JrKbzhqMKQjYOoy8VsC2gdj5pCUP/kLQPW7zm9diX +CiKTtKgPIeYdigor7V3AHcVT +-----END PRIVATE KEY----- diff --git a/src/test/resources/sanity-tests/opensearch-node.pem b/src/test/resources/sanity-tests/opensearch-node.pem new file mode 100644 index 0000000000..7ba92534e4 --- /dev/null +++ b/src/test/resources/sanity-tests/opensearch-node.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEyTCCA7GgAwIBAgIGAWLrc1O2MA0GCSqGSIb3DQEBCwUAMIGPMRMwEQYKCZIm +iZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQ +RXhhbXBsZSBDb20gSW5jLjEhMB8GA1UECwwYRXhhbXBsZSBDb20gSW5jLiBSb290 +IENBMSEwHwYDVQQDDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0EwHhcNMTgwNDIy +MDM0MzQ3WhcNMjgwNDE5MDM0MzQ3WjBeMRIwEAYKCZImiZPyLGQBGRYCZGUxDTAL +BgNVBAcMBHRlc3QxDTALBgNVBAoMBG5vZGUxDTALBgNVBAsMBG5vZGUxGzAZBgNV +BAMMEm5vZGUtMC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAJa+f476vLB+AwK53biYByUwN+40D8jMIovGXm6wgT8+9Sbs899dDXgt +9CE1Beo65oP1+JUz4c7UHMrCY3ePiDt4cidHVzEQ2g0YoVrQWv0RedS/yx/DKhs8 +Pw1O715oftP53p/2ijD5DifFv1eKfkhFH+lwny/vMSNxellpl6NxJTiJVnQ9HYOL +gf2t971ITJHnAuuxUF48HcuNovW4rhtkXef8kaAN7cE3LU+A9T474ULNCKkEFPIl +ZAKN3iJNFdVsxrTU+CUBHzk73Do1cCkEvJZ0ZFjp0Z3y8wLY/gqWGfGVyA9l2CUq +eIZNf55PNPtGzOrvvONiui48vBKH1LsCAwEAAaOCAVkwggFVMIG8BgNVHSMEgbQw +gbGAFJI1DOAPHitF9k0583tfouYSl0BzoYGVpIGSMIGPMRMwEQYKCZImiZPyLGQB +GRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEZMBcGA1UECgwQRXhhbXBs +ZSBDb20gSW5jLjEhMB8GA1UECwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMSEw +HwYDVQQDDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0GCAQEwHQYDVR0OBBYEFKyv +78ZmFjVKM9g7pMConYH7FVBHMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXg +MCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA1BgNVHREELjAsiAUq +AwQFBYISbm9kZS0wLmV4YW1wbGUuY29tgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZI +hvcNAQELBQADggEBAIOKuyXsFfGv1hI/Lkpd/73QNqjqJdxQclX57GOMWNbOM5H0 +5/9AOIZ5JQsWULNKN77aHjLRr4owq2jGbpc/Z6kAd+eiatkcpnbtbGrhKpOtoEZy +8KuslwkeixpzLDNISSbkeLpXz4xJI1ETMN/VG8ZZP1bjzlHziHHDu0JNZ6TnNzKr +XzCGMCohFfem8vnKNnKUneMQMvXd3rzUaAgvtf7Hc2LTBlf4fZzZF1EkwdSXhaMA +1lkfHiqOBxtgeDLxCHESZ2fqgVqsWX+t3qHQfivcPW6txtDyrFPRdJOGhiMGzT/t +e/9kkAtQRgpTb3skYdIOOUOV0WGQ60kJlFhAzIs= +-----END CERTIFICATE----- diff --git a/src/test/resources/sanity-tests/root-ca.pem b/src/test/resources/sanity-tests/root-ca.pem new file mode 100644 index 0000000000..4015d866e1 --- /dev/null +++ b/src/test/resources/sanity-tests/root-ca.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk +ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w +bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh +MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDQyMjAzNDM0 +NloXDTI4MDQxOTAzNDM0NlowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ +kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw +HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w +bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK/u+GARP5innhpXK0c0q7s1Su1VTEaIgmZr8VWI6S8amf5cU3ktV7WT9SuV +TsAm2i2A5P+Ctw7iZkfnHWlsC3HhPUcd6mvzGZ4moxnamM7r+a9otRp3owYoGStX +ylVTQusAjbq9do8CMV4hcBTepCd+0w0v4h6UlXU8xjhj1xeUIz4DKbRgf36q0rv4 +VIX46X72rMJSETKOSxuwLkov1ZOVbfSlPaygXIxqsHVlj1iMkYRbQmaTib6XWHKf +MibDaqDejOhukkCjzpptGZOPFQ8002UtTTNv1TiaKxkjMQJNwz6jfZ53ws3fh1I0 +RWT6WfM4oeFRFnyFRmc4uYTUgAkCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAf +BgNVHSMEGDAWgBSSNQzgDx4rRfZNOfN7X6LmEpdAczAdBgNVHQ4EFgQUkjUM4A8e +K0X2TTnze1+i5hKXQHMwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB +AQBoQHvwsR34hGO2m8qVR9nQ5Klo5HYPyd6ySKNcT36OZ4AQfaCGsk+SecTi35QF +RHL3g2qffED4tKR0RBNGQSgiLavmHGCh3YpDupKq2xhhEeS9oBmQzxanFwWFod4T +nnsG2cCejyR9WXoRzHisw0KJWeuNlwjUdJY0xnn16srm1zL/M/f0PvCyh9HU1mF1 +ivnOSqbDD2Z7JSGyckgKad1Omsg/rr5XYtCeyJeXUPcmpeX6erWJJNTUh6yWC/hY +G/dFC4xrJhfXwz6Z0ytUygJO32bJG4Np2iGAwvvgI9EfxzEv/KP+FGrJOvQJAq4/ +BU36ZAa80W/8TBnqZTkNnqZV +-----END CERTIFICATE----- diff --git a/src/test/resources/sanity-tests/test-kirk.jks b/src/test/resources/sanity-tests/test-kirk.jks new file mode 100644 index 0000000000..174dbda656 Binary files /dev/null and b/src/test/resources/sanity-tests/test-kirk.jks differ