// Copyright 2017 The Nomulus Authors. All Rights Reserved. // // 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 specific language governing permissions and // limitations under the License. package google.registry.proxy.handler; import static com.google.common.truth.Truth.assertThat; import static google.registry.proxy.Protocol.PROTOCOL_KEY; import static google.registry.proxy.handler.SslInitializerTestUtils.getKeyPair; import static google.registry.proxy.handler.SslInitializerTestUtils.setUpSslChannel; import static google.registry.proxy.handler.SslInitializerTestUtils.signKeyPair; import com.google.common.collect.ImmutableList; import google.registry.proxy.Protocol; import google.registry.proxy.Protocol.BackendProtocol; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelPipeline; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.channel.local.LocalAddress; import io.netty.channel.local.LocalChannel; import io.netty.handler.ssl.OpenSsl; import io.netty.handler.ssl.SniHandler; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslHandler; import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.util.SelfSignedCertificate; import java.security.KeyPair; import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLException; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import sun.security.provider.certpath.SunCertPathBuilderException; /** * Unit tests for {@link SslClientInitializer}. * *
To validate that the handler accepts & rejects connections as expected, a test server and a * test client are spun up, and both connect to the {@link LocalAddress} within the JVM. This avoids * the overhead of routing traffic through the network layer, even if it were to go through * loopback. It also alleviates the need to pick a free port to use. * *
The local addresses used in each test method must to be different, otherwise tests run in
* parallel may interfere with each other.
*/
@RunWith(Parameterized.class)
public class SslClientInitializerTest {
/** Fake host to test if the SSL engine gets the correct peer host. */
private static final String SSL_HOST = "www.example.tld";
/** Fake port to test if the SSL engine gets the correct peer port. */
private static final int SSL_PORT = 12345;
@Rule
public NettyRule nettyRule = new NettyRule();
@Parameter(0)
public SslProvider sslProvider;
// We do our best effort to test all available SSL providers.
@Parameters(name = "{0}")
public static SslProvider[] data() {
return OpenSsl.isAvailable()
? new SslProvider[] {SslProvider.JDK, SslProvider.OPENSSL}
: new SslProvider[] {SslProvider.JDK};
}
/** Saves the SNI hostname received by the server, if sent by the client. */
private String sniHostReceived;
/** Fake protocol saved in channel attribute. */
private static final BackendProtocol PROTOCOL =
Protocol.backendBuilder()
.name("ssl")
.host(SSL_HOST)
.port(SSL_PORT)
.handlerProviders(ImmutableList.of())
.build();
private ChannelHandler getServerHandler(PrivateKey privateKey, X509Certificate certificate)
throws Exception {
SslContext sslContext = SslContextBuilder.forServer(privateKey, certificate).build();
return new SniHandler(
hostname -> {
sniHostReceived = hostname;
return sslContext;
});
}
@Test
public void testSuccess_swappedInitializerWithSslHandler() throws Exception {
SslClientInitializer