Skip to content

Commit

Permalink
SSL / BlockHound works out of the box with the default SSL provider (n…
Browse files Browse the repository at this point in the history
…etty#9969)

Motivation:

JDK is the default SSL provider and internally uses blocking IO operations.

Modifications:

Add allowBlockingCallsInside configuration for SslHandler runAllDelegate function.

Result:

When BlockHound is installed, SSL works out of the box with the default SSL provider.


Co-authored-by: violetagg <[email protected]>
  • Loading branch information
johnou and violetagg authored Jan 30, 2020
1 parent b49bd56 commit 0671b18
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 2 deletions.
10 changes: 10 additions & 0 deletions common/src/main/java/io/netty/util/internal/Hidden.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ public void applyTo(BlockHound.Builder builder) {
"confirmShutdown"
);

builder.allowBlockingCallsInside(
"io.netty.handler.ssl.SslHandler",
"handshake"
);

builder.allowBlockingCallsInside(
"io.netty.handler.ssl.SslHandler",
"runAllDelegatedTasks"
);

builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() {
@Override
public Predicate<Thread> apply(final Predicate<Thread> p) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,7 @@ public void testHandshakeWithExecutor() throws Exception {
}
}

private void testHandshakeWithExecutor(Executor executor) throws Exception {
private static void testHandshakeWithExecutor(Executor executor) throws Exception {
final SslContext sslClientCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.sslProvider(SslProvider.JDK).build();
Expand Down Expand Up @@ -991,7 +991,7 @@ public void testServerHandshakeTimeoutBecauseExecutorNotExecute() throws Excepti
testHandshakeTimeoutBecauseExecutorNotExecute(false);
}

private void testHandshakeTimeoutBecauseExecutorNotExecute(final boolean client) throws Exception {
private static void testHandshakeTimeoutBecauseExecutorNotExecute(final boolean client) throws Exception {
final SslContext sslClientCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.sslProvider(SslProvider.JDK).build();
Expand Down
12 changes: 12 additions & 0 deletions transport-blockhound-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- Needed for SelfSignedCertificate -->
<argLine.java9.extras>--add-exports java.base/sun.security.x509=ALL-UNNAMED</argLine.java9.extras>
<skipJapicmp>true</skipJapicmp>
</properties>

Expand All @@ -55,7 +57,17 @@
<artifactId>netty-transport</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-handler</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.projectreactor.tools</groupId>
<artifactId>blockhound</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,41 @@
*/
package io.netty.util.internal;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.ImmediateExecutor;
import io.netty.util.internal.Hidden.NettyBlockHoundIntegration;
import org.junit.BeforeClass;
import org.junit.Test;
import reactor.blockhound.BlockHound;
import reactor.blockhound.integration.BlockHoundIntegration;

import java.net.InetSocketAddress;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -66,4 +92,89 @@ public void testBlockingCallsInNettyThreads() throws Exception {
assertTrue("Blocking call was reported", throwable.getMessage().contains("Blocking call"));
}
}

// Tests copied from io.netty.handler.ssl.SslHandlerTest
@Test
public void testHandshakeWithExecutorThatExecuteDirectory() throws Exception {
testHandshakeWithExecutor(Runnable::run);
}

@Test
public void testHandshakeWithImmediateExecutor() throws Exception {
testHandshakeWithExecutor(ImmediateExecutor.INSTANCE);
}

@Test
public void testHandshakeWithImmediateEventExecutor() throws Exception {
testHandshakeWithExecutor(ImmediateEventExecutor.INSTANCE);
}

@Test
public void testHandshakeWithExecutor() throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
try {
testHandshakeWithExecutor(executorService);
} finally {
executorService.shutdown();
}
}

private static void testHandshakeWithExecutor(Executor executor) throws Exception {
final SslContext sslClientCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.sslProvider(SslProvider.JDK).build();

final SelfSignedCertificate cert = new SelfSignedCertificate();
final SslContext sslServerCtx = SslContextBuilder.forServer(cert.key(), cert.cert())
.sslProvider(SslProvider.JDK).build();

EventLoopGroup group = new NioEventLoopGroup();
Channel sc = null;
Channel cc = null;
final SslHandler clientSslHandler = sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor);
final SslHandler serverSslHandler = sslServerCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor);

try {
sc = new ServerBootstrap()
.group(group)
.channel(NioServerSocketChannel.class)
.childHandler(serverSslHandler)
.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();

ChannelFuture future = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) {
ch.pipeline()
.addLast(clientSslHandler)
.addLast(new ChannelInboundHandlerAdapter() {

@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt instanceof SslHandshakeCompletionEvent &&
((SslHandshakeCompletionEvent) evt).cause() != null) {
((SslHandshakeCompletionEvent) evt).cause().printStackTrace();
}
ctx.fireUserEventTriggered(evt);
}
});
}
}).connect(sc.localAddress());
cc = future.syncUninterruptibly().channel();

assertTrue(clientSslHandler.handshakeFuture().await().isSuccess());
assertTrue(serverSslHandler.handshakeFuture().await().isSuccess());
} finally {
if (cc != null) {
cc.close().syncUninterruptibly();
}
if (sc != null) {
sc.close().syncUninterruptibly();
}
group.shutdownGracefully();
ReferenceCountUtil.release(sslClientCtx);
}
}
}

0 comments on commit 0671b18

Please sign in to comment.