From 96524cfcdc6ff5bc2f3bbac9bdb515beac230b0c Mon Sep 17 00:00:00 2001 From: Iwan Igonin Date: Tue, 4 Feb 2025 15:08:57 +0100 Subject: [PATCH] run REST-tests with JKS & BCFKS keystores Signed-off-by: Iwan Igonin --- .../precommit/TestingConventionsTasks.java | 13 +++++- client/rest/build.gradle | 5 +++ .../client/RestClientBuilderIntegTests.java | 22 ++++++---- .../client/RestClientFipsAwareTestCase.java | 26 ++++++++++++ .../src/test/resources/test_truststore.jks | Bin 0 -> 1097 bytes client/rest/src/test/resources/testks.jks | Bin 0 -> 2381 bytes client/test/build.gradle | 2 +- .../opensearch/client/RestClientTestCase.java | 5 +++ gradle/libs.versions.toml | 3 ++ .../ssl/SimpleSecureNetty4TransportTests.java | 8 ++-- server/build.gradle | 6 +-- .../org/opensearch/bootstrap/security.policy | 38 +++++++++--------- 12 files changed, 91 insertions(+), 37 deletions(-) create mode 100644 client/rest/src/test/java/org/opensearch/client/RestClientFipsAwareTestCase.java create mode 100644 client/rest/src/test/resources/test_truststore.jks create mode 100644 client/rest/src/test/resources/testks.jks diff --git a/buildSrc/src/main/java/org/opensearch/gradle/precommit/TestingConventionsTasks.java b/buildSrc/src/main/java/org/opensearch/gradle/precommit/TestingConventionsTasks.java index 9c1285914a03e..d6812704fc8f3 100644 --- a/buildSrc/src/main/java/org/opensearch/gradle/precommit/TestingConventionsTasks.java +++ b/buildSrc/src/main/java/org/opensearch/gradle/precommit/TestingConventionsTasks.java @@ -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; @@ -87,6 +88,7 @@ public class TestingConventionsTasks extends DefaultTask { private final NamedDomainObjectContainer naming; private final Project project; + private final ConfigurableFileCollection extraClassPath = getProject().files(); @Inject public TestingConventionsTasks(Project project) { @@ -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 walkPathAndLoadClasses(File testRoot) { diff --git a/client/rest/build.gradle b/client/rest/build.gradle index d3955602360b6..fe950a8db8730 100644 --- a/client/rest/build.gradle +++ b/client/rest/build.gradle @@ -29,6 +29,7 @@ */ import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis +import org.opensearch.gradle.precommit.TestingConventionsTasks apply plugin: 'opensearch.build' apply plugin: 'opensearch.publish' @@ -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) +} diff --git a/client/rest/src/test/java/org/opensearch/client/RestClientBuilderIntegTests.java b/client/rest/src/test/java/org/opensearch/client/RestClientBuilderIntegTests.java index 82a37ac29b545..96b87be327e93 100644 --- a/client/rest/src/test/java/org/opensearch/client/RestClientBuilderIntegTests.java +++ b/client/rest/src/test/java/org/opensearch/client/RestClientBuilderIntegTests.java @@ -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(); } @@ -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()) { @@ -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()); @@ -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); diff --git a/client/rest/src/test/java/org/opensearch/client/RestClientFipsAwareTestCase.java b/client/rest/src/test/java/org/opensearch/client/RestClientFipsAwareTestCase.java new file mode 100644 index 0000000000000..2f8e4718da5f8 --- /dev/null +++ b/client/rest/src/test/java/org/opensearch/client/RestClientFipsAwareTestCase.java @@ -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; +} diff --git a/client/rest/src/test/resources/test_truststore.jks b/client/rest/src/test/resources/test_truststore.jks new file mode 100644 index 0000000000000000000000000000000000000000..d27635fec5040d63969f7d124d499fa1b4788d1b GIT binary patch literal 1097 zcmezO_TO6u1_mY|W(3pRB}JvhC8;UNsYN9~vAkwc`ArP05qhQumJAFmtOiXij0R0i zFBdQ~F)}f+SnhC6G2mt6)N1o+`_9YA$j!=NkZ#Crz{$oO%EBhh6dDZUa0oLwI~s}^ zh=63+g?WAROY=$+GxHR}GE>V91q}E=;#|V)sX2+oC7H>FyawDL5pH3YlGNf7Lm>kJ z5SLk)6U0@>%TGx)kQ3)MG&e9eG&eLeG%_`d66ZAnaZRCI`Z=VDQ3*K^7+D#Zn;7{S z44N3Zn3@9EiBm+{dKY&Mx?Dh3UI&DWy9-kNdy3Y1&zCVq0?3+gn8M zW^BmU&9hebbM`WL%SM>)H`p6)xX$#V^e3^_c|yKH+g&^_eww-4(bN0WeUHXpj<24| z8#s44{mgM{<-Ekjav*FHySkd1LILvkfpKRps}T$r5>2Z+690q z4;e5vapvSFC+1}27nd}N!kKztR!V*@FxfP5!G%ql#1U*{H6}=k%#akBAuBR7kOeu2 zk420{B!;(W5m!xu6HAtD?Gnzr*6g$93L!@ePE8)StWekcf6T@8>!Hn2u@bR@rlREmQe3 z*E!m4Dbw#AUFZ2b>f&VICND7KS>ox+=yy2j@n+^nCE4?htut-6e$*Az+UNcJvug@p zxy3{0kBJ}Or$o&-*t0S9IK#8deQaWSimx8m{Sg0s=1fG3q~-m^ZtGbxL!O1KZ8*=P zSUgEB^1BHS@5>phh28)F literal 0 HcmV?d00001 diff --git a/client/rest/src/test/resources/testks.jks b/client/rest/src/test/resources/testks.jks new file mode 100644 index 0000000000000000000000000000000000000000..cd706db5e3834f4b44493530bca17697f32d8de2 GIT binary patch literal 2381 zcmcgt`9IYA8vlOB80%QF%P^K4yYI*ll4T;A?8cHMVh&T*Y{!}zYjfo2&U*Xwz`-tYJ4{loKmp6B&EKURON0ssIz4)Cv__YA&G z3_fNKX6Ang002DBTG4J7uREh5mJ7*;DV;dAlA=s5+KPl4wULQJdoL8~Pe7D3^*Cpn+O9sr03 zISo5KN{!m#CIL0)yz>t}H?Dji7ewQeMTpah_;lIM9lfx^{MI46EY=H2Gb87zSV!L9 zBNwGc)hcRNP-{ZbigjTAb+b#asOW1;eDvzR6aB?nZ0b51o)HL=(P6?em8T=Dtimf@ zkw!zNEH-cfeLsno#O=RbxSvAmmq_5eGP;=CTVxI0y~COhkJiND1UdLS2Ol7#CcE^d zL>{Nth-L14Z4j+X`yfibe=ag4rVlxJp#US7Q|y@QX^G~`3fl?pyl5Y^R8rIQWW4Id zQ{z=r`vr-qyIpkx)5AVH*xUo_`4Nx4b(N?wT{OYbRG2-rcbCh$ubPg4`&+@r5D zzPUX@zCiejz)?}CTe3&^u7rVdbjjY6C5l@V4|cw6NVPj+>;MVdCH6G z;*UbVqziZ{8{q|$yRDA6AbU?YM#cWH7~gF>>!8r(I*ID&@IdyK9Vh)mhm9(9QprF* zTcmmB5ofTGhE^wgc6e}~gaOj0+F~@7M8SRe&>AqUy`aoNh?gL%tOLG=Z`F!b~nE6fm|g zn~sp%GU*wT?a;|Lx{14y5rz@Zi*Ei`1^Asfnk+f1QoG!rBKWDm!N)n4tjm$w;#(Ms z*y4S9lR%xR>-qfN9B<|yeOK)-bH747=ZNpA3?IQ6RWFHIE8SgO`efbu{fcV~?x(fP{fMBSHJgUi@HE~B!hGqp zOO=HE;j=bw>XQc_Lz$N7+B!oz5O}9z4>`!sl^^yX__= zt-G_fDHBHnrXd?sZVgtfT~YRfOVPRZGOfh@@i4+lcQw=8yf9tQpirKyrJ1>K}mXUYH+n6o>({TY+BG7mQ%>U&6=* z!|7mnA?}kO1}>zLcYv3_Gsz2WMIr`aIF6U>vChoJK=g3-^C!7rkPyp>!omgjC;Itg z&OjU|l#Yw(grdE?U5St|9}=SqsbW+yDi|fK%5^@Z(h0@>hyMQ(p@3qii*S4+=qMmN z08v0@7zG4@>`*WMc%Za&v|oF7I$+-EMoqJWYD_z76t$P8`b?SG)ttMjYum12Jk&V7 zsHmP6>E*Mnu22@bNiF7pFuY}Fi}583GKns-grfA-Wjf!$M+>b?2e(*eKQE{W(|_ zqzG@m_}u1gR1!=yj)8OGH|*MNL9vesbIH50(wEe#5QVStcy5LF4wl>1k4ux85&=BQ z2HOs`T4SDJht6*D#{Bb)k$L@P!=cU0W*tNP=9B^XyUy|_5eP@s-Sg0mVfsMlT$VO- z8v~;Q0kD8v1Cc8sa`JH>QJipc97K+egWo;Aws9QCLw5Rs6ebUE7iSN5Z$Ezu&)-nt zFXZa&c|0~0=D%fS3g7?mX^-+LlgcTR%4w4dggQxx4bBVawnyH{XAX1Hh2PQ)FJzj~ zV0fH;=5%9^r~A0EAmDBKU?@>M=V)d1wfsQ-HBPDx*3~(vs9PE7?jqurC(74^6*Ip;MfXd)H`2nLpdhX1nEE+M3Y~js@@+eX5olR{E5MTxf=!t-%Qh!Tb~aJm hJ4YDTZ?{bYj5Ah4y>@bn_^A>sIjjET5{u3>b{aXM4 literal 0 HcmV?d00001 diff --git a/client/test/build.gradle b/client/test/build.gradle index f877bcd08d773..afecaf685c51c 100644 --- a/client/test/build.gradle +++ b/client/test/build.gradle @@ -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}" } diff --git a/client/test/src/main/java/org/opensearch/client/RestClientTestCase.java b/client/test/src/main/java/org/opensearch/client/RestClientTestCase.java index 49ee3373a071e..9d52ee4cb3da7 100644 --- a/client/test/src/main/java/org/opensearch/client/RestClientTestCase.java +++ b/client/test/src/main/java/org/opensearch/client/RestClientTestCase.java @@ -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; @@ -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> map, final String name, final String value) { List values = map.get(name); if (values == null) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0eeecec69dba1..4e2532597cbfb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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 = [ diff --git a/modules/transport-netty4/src/test/java/org/opensearch/transport/netty4/ssl/SimpleSecureNetty4TransportTests.java b/modules/transport-netty4/src/test/java/org/opensearch/transport/netty4/ssl/SimpleSecureNetty4TransportTests.java index c4272e03d27b5..c938052d321ca 100644 --- a/modules/transport-netty4/src/test/java/org/opensearch/transport/netty4/ssl/SimpleSecureNetty4TransportTests.java +++ b/modules/transport-netty4/src/test/java/org/opensearch/transport/netty4/ssl/SimpleSecureNetty4TransportTests.java @@ -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; @@ -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) { @@ -81,9 +79,11 @@ public Optional buildServerTransportExceptionHandler( @Override public Optional 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() ); diff --git a/server/build.gradle b/server/build.gradle index 491489fd19092..eb2739bb64781 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -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")) { diff --git a/server/src/main/resources/org/opensearch/bootstrap/security.policy b/server/src/main/resources/org/opensearch/bootstrap/security.policy index 9c61ec1ddad27..7d416afa2bd24 100644 --- a/server/src/main/resources/org/opensearch/bootstrap/security.policy +++ b/server/src/main/resources/org/opensearch/bootstrap/security.policy @@ -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 { @@ -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"; };