Skip to content

Commit 7604e9c

Browse files
Create gRPC managed channel builder for ITs.
Signed-off-by: Finn Carroll <carrofin@amazon.com>
1 parent 6b12983 commit 7604e9c

File tree

5 files changed

+163
-93
lines changed

5 files changed

+163
-93
lines changed

src/integrationTest/java/org/opensearch/security/grpc/GrpcHelpers.java

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,33 @@
99
*/
1010
package org.opensearch.security.grpc;
1111

12+
import java.net.InetSocketAddress;
1213
import java.util.Map;
1314

14-
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
15+
import io.grpc.ManagedChannel;
1516
import io.netty.handler.ssl.ClientAuth;
16-
import org.junit.ClassRule;
17-
import org.junit.Test;
18-
import org.junit.runner.RunWith;
1917

18+
import org.opensearch.common.transport.PortsRange;
19+
import org.opensearch.core.common.transport.TransportAddress;
2020
import org.opensearch.plugin.transport.grpc.GrpcPlugin;
21+
import org.opensearch.protobufs.BulkRequest;
22+
import org.opensearch.protobufs.BulkRequestBody;
23+
import org.opensearch.protobufs.BulkResponse;
24+
import org.opensearch.protobufs.IndexOperation;
2125
import org.opensearch.protobufs.MatchAllQuery;
2226
import org.opensearch.protobufs.QueryContainer;
2327
import org.opensearch.protobufs.SearchRequest;
2428
import org.opensearch.protobufs.SearchRequestBody;
2529
import org.opensearch.protobufs.SearchResponse;
30+
import org.opensearch.protobufs.services.DocumentServiceGrpc;
31+
import org.opensearch.protobufs.services.SearchServiceGrpc;
2632
import org.opensearch.security.support.ConfigConstants;
2733
import org.opensearch.test.framework.certificate.TestCertificates;
2834
import org.opensearch.test.framework.cluster.ClusterManager;
2935
import org.opensearch.test.framework.cluster.LocalCluster;
30-
import org.opensearch.test.framework.cluster.TestGrpcClient;
31-
import org.opensearch.test.framework.cluster.TestRestClient;
3236

33-
import static org.hamcrest.MatcherAssert.assertThat;
37+
import javax.net.ssl.SSLException;
38+
3439
import static org.opensearch.plugin.transport.grpc.ssl.SecureNetty4GrpcServerTransport.GRPC_SECURE_TRANSPORT_SETTING_KEY;
3540
import static org.opensearch.plugin.transport.grpc.ssl.SecureNetty4GrpcServerTransport.SETTING_GRPC_SECURE_PORT;
3641
import static org.opensearch.security.ssl.util.SSLConfigConstants.SECURITY_SSL_AUX_CLIENTAUTH_MODE;
@@ -46,10 +51,12 @@ public class GrpcHelpers {
4651
protected static final Map<String, Object> CLIENT_AUTH_OPT = Map.of(SECURITY_SSL_AUX_CLIENTAUTH_MODE.getConcreteSettingForNamespace(GRPC_SECURE_TRANSPORT_SETTING_KEY).getKey(), ClientAuth.OPTIONAL.name());
4752
protected static final Map<String, Object> CLIENT_AUTH_REQUIRE = Map.of(SECURITY_SSL_AUX_CLIENTAUTH_MODE.getConcreteSettingForNamespace(GRPC_SECURE_TRANSPORT_SETTING_KEY).getKey(), ClientAuth.REQUIRE.name());
4853

54+
private static final PortsRange PORTS_RANGE = new PortsRange("9400-9500");
55+
private static final String HOST_ADDR = "127.0.0.1";
4956
private static final Map<String, Object> SECURE_GRPC_TRANSPORT_SETTINGS = Map.of(
5057
ConfigConstants.SECURITY_SSL_ONLY, true,
5158
AUX_TRANSPORT_TYPES_KEY, GRPC_SECURE_TRANSPORT_SETTING_KEY,
52-
SETTING_GRPC_SECURE_PORT.getKey(), "9400-9500",
59+
SETTING_GRPC_SECURE_PORT.getKey(), PORTS_RANGE.getPortRangeString(),
5360
SECURITY_SSL_AUX_ENABLED.getConcreteSettingForNamespace(GRPC_SECURE_TRANSPORT_SETTING_KEY).getKey(), true,
5461
SECURITY_SSL_AUX_PEMKEY_FILEPATH.getConcreteSettingForNamespace(GRPC_SECURE_TRANSPORT_SETTING_KEY).getKey(), TEST_CERTIFICATES.getNodeKey(0, null).getAbsolutePath(),
5562
SECURITY_SSL_AUX_PEMCERT_FILEPATH.getConcreteSettingForNamespace(GRPC_SECURE_TRANSPORT_SETTING_KEY).getKey(), TEST_CERTIFICATES.getNodeCertificate(0).getAbsolutePath(),
@@ -66,19 +73,60 @@ public static LocalCluster.Builder baseGrpcCluster(){
6673
.sslOnly(true);
6774
}
6875

69-
public static void createTestIndex(TestRestClient client, String index, long numDocs) {
70-
try (client) {
71-
client.put(index).assertStatusCode(200);
72-
for (int i = 0; i < numDocs; i++) {
73-
String docURI = index + "/_doc/" + i;
74-
String docBody = "{\"field\": \"doc " + i + " body\"}";
75-
client.postJson(docURI, docBody)
76-
.assertStatusCode(201);
77-
}
76+
public static ManagedChannel plaintextManagedChannel() throws SSLException {
77+
return new NettyGrpcChannelBuilder()
78+
.setAddress(new TransportAddress(new InetSocketAddress(HOST_ADDR, PORTS_RANGE.ports()[0])))
79+
.build();
80+
}
81+
82+
public static ManagedChannel noAuthChannel() throws SSLException {
83+
return new NettyGrpcChannelBuilder()
84+
.setAddress(new TransportAddress(new InetSocketAddress(HOST_ADDR, PORTS_RANGE.ports()[0])))
85+
.clientAuth(ClientAuth.NONE)
86+
.build();
87+
}
88+
89+
public static ManagedChannel optAuthChannel() throws SSLException {
90+
return new NettyGrpcChannelBuilder()
91+
.setAddress(new TransportAddress(new InetSocketAddress(HOST_ADDR, PORTS_RANGE.ports()[0])))
92+
.clientAuth(ClientAuth.OPTIONAL)
93+
.keyManager(
94+
TEST_CERTIFICATES.getNodeKey(0, null).getAbsolutePath(),
95+
TEST_CERTIFICATES.getNodeCertificate(0).getAbsolutePath()
96+
)
97+
.build();
98+
}
99+
100+
public static ManagedChannel requireAuthChannel() throws SSLException {
101+
return new NettyGrpcChannelBuilder()
102+
.setAddress(new TransportAddress(new InetSocketAddress(HOST_ADDR, PORTS_RANGE.ports()[0])))
103+
.clientAuth(ClientAuth.REQUIRE)
104+
.keyManager(
105+
TEST_CERTIFICATES.getNodeKey(0, null).getAbsolutePath(),
106+
TEST_CERTIFICATES.getNodeCertificate(0).getAbsolutePath()
107+
)
108+
.build();
109+
}
110+
111+
public static BulkResponse doBulk(ManagedChannel channel, String index, long numDocs) {
112+
BulkRequest.Builder requestBuilder = BulkRequest.newBuilder();
113+
for (int i = 0; i < numDocs; i++) {
114+
String docBody = "{\"field\": \"doc " + i + " body\"}";
115+
IndexOperation indexOp = IndexOperation.newBuilder()
116+
.setIndex(index)
117+
.setId(String.valueOf(i))
118+
.build();
119+
BulkRequestBody requestBody = BulkRequestBody.newBuilder()
120+
.setIndex(indexOp)
121+
.setDoc(com.google.protobuf.ByteString.copyFromUtf8(docBody))
122+
.build();
123+
requestBuilder.addRequestBody(requestBody);
78124
}
125+
DocumentServiceGrpc.DocumentServiceBlockingStub stub = DocumentServiceGrpc.newBlockingStub(channel);
126+
return stub.bulk(requestBuilder.build());
79127
}
80128

81-
protected static SearchResponse grpcMatchAllQuery(TestGrpcClient client, String index, int size) {
129+
public static SearchResponse doMatchAll(ManagedChannel channel, String index, int size) {
82130
QueryContainer query = QueryContainer.newBuilder()
83131
.setMatchAll(MatchAllQuery.newBuilder().build())
84132
.build();
@@ -91,6 +139,7 @@ protected static SearchResponse grpcMatchAllQuery(TestGrpcClient client, String
91139
.addIndex(index)
92140
.setRequestBody(requestBody)
93141
.build();
94-
return client.search(searchRequest);
142+
SearchServiceGrpc.SearchServiceBlockingStub stub = SearchServiceGrpc.newBlockingStub(channel);
143+
return stub.search(searchRequest);
95144
}
96145
}

src/integrationTest/java/org/opensearch/security/grpc/GrpcTestsClientAuthOptionalTest.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313
import org.junit.ClassRule;
1414
import org.junit.Test;
1515
import org.junit.runner.RunWith;
16+
import org.opensearch.protobufs.BulkResponse;
1617
import org.opensearch.protobufs.SearchResponse;
1718
import org.opensearch.test.framework.cluster.LocalCluster;
1819

20+
import javax.net.ssl.SSLException;
21+
1922
import static org.hamcrest.MatcherAssert.assertThat;
2023
import static org.opensearch.security.grpc.GrpcHelpers.CLIENT_AUTH_OPT;
2124
import static org.opensearch.security.grpc.GrpcHelpers.TEST_CERTIFICATES;
@@ -30,15 +33,19 @@ public class GrpcTestsClientAuthOptionalTest {
3033
.build();
3134

3235
@Test
33-
public void testSearch() {
36+
public void testSearch() throws SSLException {
3437
long testDocs = 9;
3538
String testIndex = "test-index";
36-
GrpcHelpers.createTestIndex(cluster.getRestClient(), testIndex, testDocs);
37-
SearchResponse resp = GrpcHelpers.grpcMatchAllQuery(cluster.getGrpcClient(TEST_CERTIFICATES), testIndex, 100);
39+
BulkResponse bulkResp = GrpcHelpers.doBulk(GrpcHelpers.plaintextManagedChannel(), testIndex, testDocs);
40+
41+
42+
43+
44+
SearchResponse searchResp = GrpcHelpers.doMatchAll(GrpcHelpers.plaintextManagedChannel(), testIndex, 100);
3845
assertThat("Search response should not be null", resp != null);
39-
SearchResponse.ResponseCase respCase = resp.getResponseCase();
46+
SearchResponse.ResponseCase respCase = searchResp.getResponseCase();
4047
assertThat("Search response should indicate success", respCase.getNumber() == SearchResponse.ResponseCase.RESPONSE_BODY.getNumber());
41-
long hits = resp.getResponseBody().getHits().getTotal().getTotalHits().getValue();
48+
long hits = searchResp.getResponseBody().getHits().getTotal().getTotalHits().getValue();
4249
assertThat("Search response has correct hits count", hits == 9);
4350
}
4451
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package org.opensearch.security.grpc;
2+
3+
import javax.net.ssl.SSLException;
4+
import java.io.File;
5+
6+
import io.netty.handler.ssl.ClientAuth;
7+
8+
import io.grpc.ManagedChannel;
9+
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
10+
import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolConfig;
11+
import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolNames;
12+
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder;
13+
import io.grpc.netty.shaded.io.netty.handler.ssl.SslProvider;
14+
import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory;
15+
16+
import org.opensearch.core.common.transport.TransportAddress;
17+
18+
import static io.grpc.internal.GrpcUtil.NOOP_PROXY_DETECTOR;
19+
20+
public class NettyGrpcChannelBuilder {
21+
private ClientAuth clientAuth = null;
22+
private TransportAddress addr;
23+
SslContextBuilder sslContextBuilder = null;
24+
25+
private static final ApplicationProtocolConfig CLIENT_ALPN = new ApplicationProtocolConfig(
26+
ApplicationProtocolConfig.Protocol.ALPN,
27+
ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
28+
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
29+
ApplicationProtocolNames.HTTP_2
30+
);
31+
32+
NettyGrpcChannelBuilder() {
33+
// Default options required for gRPC clients
34+
this.sslContextBuilder = SslContextBuilder.forClient()
35+
.sslProvider(SslProvider.JDK)
36+
.applicationProtocolConfig(CLIENT_ALPN)
37+
.trustManager(InsecureTrustManagerFactory.INSTANCE);
38+
}
39+
40+
public ManagedChannel build() throws SSLException {
41+
NettyChannelBuilder channelBuilder = NettyChannelBuilder
42+
.forAddress(addr.getAddress(), addr.getPort())
43+
.proxyDetector(NOOP_PROXY_DETECTOR);
44+
45+
if (clientAuth == null) {
46+
return channelBuilder.usePlaintext().build();
47+
}
48+
49+
switch (clientAuth) {
50+
case ClientAuth.NONE -> channelBuilder.usePlaintext();
51+
case ClientAuth.OPTIONAL, ClientAuth.REQUIRE ->
52+
channelBuilder.sslContext(this.sslContextBuilder.build());
53+
}
54+
55+
return channelBuilder.build();
56+
}
57+
58+
/**
59+
* Set server address.
60+
*/
61+
public NettyGrpcChannelBuilder setAddress(TransportAddress addr) {
62+
this.addr = addr;
63+
return this;
64+
}
65+
66+
/**
67+
* Configure key store by filepath of .pem key.
68+
* Required for mTLS/client auth required configurations.
69+
*/
70+
public NettyGrpcChannelBuilder keyManager(String privateKeyPath, String certChainPath) {
71+
this.sslContextBuilder.keyManager(new File(certChainPath), new File(privateKeyPath));
72+
return this;
73+
}
74+
75+
/**
76+
* Set client auth mode.
77+
* No client auth set gives plaintext connection.
78+
*/
79+
public NettyGrpcChannelBuilder clientAuth(ClientAuth clientAuth) {
80+
this.clientAuth = clientAuth;
81+
return this;
82+
}
83+
}

src/integrationTest/java/org/opensearch/test/framework/cluster/OpenSearchClientProvider.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,6 @@ default TestRestClient getRestClient(List<Header> headers, CertificateData useCe
232232
return createGenericClientRestClient(headers, useCertificateData, null);
233233
}
234234

235-
default TestGrpcClient getGrpcClient(TestCertificates testCertificates) {
236-
return createGenericClientGrpcClient(testCertificates);
237-
}
238-
239235
default TestRestClient getSecurityDisabledRestClient() {
240236
return new TestRestClient(getHttpAddress(), List.of(), getSSLContext(null), null, false, false);
241237
}
@@ -248,10 +244,6 @@ default TestRestClient createGenericClientRestClient(
248244
return new TestRestClient(getHttpAddress(), headers, getSSLContext(useCertificateData), sourceInetAddress, true, false);
249245
}
250246

251-
default TestGrpcClient createGenericClientGrpcClient(TestCertificates testCertificates) {
252-
return new TestGrpcClient(getHttpAddress(), "", getSSLContext(), testCertificates);
253-
}
254-
255247
default TestRestClient createGenericClientRestClient(TestRestClientConfiguration configuration) {
256248
return new TestRestClient(
257249
getHttpAddress(),

src/integrationTest/java/org/opensearch/test/framework/cluster/TestGrpcClient.java

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)