package org.infinispan.server.hotrod; import static org.infinispan.server.core.test.ServerTestingUtil.killServer; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.assertSuccess; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.k; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.killClient; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.serverPort; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.startHotRodServer; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.v; import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import javax.net.ssl.SNIHostName; import javax.net.ssl.SNIServerName; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLParameters; import org.infinispan.commons.util.SslContextFactory; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.server.hotrod.configuration.HotRodServerConfigurationBuilder; import org.infinispan.server.hotrod.test.HotRodClient; import org.infinispan.server.hotrod.test.Op; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; /** * Hot Rod server functional test for SNI. * * See <a href="https://tools.ietf.org/html/rfc6066#page-6">RFC 6066</a>. * * @author Sebastian Ɓaskawiec * @since 9.0 */ @Test(groups = "functional", testName = "server.hotrod.HotRodSniFunctionalTest") public class HotRodSniFunctionalTest extends HotRodSingleNodeTest { private String defaultServerKeystore = getClass().getClassLoader().getResource("default_server_keystore.jks").getPath(); private String sniServerKeystore = getClass().getClassLoader().getResource("sni_server_keystore.jks").getPath(); private String noAuthorizedClientsServerKeystore = getClass().getClassLoader().getResource("no_trusted_clients_keystore.jks").getPath(); private String defaultTrustedClientTruststore = getClass().getClassLoader().getResource("default_client_truststore.jks").getPath(); private String sniTrustedClientTruststore = getClass().getClassLoader().getResource("sni_client_truststore.jks").getPath(); @AfterMethod(alwaysRun = true) public void afterMethod() { //HotRodSingleNodeTest assumes that we start/shutdown server once instead of per-test. We need to perform our own cleanup. killClient(hotRodClient); killServer(hotRodServer); } public void testServerAndClientWithDefaultSslContext(Method m) { //given hotRodServer = new HotrodServerBuilder() .addSniDomain("*", defaultServerKeystore, "secret", defaultTrustedClientTruststore, "secret") .build(); hotRodClient = new HotrodClientBuilder(hotRodServer) .useSslConfiguration(defaultServerKeystore, "secret", defaultTrustedClientTruststore, "secret") .build(); //when client().assertPut(m); //then assertSuccess(client().assertGet(m), v(m)); } public void testServerAndClientWithSniSslContext(Method m) { //given hotRodServer = new HotrodServerBuilder() //this will reject all clients without SNI Domain specified .addSniDomain("*", noAuthorizedClientsServerKeystore, "secret", sniTrustedClientTruststore, "secret") //and here we allow only those with SNI specified .addSniDomain("sni", sniServerKeystore, "secret", sniTrustedClientTruststore, "secret") .build(); hotRodClient = new HotrodClientBuilder(hotRodServer) .useSslConfiguration(sniServerKeystore, "secret", sniTrustedClientTruststore, "secret") .addSniDomain(Collections.singletonList("sni")) .build(); //when client().assertPut(m); //then assertSuccess(client().assertGet(m), v(m)); } public void testServerWithNotMatchingDefaultAndClientWithSNI(Method m) { //given hotRodServer = new HotrodServerBuilder() .addSniDomain("*", noAuthorizedClientsServerKeystore, "secret", sniTrustedClientTruststore, "secret") .build(); hotRodClient = new HotrodClientBuilder(hotRodServer) .useSslConfiguration(sniServerKeystore, "secret", sniTrustedClientTruststore, "secret") .addSniDomain(Collections.singletonList("sni")) .build(); //when Op op = new Op(0xA0, (byte) 0x01, (byte) 20, client().defaultCacheName(), k(m), 0, 0, v(m), 0, 0, (byte) 1, 0); boolean success = client().writeOp(op, false); //assert Assert.assertFalse(success); } //Server configuration needs to be performed per test protected @Override HotRodServer createStartHotRodServer(EmbeddedCacheManager cacheManager) { return null; } //Client configuration needs to be performed per test protected @Override HotRodClient connectClient() { return null; } class HotrodClientBuilder { private final HotRodServer hotRodServer; SSLContext sslContext; SSLEngine sslEngine; public HotrodClientBuilder(HotRodServer hotRodServer) { this.hotRodServer = hotRodServer; } public HotrodClientBuilder useSslConfiguration(String keystoreFileName, String keystorePassword, String truststoreFileName, String truststorePassword) { sslContext = SslContextFactory.getContext(keystoreFileName, keystorePassword.toCharArray(), truststoreFileName, truststorePassword.toCharArray()); sslEngine = SslContextFactory.getEngine(sslContext, true, false); return this; } public HotrodClientBuilder addSniDomain(List<String> sniNames) { if (!sniNames.isEmpty()) { SSLParameters sslParameters = sslEngine.getSSLParameters(); List<SNIServerName> hosts = sniNames.stream().map(SNIHostName::new).collect(Collectors.toList()); sslParameters.setServerNames(hosts); sslEngine.setSSLParameters(sslParameters); } return this; } public HotRodClient build() { return new HotRodClient("127.0.0.1", hotRodServer.getPort(), cacheName, 60, (byte) 20, sslEngine); } } class HotrodServerBuilder { String ip = "127.0.0.1"; HotRodServerConfigurationBuilder builder = new HotRodServerConfigurationBuilder() .proxyHost("127.0.0.1") .proxyPort(serverPort()) .idleTimeout(0); public HotrodServerBuilder addSniDomain(String domain, String keystoreFileName, String keystorePassword, String truststoreFileName, String truststorePassword) { builder.ssl().enable() .sniHostName(domain) .keyStoreFileName(keystoreFileName) .keyStorePassword(keystorePassword.toCharArray()) .trustStoreFileName(truststoreFileName) .trustStorePassword(truststorePassword.toCharArray()); return this; } public HotRodServer build() { return startHotRodServer(cacheManager, serverPort(), -1, builder); } } }