mirror of https://github.com/dapr/java-sdk.git
Feat Add TLS & mTLS support for gRPC with root CA and insecure mode (#1361)
* feat: Support for GRPC ssl Signed-off-by: Javier Aliaga <javier@diagrid.io> * add tests Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * fix CI Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * add back else if Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * channel cleanup Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * add root ca support Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * checkstyles Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * add insecure Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * fix checkstyles Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * use InsecureTrustManagerFactory Signed-off-by: Cassandra Coyle <cassie@diagrid.io> * fix test Signed-off-by: Cassandra Coyle <cassie@diagrid.io> --------- Signed-off-by: Javier Aliaga <javier@diagrid.io> Signed-off-by: Cassandra Coyle <cassie@diagrid.io> Co-authored-by: Javier Aliaga <javier@diagrid.io>
This commit is contained in:
parent
551d205b1d
commit
daf4c8b703
17
sdk/pom.xml
17
sdk/pom.xml
|
@ -132,6 +132,23 @@
|
||||||
<artifactId>assertj-core</artifactId>
|
<artifactId>assertj-core</artifactId>
|
||||||
<version>${assertj.version}</version>
|
<version>${assertj.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
<version>1.70</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcpkix-jdk15on</artifactId>
|
||||||
|
<version>1.70</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-netty-shaded</artifactId>
|
||||||
|
<version>${grpc.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -102,6 +102,41 @@ public class Properties {
|
||||||
"DAPR_GRPC_PORT",
|
"DAPR_GRPC_PORT",
|
||||||
DEFAULT_GRPC_PORT);
|
DEFAULT_GRPC_PORT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GRPC TLS cert path for Dapr after checking system property and environment variable.
|
||||||
|
*/
|
||||||
|
public static final Property<String> GRPC_TLS_CERT_PATH = new StringProperty(
|
||||||
|
"dapr.grpc.tls.cert.path",
|
||||||
|
"DAPR_GRPC_TLS_CERT_PATH",
|
||||||
|
null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GRPC TLS key path for Dapr after checking system property and environment variable.
|
||||||
|
*/
|
||||||
|
public static final Property<String> GRPC_TLS_KEY_PATH = new StringProperty(
|
||||||
|
"dapr.grpc.tls.key.path",
|
||||||
|
"DAPR_GRPC_TLS_KEY_PATH",
|
||||||
|
null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GRPC TLS CA cert path for Dapr after checking system property and environment variable.
|
||||||
|
* This is used for TLS connections to servers with self-signed certificates.
|
||||||
|
*/
|
||||||
|
public static final Property<String> GRPC_TLS_CA_PATH = new StringProperty(
|
||||||
|
"dapr.grpc.tls.ca.path",
|
||||||
|
"DAPR_GRPC_TLS_CA_PATH",
|
||||||
|
null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use insecure TLS mode which still uses TLS but doesn't verify certificates.
|
||||||
|
* This uses InsecureTrustManagerFactory to trust all certificates.
|
||||||
|
* This should only be used for testing or in secure environments.
|
||||||
|
*/
|
||||||
|
public static final Property<Boolean> GRPC_TLS_INSECURE = new BooleanProperty(
|
||||||
|
"dapr.grpc.tls.insecure",
|
||||||
|
"DAPR_GRPC_TLS_INSECURE",
|
||||||
|
false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GRPC endpoint for remote sidecar connectivity.
|
* GRPC endpoint for remote sidecar connectivity.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -14,11 +14,21 @@ limitations under the License.
|
||||||
package io.dapr.utils;
|
package io.dapr.utils;
|
||||||
|
|
||||||
import io.dapr.config.Properties;
|
import io.dapr.config.Properties;
|
||||||
|
import io.dapr.exceptions.DaprError;
|
||||||
|
import io.dapr.exceptions.DaprException;
|
||||||
|
import io.grpc.ChannelCredentials;
|
||||||
import io.grpc.ClientInterceptor;
|
import io.grpc.ClientInterceptor;
|
||||||
|
import io.grpc.Grpc;
|
||||||
import io.grpc.ManagedChannel;
|
import io.grpc.ManagedChannel;
|
||||||
import io.grpc.ManagedChannelBuilder;
|
import io.grpc.ManagedChannelBuilder;
|
||||||
|
import io.grpc.TlsChannelCredentials;
|
||||||
|
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
|
||||||
|
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
|
||||||
|
import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
@ -26,9 +36,12 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static io.dapr.config.Properties.GRPC_ENDPOINT;
|
import static io.dapr.config.Properties.GRPC_ENDPOINT;
|
||||||
import static io.dapr.config.Properties.GRPC_PORT;
|
import static io.dapr.config.Properties.GRPC_PORT;
|
||||||
|
import static io.dapr.config.Properties.GRPC_TLS_CA_PATH;
|
||||||
|
import static io.dapr.config.Properties.GRPC_TLS_CERT_PATH;
|
||||||
|
import static io.dapr.config.Properties.GRPC_TLS_INSECURE;
|
||||||
|
import static io.dapr.config.Properties.GRPC_TLS_KEY_PATH;
|
||||||
import static io.dapr.config.Properties.SIDECAR_IP;
|
import static io.dapr.config.Properties.SIDECAR_IP;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for network, internal to Dapr SDK.
|
* Utility methods for network, internal to Dapr SDK.
|
||||||
*/
|
*/
|
||||||
|
@ -56,19 +69,20 @@ public final class NetworkUtils {
|
||||||
private static final String GRPC_ENDPOINT_HOSTNAME_REGEX_PART = "(([A-Za-z0-9_\\-\\.]+)|(\\[" + IPV6_REGEX + "\\]))";
|
private static final String GRPC_ENDPOINT_HOSTNAME_REGEX_PART = "(([A-Za-z0-9_\\-\\.]+)|(\\[" + IPV6_REGEX + "\\]))";
|
||||||
|
|
||||||
private static final String GRPC_ENDPOINT_DNS_AUTHORITY_REGEX_PART =
|
private static final String GRPC_ENDPOINT_DNS_AUTHORITY_REGEX_PART =
|
||||||
"(?<dnsWithAuthority>dns://)(?<authorityEndpoint>" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ":[0-9]+)?/";
|
"(?<dnsWithAuthority>dns://)(?<authorityEndpoint>"
|
||||||
|
+ GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ":[0-9]+)?/";
|
||||||
|
|
||||||
private static final String GRPC_ENDPOINT_PARAM_REGEX_PART = "(\\?(?<param>tls\\=((true)|(false))))?";
|
private static final String GRPC_ENDPOINT_PARAM_REGEX_PART = "(\\?(?<param>tls\\=((true)|(false))))?";
|
||||||
|
|
||||||
private static final String GRPC_ENDPOINT_SOCKET_REGEX_PART =
|
private static final String GRPC_ENDPOINT_SOCKET_REGEX_PART = "(?<socket>((unix:)|(unix://)|(unix-abstract:))"
|
||||||
"(?<socket>((unix:)|(unix://)|(unix-abstract:))" + GRPC_ENDPOINT_FILENAME_REGEX_PART + ")";
|
+ GRPC_ENDPOINT_FILENAME_REGEX_PART + ")";
|
||||||
|
|
||||||
private static final String GRPC_ENDPOINT_VSOCKET_REGEX_PART =
|
private static final String GRPC_ENDPOINT_VSOCKET_REGEX_PART = "(?<vsocket>vsock:" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART
|
||||||
"(?<vsocket>vsock:" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ":[0-9]+)";
|
+ ":[0-9]+)";
|
||||||
private static final String GRPC_ENDPOINT_HOST_REGEX_PART =
|
private static final String GRPC_ENDPOINT_HOST_REGEX_PART = "((?<http>http://)|(?<https>https://)|(?<dns>dns:)|("
|
||||||
"((?<http>http://)|(?<https>https://)|(?<dns>dns:)|(" + GRPC_ENDPOINT_DNS_AUTHORITY_REGEX_PART + "))?"
|
+ GRPC_ENDPOINT_DNS_AUTHORITY_REGEX_PART + "))?"
|
||||||
+ "(?<hostname>" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ")?+"
|
+ "(?<hostname>" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ")?+"
|
||||||
+ "(:(?<port>[0-9]+))?";
|
+ "(:(?<port>[0-9]+))?";
|
||||||
|
|
||||||
private static final String GRPC_ENDPOINT_REGEX = "^("
|
private static final String GRPC_ENDPOINT_REGEX = "^("
|
||||||
+ "(" + GRPC_ENDPOINT_HOST_REGEX_PART + ")|"
|
+ "(" + GRPC_ENDPOINT_HOST_REGEX_PART + ")|"
|
||||||
|
@ -107,17 +121,76 @@ public final class NetworkUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a GRPC managed channel.
|
* Creates a GRPC managed channel.
|
||||||
* @param properties instance to set up the GrpcEndpoint
|
*
|
||||||
|
* @param properties instance to set up the GrpcEndpoint
|
||||||
* @param interceptors Optional interceptors to add to the channel.
|
* @param interceptors Optional interceptors to add to the channel.
|
||||||
* @return GRPC managed channel to communicate with the sidecar.
|
* @return GRPC managed channel to communicate with the sidecar.
|
||||||
*/
|
*/
|
||||||
public static ManagedChannel buildGrpcManagedChannel(Properties properties, ClientInterceptor... interceptors) {
|
public static ManagedChannel buildGrpcManagedChannel(Properties properties, ClientInterceptor... interceptors) {
|
||||||
var settings = GrpcEndpointSettings.parse(properties);
|
var settings = GrpcEndpointSettings.parse(properties);
|
||||||
ManagedChannelBuilder<?> builder = ManagedChannelBuilder.forTarget(settings.endpoint)
|
|
||||||
.userAgent(Version.getSdkVersion());
|
boolean insecureTls = properties.getValue(GRPC_TLS_INSECURE);
|
||||||
if (!settings.secure) {
|
if (insecureTls) {
|
||||||
|
try {
|
||||||
|
ManagedChannelBuilder<?> builder = NettyChannelBuilder.forTarget(settings.endpoint)
|
||||||
|
.sslContext(GrpcSslContexts.forClient()
|
||||||
|
.trustManager(InsecureTrustManagerFactory.INSTANCE)
|
||||||
|
.build());
|
||||||
|
builder.userAgent(Version.getSdkVersion());
|
||||||
|
if (interceptors != null && interceptors.length > 0) {
|
||||||
|
builder = builder.intercept(interceptors);
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new DaprException(
|
||||||
|
new DaprError().setErrorCode("TLS_CREDENTIALS_ERROR")
|
||||||
|
.setMessage("Failed to create insecure TLS credentials"), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String clientKeyPath = settings.tlsPrivateKeyPath;
|
||||||
|
String clientCertPath = settings.tlsCertPath;
|
||||||
|
String caCertPath = settings.tlsCaPath;
|
||||||
|
|
||||||
|
ManagedChannelBuilder<?> builder = ManagedChannelBuilder.forTarget(settings.endpoint);
|
||||||
|
|
||||||
|
if (clientCertPath != null && clientKeyPath != null) {
|
||||||
|
// mTLS case - using client cert and key, with optional CA cert for server authentication
|
||||||
|
try (
|
||||||
|
InputStream clientCertInputStream = new FileInputStream(clientCertPath);
|
||||||
|
InputStream clientKeyInputStream = new FileInputStream(clientKeyPath);
|
||||||
|
InputStream caCertInputStream = caCertPath != null ? new FileInputStream(caCertPath) : null
|
||||||
|
) {
|
||||||
|
TlsChannelCredentials.Builder builderCreds = TlsChannelCredentials.newBuilder()
|
||||||
|
.keyManager(clientCertInputStream, clientKeyInputStream); // For client authentication
|
||||||
|
if (caCertInputStream != null) {
|
||||||
|
builderCreds.trustManager(caCertInputStream); // For server authentication
|
||||||
|
}
|
||||||
|
ChannelCredentials credentials = builderCreds.build();
|
||||||
|
builder = Grpc.newChannelBuilder(settings.endpoint, credentials);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new DaprException(
|
||||||
|
new DaprError().setErrorCode("TLS_CREDENTIALS_ERROR")
|
||||||
|
.setMessage("Failed to create mTLS credentials" + (caCertPath != null ? " with CA cert" : "")), e);
|
||||||
|
}
|
||||||
|
} else if (caCertPath != null) {
|
||||||
|
// Simple TLS case - using CA cert only for server authentication
|
||||||
|
try (InputStream caCertInputStream = new FileInputStream(caCertPath)) {
|
||||||
|
ChannelCredentials credentials = TlsChannelCredentials.newBuilder()
|
||||||
|
.trustManager(caCertInputStream)
|
||||||
|
.build();
|
||||||
|
builder = Grpc.newChannelBuilder(settings.endpoint, credentials);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new DaprException(
|
||||||
|
new DaprError().setErrorCode("TLS_CREDENTIALS_ERROR")
|
||||||
|
.setMessage("Failed to create TLS credentials with CA cert"), e);
|
||||||
|
}
|
||||||
|
} else if (!settings.secure) {
|
||||||
builder = builder.usePlaintext();
|
builder = builder.usePlaintext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.userAgent(Version.getSdkVersion());
|
||||||
|
|
||||||
if (interceptors != null && interceptors.length > 0) {
|
if (interceptors != null && interceptors.length > 0) {
|
||||||
builder = builder.intercept(interceptors);
|
builder = builder.intercept(interceptors);
|
||||||
}
|
}
|
||||||
|
@ -128,15 +201,26 @@ public final class NetworkUtils {
|
||||||
static final class GrpcEndpointSettings {
|
static final class GrpcEndpointSettings {
|
||||||
final String endpoint;
|
final String endpoint;
|
||||||
final boolean secure;
|
final boolean secure;
|
||||||
|
final String tlsPrivateKeyPath;
|
||||||
|
final String tlsCertPath;
|
||||||
|
final String tlsCaPath;
|
||||||
|
|
||||||
private GrpcEndpointSettings(String endpoint, boolean secure) {
|
private GrpcEndpointSettings(
|
||||||
|
String endpoint, boolean secure, String tlsPrivateKeyPath, String tlsCertPath, String tlsCaPath) {
|
||||||
this.endpoint = endpoint;
|
this.endpoint = endpoint;
|
||||||
this.secure = secure;
|
this.secure = secure;
|
||||||
|
this.tlsPrivateKeyPath = tlsPrivateKeyPath;
|
||||||
|
this.tlsCertPath = tlsCertPath;
|
||||||
|
this.tlsCaPath = tlsCaPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GrpcEndpointSettings parse(Properties properties) {
|
static GrpcEndpointSettings parse(Properties properties) {
|
||||||
String address = properties.getValue(SIDECAR_IP);
|
String address = properties.getValue(SIDECAR_IP);
|
||||||
int port = properties.getValue(GRPC_PORT);
|
int port = properties.getValue(GRPC_PORT);
|
||||||
|
String clientKeyPath = properties.getValue(GRPC_TLS_KEY_PATH);
|
||||||
|
String clientCertPath = properties.getValue(GRPC_TLS_CERT_PATH);
|
||||||
|
String caCertPath = properties.getValue(GRPC_TLS_CA_PATH);
|
||||||
|
|
||||||
boolean secure = false;
|
boolean secure = false;
|
||||||
String grpcEndpoint = properties.getValue(GRPC_ENDPOINT);
|
String grpcEndpoint = properties.getValue(GRPC_ENDPOINT);
|
||||||
if ((grpcEndpoint != null) && !grpcEndpoint.isEmpty()) {
|
if ((grpcEndpoint != null) && !grpcEndpoint.isEmpty()) {
|
||||||
|
@ -172,21 +256,31 @@ public final class NetworkUtils {
|
||||||
|
|
||||||
var authorityEndpoint = matcher.group("authorityEndpoint");
|
var authorityEndpoint = matcher.group("authorityEndpoint");
|
||||||
if (authorityEndpoint != null) {
|
if (authorityEndpoint != null) {
|
||||||
return new GrpcEndpointSettings(String.format("dns://%s/%s:%d", authorityEndpoint, address, port), secure);
|
return new GrpcEndpointSettings(
|
||||||
|
String.format(
|
||||||
|
"dns://%s/%s:%d",
|
||||||
|
authorityEndpoint,
|
||||||
|
address,
|
||||||
|
port
|
||||||
|
), secure, clientKeyPath, clientCertPath, caCertPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
var socket = matcher.group("socket");
|
var socket = matcher.group("socket");
|
||||||
if (socket != null) {
|
if (socket != null) {
|
||||||
return new GrpcEndpointSettings(socket, secure);
|
return new GrpcEndpointSettings(socket, secure, clientKeyPath, clientCertPath, caCertPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
var vsocket = matcher.group("vsocket");
|
var vsocket = matcher.group("vsocket");
|
||||||
if (vsocket != null) {
|
if (vsocket != null) {
|
||||||
return new GrpcEndpointSettings(vsocket, secure);
|
return new GrpcEndpointSettings(vsocket, secure, clientKeyPath, clientCertPath, caCertPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GrpcEndpointSettings(String.format("dns:///%s:%d", address, port), secure);
|
return new GrpcEndpointSettings(String.format(
|
||||||
|
"dns:///%s:%d",
|
||||||
|
address,
|
||||||
|
port
|
||||||
|
), secure, clientKeyPath, clientCertPath, caCertPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Dapr Authors
|
||||||
|
* Licensed 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 sppecific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package io.dapr.utils;
|
package io.dapr.utils;
|
||||||
|
|
||||||
import io.dapr.config.Properties;
|
import io.dapr.config.Properties;
|
||||||
|
import io.dapr.exceptions.DaprException;
|
||||||
import io.grpc.ManagedChannel;
|
import io.grpc.ManagedChannel;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Assumptions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||||
|
import org.junit.jupiter.api.condition.OS;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
|
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||||
|
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||||
|
import org.bouncycastle.operator.ContentSigner;
|
||||||
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||||
|
|
||||||
public class NetworkUtilsTest {
|
public class NetworkUtilsTest {
|
||||||
private final int defaultGrpcPort = 50001;
|
private final int defaultGrpcPort = 50001;
|
||||||
private final String defaultSidecarIP = "127.0.0.1";
|
private final String defaultSidecarIP = "127.0.0.1";
|
||||||
private ManagedChannel channel;
|
private ManagedChannel channel;
|
||||||
|
private static final List<ManagedChannel> channels = new ArrayList<>();
|
||||||
|
|
||||||
|
// Helper method to generate a self-signed certificate for testing
|
||||||
|
private static KeyPair generateKeyPair() throws Exception {
|
||||||
|
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||||
|
keyPairGenerator.initialize(2048);
|
||||||
|
return keyPairGenerator.generateKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static X509Certificate generateCertificate(KeyPair keyPair) throws Exception {
|
||||||
|
X500Name issuer = new X500Name("CN=Test Certificate");
|
||||||
|
X500Name subject = new X500Name("CN=Test Certificate");
|
||||||
|
Date notBefore = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
|
||||||
|
Date notAfter = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000L);
|
||||||
|
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
|
||||||
|
X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(
|
||||||
|
issuer,
|
||||||
|
java.math.BigInteger.valueOf(System.currentTimeMillis()),
|
||||||
|
notBefore,
|
||||||
|
notAfter,
|
||||||
|
subject,
|
||||||
|
publicKeyInfo
|
||||||
|
);
|
||||||
|
|
||||||
|
ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate());
|
||||||
|
X509Certificate cert = new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer));
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeCertificateToFile(X509Certificate cert, File file) throws Exception {
|
||||||
|
String certPem = "-----BEGIN CERTIFICATE-----\n" +
|
||||||
|
java.util.Base64.getEncoder().encodeToString(cert.getEncoded()) +
|
||||||
|
"\n-----END CERTIFICATE-----";
|
||||||
|
Files.write(file.toPath(), certPem.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writePrivateKeyToFile(KeyPair keyPair, File file) throws Exception {
|
||||||
|
String keyPem = "-----BEGIN PRIVATE KEY-----\n" +
|
||||||
|
java.util.Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()) +
|
||||||
|
"\n-----END PRIVATE KEY-----";
|
||||||
|
Files.write(file.toPath(), keyPem.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
|
@ -22,9 +95,20 @@ public class NetworkUtilsTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public static void tearDownAll() {
|
||||||
|
for (ManagedChannel ch : channels) {
|
||||||
|
if (ch != null && !ch.isShutdown()) {
|
||||||
|
ch.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
channels.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBuildGrpcManagedChannel() {
|
public void testBuildGrpcManagedChannel() {
|
||||||
channel = NetworkUtils.buildGrpcManagedChannel(new Properties());
|
channel = NetworkUtils.buildGrpcManagedChannel(new Properties());
|
||||||
|
channels.add(channel);
|
||||||
|
|
||||||
String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort);
|
String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort);
|
||||||
Assertions.assertEquals(expectedAuthority, channel.authority());
|
Assertions.assertEquals(expectedAuthority, channel.authority());
|
||||||
|
@ -34,6 +118,7 @@ public class NetworkUtilsTest {
|
||||||
public void testBuildGrpcManagedChannel_httpEndpointNoPort() {
|
public void testBuildGrpcManagedChannel_httpEndpointNoPort() {
|
||||||
var properties = new Properties(Map.of(Properties.GRPC_ENDPOINT.getName(), "http://example.com"));
|
var properties = new Properties(Map.of(Properties.GRPC_ENDPOINT.getName(), "http://example.com"));
|
||||||
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
|
||||||
String expectedAuthority = "example.com:80";
|
String expectedAuthority = "example.com:80";
|
||||||
Assertions.assertEquals(expectedAuthority, channel.authority());
|
Assertions.assertEquals(expectedAuthority, channel.authority());
|
||||||
|
@ -43,6 +128,7 @@ public class NetworkUtilsTest {
|
||||||
public void testBuildGrpcManagedChannel_httpEndpointWithPort() {
|
public void testBuildGrpcManagedChannel_httpEndpointWithPort() {
|
||||||
var properties = new Properties(Map.of(Properties.GRPC_ENDPOINT.getName(), "http://example.com:3000"));
|
var properties = new Properties(Map.of(Properties.GRPC_ENDPOINT.getName(), "http://example.com:3000"));
|
||||||
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
|
||||||
String expectedAuthority = "example.com:3000";
|
String expectedAuthority = "example.com:3000";
|
||||||
Assertions.assertEquals(expectedAuthority, channel.authority());
|
Assertions.assertEquals(expectedAuthority, channel.authority());
|
||||||
|
@ -52,6 +138,7 @@ public class NetworkUtilsTest {
|
||||||
public void testBuildGrpcManagedChannel_httpsEndpointNoPort() {
|
public void testBuildGrpcManagedChannel_httpsEndpointNoPort() {
|
||||||
var properties = new Properties(Map.of(Properties.GRPC_ENDPOINT.getName(), "https://example.com"));
|
var properties = new Properties(Map.of(Properties.GRPC_ENDPOINT.getName(), "https://example.com"));
|
||||||
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
|
||||||
String expectedAuthority = "example.com:443";
|
String expectedAuthority = "example.com:443";
|
||||||
Assertions.assertEquals(expectedAuthority, channel.authority());
|
Assertions.assertEquals(expectedAuthority, channel.authority());
|
||||||
|
@ -61,11 +148,236 @@ public class NetworkUtilsTest {
|
||||||
public void testBuildGrpcManagedChannel_httpsEndpointWithPort() {
|
public void testBuildGrpcManagedChannel_httpsEndpointWithPort() {
|
||||||
var properties = new Properties(Map.of(Properties.GRPC_ENDPOINT.getName(), "https://example.com:3000"));
|
var properties = new Properties(Map.of(Properties.GRPC_ENDPOINT.getName(), "https://example.com:3000"));
|
||||||
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
|
||||||
String expectedAuthority = "example.com:3000";
|
String expectedAuthority = "example.com:3000";
|
||||||
Assertions.assertEquals(expectedAuthority, channel.authority());
|
Assertions.assertEquals(expectedAuthority, channel.authority());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithTls() throws Exception {
|
||||||
|
// Generate test certificate and key
|
||||||
|
KeyPair keyPair = generateKeyPair();
|
||||||
|
X509Certificate cert = generateCertificate(keyPair);
|
||||||
|
|
||||||
|
File certFile = File.createTempFile("test-cert", ".pem");
|
||||||
|
File keyFile = File.createTempFile("test-key", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(cert, certFile);
|
||||||
|
writePrivateKeyToFile(keyPair, keyFile);
|
||||||
|
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath()
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort);
|
||||||
|
Assertions.assertEquals(expectedAuthority, channel.authority());
|
||||||
|
} finally {
|
||||||
|
certFile.delete();
|
||||||
|
keyFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithTlsAndEndpoint() throws Exception {
|
||||||
|
// Generate test certificate and key
|
||||||
|
KeyPair keyPair = generateKeyPair();
|
||||||
|
X509Certificate cert = generateCertificate(keyPair);
|
||||||
|
|
||||||
|
File certFile = File.createTempFile("test-cert", ".pem");
|
||||||
|
File keyFile = File.createTempFile("test-key", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(cert, certFile);
|
||||||
|
writePrivateKeyToFile(keyPair, keyFile);
|
||||||
|
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_ENDPOINT.getName(), "https://example.com:443"
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
Assertions.assertEquals("example.com:443", channel.authority());
|
||||||
|
} finally {
|
||||||
|
certFile.delete();
|
||||||
|
keyFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithInvalidTlsCert() {
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CERT_PATH.getName(), "/nonexistent/cert.pem",
|
||||||
|
Properties.GRPC_TLS_KEY_PATH.getName(), "/nonexistent/key.pem"
|
||||||
|
));
|
||||||
|
|
||||||
|
Assertions.assertThrows(DaprException.class, () -> {
|
||||||
|
NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnabledOnOs({OS.LINUX, OS.MAC}) // Unix domain sockets are only supported on Linux and macOS
|
||||||
|
public void testBuildGrpcManagedChannelWithTlsAndUnixSocket() throws Exception {
|
||||||
|
// Skip test if Unix domain sockets are not supported
|
||||||
|
Assumptions.assumeTrue(System.getProperty("os.name").toLowerCase().contains("linux") ||
|
||||||
|
System.getProperty("os.name").toLowerCase().contains("mac"));
|
||||||
|
|
||||||
|
// Generate test certificate and key
|
||||||
|
KeyPair keyPair = generateKeyPair();
|
||||||
|
X509Certificate cert = generateCertificate(keyPair);
|
||||||
|
|
||||||
|
File certFile = File.createTempFile("test-cert", ".pem");
|
||||||
|
File keyFile = File.createTempFile("test-key", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(cert, certFile);
|
||||||
|
writePrivateKeyToFile(keyPair, keyFile);
|
||||||
|
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_ENDPOINT.getName(), "unix:/tmp/test.sock"
|
||||||
|
));
|
||||||
|
|
||||||
|
// For Unix sockets, we expect an exception if the platform doesn't support it
|
||||||
|
try {
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
// If we get here, Unix sockets are supported
|
||||||
|
Assertions.assertNotNull(channel.authority(), "Channel authority should not be null");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// If we get here, Unix sockets are not supported
|
||||||
|
Assertions.assertTrue(e.getMessage().contains("DomainSocketAddress"));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
certFile.delete();
|
||||||
|
keyFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithTlsAndDnsAuthority() throws Exception {
|
||||||
|
// Generate test certificate and key
|
||||||
|
KeyPair keyPair = generateKeyPair();
|
||||||
|
X509Certificate cert = generateCertificate(keyPair);
|
||||||
|
|
||||||
|
File certFile = File.createTempFile("test-cert", ".pem");
|
||||||
|
File keyFile = File.createTempFile("test-key", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(cert, certFile);
|
||||||
|
writePrivateKeyToFile(keyPair, keyFile);
|
||||||
|
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CERT_PATH.getName(), certFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_TLS_KEY_PATH.getName(), keyFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_ENDPOINT.getName(), "dns://authority:53/example.com:443"
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
Assertions.assertEquals("example.com:443", channel.authority());
|
||||||
|
} finally {
|
||||||
|
certFile.delete();
|
||||||
|
keyFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithTlsAndCaCert() throws Exception {
|
||||||
|
// Generate test CA certificate
|
||||||
|
KeyPair caKeyPair = generateKeyPair();
|
||||||
|
X509Certificate caCert = generateCertificate(caKeyPair);
|
||||||
|
|
||||||
|
File caCertFile = File.createTempFile("test-ca-cert", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(caCert, caCertFile);
|
||||||
|
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath()
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort);
|
||||||
|
Assertions.assertEquals(expectedAuthority, channel.authority());
|
||||||
|
} finally {
|
||||||
|
caCertFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithTlsAndCaCertAndEndpoint() throws Exception {
|
||||||
|
// Generate test CA certificate
|
||||||
|
KeyPair caKeyPair = generateKeyPair();
|
||||||
|
X509Certificate caCert = generateCertificate(caKeyPair);
|
||||||
|
|
||||||
|
File caCertFile = File.createTempFile("test-ca-cert", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(caCert, caCertFile);
|
||||||
|
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_ENDPOINT.getName(), "https://example.com:443"
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
Assertions.assertEquals("example.com:443", channel.authority());
|
||||||
|
} finally {
|
||||||
|
caCertFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithInvalidCaCert() {
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CA_PATH.getName(), "/nonexistent/ca.pem"
|
||||||
|
));
|
||||||
|
|
||||||
|
Assertions.assertThrows(DaprException.class, () -> {
|
||||||
|
NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithMtlsAndCaCert() throws Exception {
|
||||||
|
// Generate test certificates
|
||||||
|
KeyPair caKeyPair = generateKeyPair();
|
||||||
|
X509Certificate caCert = generateCertificate(caKeyPair);
|
||||||
|
KeyPair clientKeyPair = generateKeyPair();
|
||||||
|
X509Certificate clientCert = generateCertificate(clientKeyPair);
|
||||||
|
|
||||||
|
File caCertFile = File.createTempFile("test-ca-cert", ".pem");
|
||||||
|
File clientCertFile = File.createTempFile("test-client-cert", ".pem");
|
||||||
|
File clientKeyFile = File.createTempFile("test-client-key", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(caCert, caCertFile);
|
||||||
|
writeCertificateToFile(clientCert, clientCertFile);
|
||||||
|
writePrivateKeyToFile(clientKeyPair, clientKeyFile);
|
||||||
|
|
||||||
|
// Test mTLS with both client certs and CA cert
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_TLS_CERT_PATH.getName(), clientCertFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_TLS_KEY_PATH.getName(), clientKeyFile.getAbsolutePath()
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
String expectedAuthority = String.format("%s:%s", defaultSidecarIP, defaultGrpcPort);
|
||||||
|
Assertions.assertEquals(expectedAuthority, channel.authority());
|
||||||
|
Assertions.assertFalse(channel.isTerminated(), "Channel should be active");
|
||||||
|
} finally {
|
||||||
|
caCertFile.delete();
|
||||||
|
clientCertFile.delete();
|
||||||
|
clientKeyFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGrpcEndpointParsing() {
|
public void testGrpcEndpointParsing() {
|
||||||
testGrpcEndpointParsingScenario(":5000", "dns:///127.0.0.1:5000", false);
|
testGrpcEndpointParsingScenario(":5000", "dns:///127.0.0.1:5000", false);
|
||||||
|
@ -146,4 +458,137 @@ public class NetworkUtilsTest {
|
||||||
// Expected
|
// Expected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithCaCertAndUnixSocket() throws Exception {
|
||||||
|
// Skip test if Unix domain sockets are not supported
|
||||||
|
Assumptions.assumeTrue(System.getProperty("os.name").toLowerCase().contains("linux") ||
|
||||||
|
System.getProperty("os.name").toLowerCase().contains("mac"));
|
||||||
|
|
||||||
|
// Generate test CA certificate
|
||||||
|
KeyPair caKeyPair = generateKeyPair();
|
||||||
|
X509Certificate caCert = generateCertificate(caKeyPair);
|
||||||
|
|
||||||
|
File caCertFile = File.createTempFile("test-ca-cert", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(caCert, caCertFile);
|
||||||
|
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_ENDPOINT.getName(), "unix:/tmp/test.sock"
|
||||||
|
));
|
||||||
|
|
||||||
|
// For Unix sockets, we expect an exception if the platform doesn't support it
|
||||||
|
try {
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
Assertions.assertNotNull(channel.authority(), "Channel authority should not be null");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// If we get here, Unix sockets are not supported
|
||||||
|
Assertions.assertTrue(e.getMessage().contains("DomainSocketAddress"));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
caCertFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithCaCertAndDnsAuthority() throws Exception {
|
||||||
|
// Generate test CA certificate
|
||||||
|
KeyPair caKeyPair = generateKeyPair();
|
||||||
|
X509Certificate caCert = generateCertificate(caKeyPair);
|
||||||
|
|
||||||
|
File caCertFile = File.createTempFile("test-ca-cert", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(caCert, caCertFile);
|
||||||
|
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_ENDPOINT.getName(), "dns://authority:53/example.com:443"
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
Assertions.assertEquals("example.com:443", channel.authority());
|
||||||
|
} finally {
|
||||||
|
caCertFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithInsecureTls() throws Exception {
|
||||||
|
// Test insecure TLS mode with a secure endpoint
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_INSECURE.getName(), "true",
|
||||||
|
Properties.GRPC_ENDPOINT.getName(), "dns:///example.com:443?tls=true"
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
|
||||||
|
// Verify the channel is created with the correct authority
|
||||||
|
Assertions.assertEquals("example.com:443", channel.authority());
|
||||||
|
|
||||||
|
// Verify the channel is active and using TLS (not plaintext)
|
||||||
|
Assertions.assertFalse(channel.isTerminated(), "Channel should be active");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithInsecureTlsAndMtls() throws Exception {
|
||||||
|
// Generate test certificates
|
||||||
|
KeyPair caKeyPair = generateKeyPair();
|
||||||
|
X509Certificate caCert = generateCertificate(caKeyPair);
|
||||||
|
KeyPair clientKeyPair = generateKeyPair();
|
||||||
|
X509Certificate clientCert = generateCertificate(clientKeyPair);
|
||||||
|
|
||||||
|
File caCertFile = File.createTempFile("test-ca-cert", ".pem");
|
||||||
|
File clientCertFile = File.createTempFile("test-client-cert", ".pem");
|
||||||
|
File clientKeyFile = File.createTempFile("test-client-key", ".pem");
|
||||||
|
try {
|
||||||
|
writeCertificateToFile(caCert, caCertFile);
|
||||||
|
writeCertificateToFile(clientCert, clientCertFile);
|
||||||
|
writePrivateKeyToFile(clientKeyPair, clientKeyFile);
|
||||||
|
|
||||||
|
// Test that insecure TLS still works with mTLS settings
|
||||||
|
// The client certs should be ignored since we're using InsecureTrustManagerFactory
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_INSECURE.getName(), "true",
|
||||||
|
Properties.GRPC_TLS_CA_PATH.getName(), caCertFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_TLS_CERT_PATH.getName(), clientCertFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_TLS_KEY_PATH.getName(), clientKeyFile.getAbsolutePath(),
|
||||||
|
Properties.GRPC_ENDPOINT.getName(), "dns:///example.com:443?tls=true"
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
|
||||||
|
// Verify the channel is created with the correct authority
|
||||||
|
Assertions.assertEquals("example.com:443", channel.authority());
|
||||||
|
|
||||||
|
// Verify the channel is active and using TLS (not plaintext)
|
||||||
|
Assertions.assertFalse(channel.isTerminated(), "Channel should be active");
|
||||||
|
} finally {
|
||||||
|
caCertFile.delete();
|
||||||
|
clientCertFile.delete();
|
||||||
|
clientKeyFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildGrpcManagedChannelWithInsecureTlsAndCustomEndpoint() throws Exception {
|
||||||
|
// Test insecure TLS with a custom endpoint that would normally require TLS
|
||||||
|
var properties = new Properties(Map.of(
|
||||||
|
Properties.GRPC_TLS_INSECURE.getName(), "true",
|
||||||
|
Properties.GRPC_ENDPOINT.getName(), "dns://authority:53/example.com:443?tls=true"
|
||||||
|
));
|
||||||
|
|
||||||
|
channel = NetworkUtils.buildGrpcManagedChannel(properties);
|
||||||
|
channels.add(channel);
|
||||||
|
|
||||||
|
// Verify the channel is created with the correct authority
|
||||||
|
Assertions.assertEquals("example.com:443", channel.authority());
|
||||||
|
|
||||||
|
// Verify the channel is active and using TLS (not plaintext)
|
||||||
|
Assertions.assertFalse(channel.isTerminated(), "Channel should be active");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue