Skip to content

Commit

Permalink
run REST-tests with JKS & BCFKS keystores
Browse files Browse the repository at this point in the history
Signed-off-by: Iwan Igonin <iigonin@sternad.de>
  • Loading branch information
iigonin committed Feb 20, 2025
1 parent 55d6f6b commit 96524cf
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.plugins.jvm.JvmTestSuite;
Expand Down Expand Up @@ -87,6 +88,7 @@ public class TestingConventionsTasks extends DefaultTask {

private final NamedDomainObjectContainer<TestingConventionRule> naming;
private final Project project;
private final ConfigurableFileCollection extraClassPath = getProject().files();

@Inject
public TestingConventionsTasks(Project project) {
Expand Down Expand Up @@ -398,7 +400,16 @@ private boolean isAnnotated(Method method, Class<?> annotation) {

@Classpath
public FileCollection getTestsClassPath() {
return Util.getJavaTestSourceSet(project).get().getRuntimeClasspath();
return Util.getJavaTestSourceSet(project).get().getRuntimeClasspath().plus(extraClassPath);
}

@Classpath
public ConfigurableFileCollection getExtraClassPath() {
return extraClassPath;
}

public void addExtraClassPath(Object... paths) {
extraClassPath.from(paths);
}

private Map<String, File> walkPathAndLoadClasses(File testRoot) {
Expand Down
5 changes: 5 additions & 0 deletions client/rest/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
*/

import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis
import org.opensearch.gradle.precommit.TestingConventionsTasks

apply plugin: 'opensearch.build'
apply plugin: 'opensearch.publish'
Expand Down Expand Up @@ -222,3 +223,7 @@ tasks.withType(JavaCompile) {
tasks.withType(Test).configureEach {
classpath += files(project(':libs:opensearch-ssl-config').jar.archiveFile)
}

tasks.named("testingConventions", TestingConventionsTasks).configure {
addExtraClassPath(project(":libs:opensearch-ssl-config").jar.archiveFile)
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@
/**
* Integration test to validate the builder builds a client with the correct configuration
*/
public class RestClientBuilderIntegTests extends RestClientTestCase {
public class RestClientBuilderIntegTests extends RestClientTestCase implements RestClientFipsAwareTestCase {

private static HttpsServer httpsServer;

@BeforeClass
public static void startHttpServer() throws Exception {
httpsServer = HttpsServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
httpsServer.setHttpsConfigurator(new HttpsConfigurator(getSslContext(true)));
httpsServer.setHttpsConfigurator(new HttpsConfigurator(getSslContext(true, KeyStoreType.BCFKS)));
httpsServer.createContext("/", new ResponseHandler());
httpsServer.start();
}
Expand All @@ -93,6 +93,11 @@ public static void stopHttpServers() throws IOException {
}

public void testBuilderUsesDefaultSSLContext() throws Exception {
makeRequest();
}

@Override
public void makeRequest(KeyStoreType keyStoreType) throws Exception {
final SSLContext defaultSSLContext = SSLContext.getDefault();
try {
try (RestClient client = buildRestClient()) {
Expand All @@ -104,7 +109,7 @@ public void testBuilderUsesDefaultSSLContext() throws Exception {
}
}

SSLContext.setDefault(getSslContext(false));
SSLContext.setDefault(getSslContext(false, keyStoreType));
try (RestClient client = buildRestClient()) {
Response response = client.performRequest(new Request("GET", "/"));
assertEquals(200, response.getStatusLine().getStatusCode());
Expand All @@ -119,21 +124,22 @@ private RestClient buildRestClient() {
return RestClient.builder(new HttpHost("https", address.getHostString(), address.getPort())).build();
}

private static SSLContext getSslContext(boolean server) throws Exception {
private static SSLContext getSslContext(boolean server, KeyStoreType keyStoreType) throws Exception {
SSLContext sslContext;
char[] password = "password".toCharArray();
SecureRandom secureRandom = SecureRandom.getInstance("DEFAULT", "BCFIPS");
String fileExtension = KeyStoreType.TYPE_TO_EXTENSION_MAP.get(keyStoreType).get(0);

try (
InputStream trustStoreFile = RestClientBuilderIntegTests.class.getResourceAsStream("/test_truststore.bcfks");
InputStream keyStoreFile = RestClientBuilderIntegTests.class.getResourceAsStream("/testks.bcfks")
InputStream trustStoreFile = RestClientBuilderIntegTests.class.getResourceAsStream("/test_truststore" + fileExtension);
InputStream keyStoreFile = RestClientBuilderIntegTests.class.getResourceAsStream("/testks" + fileExtension)
) {
KeyStore keyStore = KeyStoreFactory.getInstance(KeyStoreType.BCFKS);
KeyStore keyStore = KeyStoreFactory.getInstance(keyStoreType);
keyStore.load(keyStoreFile, password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, password);

KeyStore trustStore = KeyStoreFactory.getInstance(KeyStoreType.BCFKS);
KeyStore trustStore = KeyStoreFactory.getInstance(keyStoreType);
trustStore.load(trustStoreFile, password);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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.
*/

package org.opensearch.client;

import org.opensearch.common.ssl.KeyStoreType;

import static org.opensearch.client.RestClientTestCase.inFipsJvm;

public interface RestClientFipsAwareTestCase {

default void makeRequest() throws Exception {
if (inFipsJvm()) {
makeRequest(KeyStoreType.BCFKS);
} else {
makeRequest(KeyStoreType.JKS);
}
}

void makeRequest(KeyStoreType keyStoreType) throws Exception;
}
Binary file not shown.
Binary file added client/rest/src/test/resources/testks.jks
Binary file not shown.
2 changes: 1 addition & 1 deletion client/test/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ dependencies {
api "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.randomizedrunner}"
api "junit:junit:${versions.junit}"
api "org.hamcrest:hamcrest:${versions.hamcrest}"
runtimeOnly "org.bouncycastle:bc-fips:${versions.bouncycastle_jce}"
api "org.bouncycastle:bc-fips:${versions.bouncycastle_jce}"
runtimeOnly "org.bouncycastle:bcutil-fips:${versions.bouncycastle_util}"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.carrotsearch.randomizedtesting.annotations.TimeoutSuite;

import org.apache.hc.core5.http.Header;
import org.bouncycastle.crypto.CryptoServicesRegistrar;

import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -116,6 +117,10 @@ protected static void assertHeaders(
assertTrue("some headers that were sent weren't returned " + expectedHeaders, expectedHeaders.isEmpty());
}

protected static boolean inFipsJvm() {
return CryptoServicesRegistrar.isInApprovedOnlyMode();
}

private static void addValueToListEntry(final Map<String, List<String>> map, final String name, final String value) {
List<String> values = map.get(name);
if (values == null) {
Expand Down
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ reactor-netty-http = { group = "io.projectreactor.netty", name = "reactor-netty-
roaringbitmap = { group = "org.roaringbitmap", name = "RoaringBitmap", version.ref = "roaringbitmap" }
spatial4j = { group = "org.locationtech.spatial4j", name = "spatial4j", version.ref = "spatial4j" }
tdigest = { group = "com.tdunning", name = "t-digest", version.ref = "tdigest" }
bcjce = { group = "org.bouncycastle", name = "bc-fips", version.ref = "bouncycastle_jce" }
bctls = { group = "org.bouncycastle", name = "bctls-fips", version.ref = "bouncycastle_tls" }
bcutil = { group = "org.bouncycastle", name = "bcutil-fips", version.ref = "bouncycastle_util" }

[bundles]
lucene = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

package org.opensearch.transport.netty4.ssl;

import org.apache.lucene.tests.util.LuceneTestCase;
import org.opensearch.Version;
import org.opensearch.cluster.node.DiscoveryNode;
import org.opensearch.common.network.NetworkService;
Expand Down Expand Up @@ -67,7 +66,6 @@
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.lessThanOrEqualTo;

@LuceneTestCase.AwaitsFix(bugUrl = "")
public class SimpleSecureNetty4TransportTests extends AbstractSimpleTransportTestCase {
@Override
protected Transport build(Settings settings, final Version version, ClusterSettings clusterSettings, boolean doHandshake) {
Expand All @@ -81,9 +79,11 @@ public Optional<TransportExceptionHandler> buildServerTransportExceptionHandler(
@Override
public Optional<SSLEngine> buildSecureServerTransportEngine(Settings settings, Transport transport) throws SSLException {
try {
final KeyStore keyStore = KeyStoreFactory.getInstance(KeyStoreType.JKS);
var keyStoreType = inFipsJvm() ? KeyStoreType.BCFKS : KeyStoreType.JKS;
var fileExtension = KeyStoreType.TYPE_TO_EXTENSION_MAP.get(keyStoreType).get(0);
final KeyStore keyStore = KeyStoreFactory.getInstance(keyStoreType);
keyStore.load(
SimpleSecureNetty4TransportTests.class.getResourceAsStream("/netty4-secure.jks"),
SimpleSecureNetty4TransportTests.class.getResourceAsStream("/netty4-secure" + fileExtension),
"password".toCharArray()
);

Expand Down
6 changes: 3 additions & 3 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ dependencies {
api libs.roaringbitmap

// bouncyCastle
api "org.bouncycastle:bc-fips:${versions.bouncycastle_jce}"
api "org.bouncycastle:bctls-fips:${versions.bouncycastle_tls}"
api "org.bouncycastle:bcutil-fips:${versions.bouncycastle_util}"
api libs.bcjce
api libs.bctls
api libs.bcutil

testImplementation 'org.awaitility:awaitility:4.2.2'
testImplementation(project(":test:framework")) {
Expand Down
38 changes: 18 additions & 20 deletions server/src/main/resources/org/opensearch/bootstrap/security.policy
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,6 @@ grant codeBase "${codebase.reactor-core}" {
permission java.net.SocketPermission "*", "connect,resolve";
};

// security
grant {
permission java.lang.RuntimePermission "accessClassInPackage.sun.security.internal.spec";
permission java.lang.RuntimePermission "accessDeclaredMembers";
permission java.lang.RuntimePermission "closeClassLoader";
permission java.lang.RuntimePermission "getProtectionDomain";
permission java.io.FilePermission "${java.home}/lib/security/cacerts", "read";
permission java.io.FilePermission "${java.home}/lib/security/jssecacerts", "read";
permission java.security.SecurityPermission "getProperty.jdk.certpath.disabledAlgorithms";
permission java.security.SecurityPermission "getProperty.jdk.tls.disabledAlgorithms";
permission java.security.SecurityPermission "getProperty.jdk.tls.server.defaultDHEParameters";
permission java.security.SecurityPermission "getProperty.keystore.type.compat";
permission java.security.SecurityPermission "getProperty.org.bouncycastle.*";
permission java.security.SecurityPermission "removeProvider.SunJCE";
permission java.util.PropertyPermission "java.runtime.name", "read";
permission org.bouncycastle.crypto.CryptoServicesPermission "defaultRandomConfig";
permission org.bouncycastle.crypto.CryptoServicesPermission "exportSecretKey";
permission org.bouncycastle.crypto.CryptoServicesPermission "exportPrivateKey";
};

//// Everything else:

grant {
Expand Down Expand Up @@ -215,4 +195,22 @@ grant {
permission java.io.FilePermission "/sys/fs/cgroup/cpuacct/-", "read";
permission java.io.FilePermission "/sys/fs/cgroup/memory", "read";
permission java.io.FilePermission "/sys/fs/cgroup/memory/-", "read";

// security
permission java.lang.RuntimePermission "accessClassInPackage.sun.security.internal.spec";
permission java.lang.RuntimePermission "accessDeclaredMembers";
permission java.lang.RuntimePermission "closeClassLoader";
permission java.lang.RuntimePermission "getProtectionDomain";
permission java.io.FilePermission "${java.home}/lib/security/cacerts", "read";
permission java.io.FilePermission "${java.home}/lib/security/jssecacerts", "read";
permission java.security.SecurityPermission "getProperty.jdk.certpath.disabledAlgorithms";
permission java.security.SecurityPermission "getProperty.jdk.tls.disabledAlgorithms";
permission java.security.SecurityPermission "getProperty.jdk.tls.server.defaultDHEParameters";
permission java.security.SecurityPermission "getProperty.keystore.type.compat";
permission java.security.SecurityPermission "getProperty.org.bouncycastle.*";
permission java.security.SecurityPermission "removeProvider.SunJCE";
permission java.util.PropertyPermission "java.runtime.name", "read";
permission org.bouncycastle.crypto.CryptoServicesPermission "defaultRandomConfig";
permission org.bouncycastle.crypto.CryptoServicesPermission "exportSecretKey";
permission org.bouncycastle.crypto.CryptoServicesPermission "exportPrivateKey";
};

0 comments on commit 96524cf

Please sign in to comment.