Skip to content

Commit

Permalink
Correct initialization of SSL tunnel tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mirromutth committed Feb 13, 2024
1 parent 5def47e commit b0d00a0
Showing 1 changed file with 62 additions and 32 deletions.
94 changes: 62 additions & 32 deletions src/test/java/io/asyncer/r2dbc/mysql/SslTunnelIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package io.asyncer.r2dbc.mysql;


import io.asyncer.r2dbc.mysql.constant.SslMode;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
Expand All @@ -34,9 +33,13 @@
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.r2dbc.spi.ValidationDepth;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import javax.net.ssl.SSLException;
import java.net.InetSocketAddress;
Expand All @@ -53,6 +56,35 @@ public class SslTunnelIntegrationTest {

private SslTunnelServer sslTunnelServer;

@BeforeAll
static void initCachingSha2Password() {
// If the server uses caching_sha2_password, the first time a client connects to the server, the
// server will require a native SSL connection. So all the SSL tunnel tests should be run after
// the caching_sha2_password initialization.
String password = System.getProperty("test.mysql.password");

assertThat(password).withFailMessage("Property test.mysql.password must exists and not be empty")
.isNotNull()
.isNotEmpty();

MySqlConnectionConfiguration configuration = MySqlConnectionConfiguration.builder()
.host("localhost")
.port(3306)
.connectTimeout(Duration.ofSeconds(3))
.user("root")
.password(password)
.database("r2dbc")
.createDatabaseIfNotExist(true)
.build();

MySqlConnectionFactory.from(configuration).create()
.flatMap(connection -> connection.validate(ValidationDepth.REMOTE)
.flatMap(it -> connection.close().then(Mono.just(it))))
.as(StepVerifier::create)
.expectNext(true)
.verifyComplete();
}

@BeforeEach
void setUp() throws CertificateException, SSLException, InterruptedException {
server = new SelfSignedCertificate();
Expand All @@ -73,32 +105,30 @@ void tearDown() throws InterruptedException {
void sslTunnelConnectionTest() {
final String password = System.getProperty("test.mysql.password");
assertThat(password).withFailMessage("Property test.mysql.password must exists and not be empty")
.isNotNull()
.isNotEmpty();

final MySqlConnectionConfiguration configuration = MySqlConnectionConfiguration
.builder()
.host("localhost")
.port(sslTunnelServer.getLocalPort())
.connectTimeout(Duration.ofSeconds(3))
.user("root")
.password(password)
.database("r2dbc")
.createDatabaseIfNotExist(true)
.sslMode(SslMode.TUNNEL)
.sslKey(client.privateKey().getAbsolutePath())
.sslCert(client.certificate().getAbsolutePath())
.sslCa(server.certificate().getAbsolutePath())
.build();
.isNotNull()
.isNotEmpty();

final MySqlConnectionConfiguration configuration = MySqlConnectionConfiguration.builder()
.host("localhost")
.port(sslTunnelServer.getLocalPort())
.connectTimeout(Duration.ofSeconds(3))
.user("root")
.password(password)
.database("r2dbc")
.sslMode(SslMode.TUNNEL)
.sslKey(client.privateKey().getAbsolutePath())
.sslCert(client.certificate().getAbsolutePath())
.sslCa(server.certificate().getAbsolutePath())
.build();

final MySqlConnectionFactory connectionFactory = MySqlConnectionFactory.from(configuration);

final MySqlConnection connection = connectionFactory.create().block();
assert null != connection;
connection.createStatement("SELECT 3").execute()
.flatMap(it -> it.map((row, rowMetadata) -> row.get(0, Long.class)))
.doOnNext(it -> assertThat(it).isEqualTo(3L))
.blockLast();
.flatMap(it -> it.map((row, rowMetadata) -> row.get(0, Long.class)))
.doOnNext(it -> assertThat(it).isEqualTo(3L))
.blockLast();

connection.close().block();
}
Expand All @@ -113,7 +143,6 @@ private static class SslTunnelServer {

private volatile ChannelFuture channelFuture;


private SslTunnelServer(String remoteHost, int remotePort, SslContext sslContext) {
this.remoteHost = remoteHost;
this.remotePort = remotePort;
Expand All @@ -124,10 +153,10 @@ void setUp() throws InterruptedException {
// Configure the server.
ServerBootstrap b = new ServerBootstrap();
b.localAddress(0)
.group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(new ProxyInitializer(remoteHost, remotePort, sslContext))
.childOption(ChannelOption.AUTO_READ, false);
.group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(new ProxyInitializer(remoteHost, remotePort, sslContext))
.childOption(ChannelOption.AUTO_READ, false);

// Start the server.
channelFuture = b.bind().sync();
Expand All @@ -143,7 +172,6 @@ int getLocalPort() {

}


private static class ProxyInitializer extends ChannelInitializer<SocketChannel> {

private final String remoteHost;
Expand All @@ -168,10 +196,12 @@ public void initChannel(SocketChannel ch) {
private static class ProxyFrontendHandler extends ChannelInboundHandlerAdapter {

private final String remoteHost;

private final int remotePort;

// As we use inboundChannel.eventLoop() when building the Bootstrap this does not need to be volatile as
// the outboundChannel will use the same EventLoop (and therefore Thread) as the inboundChannel.
// As we use inboundChannel.eventLoop() when building the Bootstrap this does not need to be
// volatile as the outboundChannel will use the same EventLoop (and therefore Thread) as the
// inboundChannel.
private Channel outboundChannel;

private ProxyFrontendHandler(String remoteHost, int remotePort) {
Expand All @@ -186,9 +216,9 @@ public void channelActive(ChannelHandlerContext ctx) {
// Start the connection attempt.
Bootstrap b = new Bootstrap();
b.group(inboundChannel.eventLoop())
.channel(ctx.channel().getClass())
.handler(new ProxyBackendHandler(inboundChannel))
.option(ChannelOption.AUTO_READ, false);
.channel(ctx.channel().getClass())
.handler(new ProxyBackendHandler(inboundChannel))
.option(ChannelOption.AUTO_READ, false);
ChannelFuture f = b.connect(remoteHost, remotePort);
outboundChannel = f.channel();
f.addListener((ChannelFutureListener) future -> {
Expand Down

0 comments on commit b0d00a0

Please sign in to comment.