diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index 1bb61910ec..5a8fabbf3d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -202,7 +202,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i log.info("Edge RPC service initialized!"); } - private void setupSsl(NettyServerBuilder builder) throws Exception { + void setupSsl(NettyServerBuilder builder) throws Exception { PemSslCredentials credentials = new PemSslCredentials(); credentials.setCertFile(certFileResource); credentials.setKeyFile(StringUtils.isEmpty(privateKeyResource) ? null : privateKeyResource); diff --git a/application/src/test/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSslTest.java b/application/src/test/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSslTest.java index 4401738f5d..ed736ebdfb 100644 --- a/application/src/test/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSslTest.java +++ b/application/src/test/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSslTest.java @@ -20,22 +20,18 @@ import io.grpc.Server; import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; -import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; -import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder; -import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.util.io.pem.PemObject; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; -import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.transport.config.ssl.PemSslCredentials; +import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.server.gen.edge.v1.EdgeRpcServiceGrpc; import java.io.ByteArrayInputStream; @@ -59,13 +55,15 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.awaitility.Awaitility.await; /** - * Tests for Edge gRPC SSL setup using PemSslCredentials. - * Covers all test plan scenarios: - * 1. Separate cert and key files (existing behavior) - * 2. Combined PEM file (cert + key) - * 3. Encrypted private key + key_password - * 4. Error when combined PEM has no private key and private_key is empty - * 5. ECDSA P-384 key support + * Tests for Edge gRPC SSL setup using the production {@link EdgeGrpcService#setupSsl} method. + *
+ * Covers: + * 1. Separate cert and key PEM inputs + * 2. Combined PEM (cert + key in one file) + * 3. Encrypted private key with password + * 4. Missing key in combined PEM → error + *
+ * Each scenario is parameterized across key types: RSA-2048, RSA-4096, EC P-256, EC P-384. */ class EdgeGrpcSslTest { @@ -174,28 +172,25 @@ class EdgeGrpcSslTest { .isInstanceOf(IllegalArgumentException.class); } - // --- Helpers that mirror EdgeGrpcService.setupSsl() --- + // --- Server startup using production EdgeGrpcService.setupSsl() --- private Server startServer(String certFileResource, String privateKeyResource, String keyPassword) throws Exception { - PemSslCredentials credentials = new PemSslCredentials(); - credentials.setCertFile(certFileResource); - credentials.setKeyFile(StringUtils.isEmpty(privateKeyResource) ? null : privateKeyResource); - credentials.setKeyPassword(keyPassword); - credentials.init(false); - - SslContext sslContext = GrpcSslContexts.configure( - SslContextBuilder.forServer(credentials.createKeyManagerFactory())).build(); - - return NettyServerBuilder.forPort(0) - .sslContext(sslContext) - .addService(new EdgeRpcServiceGrpc.EdgeRpcServiceImplBase() {}) - .build() - .start(); + EdgeGrpcService edgeGrpcService = new EdgeGrpcService(); + ReflectionTestUtils.setField(edgeGrpcService, "certFileResource", certFileResource); + ReflectionTestUtils.setField(edgeGrpcService, "privateKeyResource", privateKeyResource); + ReflectionTestUtils.setField(edgeGrpcService, "keyPassword", keyPassword != null ? keyPassword : ""); + + NettyServerBuilder builder = NettyServerBuilder.forPort(0) + .addService(new EdgeRpcServiceGrpc.EdgeRpcServiceImplBase() {}); + + edgeGrpcService.setupSsl(builder); + + return builder.build().start(); } private void assertTlsConnectivity(X509Certificate trustedCert) throws Exception { String certPem = toPem(trustedCert); - SslContext clientSsl = GrpcSslContexts.forClient() + var clientSsl = GrpcSslContexts.forClient() .trustManager(new ByteArrayInputStream(certPem.getBytes(StandardCharsets.UTF_8))) .build();