Add integration tests for auto-configuration of Apache Geode/Pivotal GemFire SSL transport between client and server.
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.boot.data.geode.security.ssl;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.data.geode.core.util.ObjectUtils;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.gemfire.PartitionedRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.config.annotation.CacheServerApplication;
|
||||
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
|
||||
import org.springframework.data.gemfire.config.annotation.EnableSsl;
|
||||
import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer;
|
||||
import org.springframework.data.gemfire.support.ConnectionEndpoint;
|
||||
import org.springframework.data.gemfire.tests.integration.ClientServerIntegrationTestsSupport;
|
||||
import org.springframework.data.gemfire.tests.process.ProcessWrapper;
|
||||
import org.springframework.data.gemfire.tests.util.FileSystemUtils;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import example.geode.cache.EchoCacheLoader;
|
||||
|
||||
/**
|
||||
* Integration tests testing the auto-configuration of Apache Geode/Pivotal GemFire SSL.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
* @see org.springframework.boot.test.context.SpringBootTest
|
||||
* @see org.springframework.core.io.Resource
|
||||
* @see org.springframework.data.gemfire.config.annotation.CacheServerApplication
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnableSsl
|
||||
* @see org.springframework.data.gemfire.tests.integration.ClientServerIntegrationTestsSupport
|
||||
* @see org.springframework.data.gemfire.tests.process.ProcessWrapper
|
||||
* @see org.springframework.test.context.junit4.SpringRunner
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE,
|
||||
classes = AutoConfiguredSslIntegrationTests.GemFireClientConfiguration.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class AutoConfiguredSslIntegrationTests extends ClientServerIntegrationTestsSupport {
|
||||
|
||||
private static final String GEMFIRE_LOG_LEVEL = "error";
|
||||
private static final String TRUSTED_KEYSTORE_FILENAME = "trusted.keystore";
|
||||
|
||||
private static ProcessWrapper gemfireServer;
|
||||
|
||||
@BeforeClass
|
||||
public static void startGemFireServer() throws IOException {
|
||||
|
||||
int availablePort = findAvailablePort();
|
||||
|
||||
gemfireServer = run(GemFireServerConfiguration.class,
|
||||
javaxNetSslKeyStorePropertyFromClassPath(),
|
||||
//javaxNetSslKeyStorePropertyFromFileSystem(),
|
||||
String.format("-D%s=%d", GEMFIRE_CACHE_SERVER_PORT_PROPERTY, availablePort));
|
||||
|
||||
waitForServerToStart("localhost", availablePort);
|
||||
|
||||
System.setProperty(GEMFIRE_CACHE_SERVER_PORT_PROPERTY, String.valueOf(availablePort));
|
||||
}
|
||||
|
||||
private static String javaxNetSslKeyStorePropertyFromClassPath() {
|
||||
|
||||
return String.format("-Djavax.net.ssl.keyStore=%s", locateKeyStoreInClassPath()
|
||||
.filter(StringUtils::hasText)
|
||||
.orElseThrow(() -> newIllegalStateException("KeyStore file [%s] was not found",
|
||||
TRUSTED_KEYSTORE_FILENAME)));
|
||||
}
|
||||
|
||||
private static String javaxNetSslKeyStorePropertyFromFileSystem() {
|
||||
|
||||
return String.format("-Djavax.net.ssl.keyStore=%s", locateKeyStoreInFileSystem()
|
||||
.map(File::getAbsolutePath)
|
||||
.filter(StringUtils::hasText)
|
||||
.orElseThrow(() -> newIllegalStateException("KeyStore file [%s] was not found",
|
||||
TRUSTED_KEYSTORE_FILENAME)));
|
||||
}
|
||||
|
||||
private static Optional<String> locateKeyStoreInClassPath() {
|
||||
return locateKeyStoreInClassPath(TRUSTED_KEYSTORE_FILENAME);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private static Optional<String> locateKeyStoreInClassPath(String keystoreName) {
|
||||
|
||||
/*
|
||||
System.err.printf("KEYSTORE LOCATION [%s]%n", ObjectUtils.doOperationSafely(() ->
|
||||
new File(new ClassPathResource(keystoreName).getURL().toURI())).getAbsolutePath());
|
||||
*/
|
||||
|
||||
return Optional.of(new ClassPathResource(keystoreName))
|
||||
.filter(Resource::exists)
|
||||
.map(it -> ObjectUtils.doOperationSafely(() -> it.getURL()))
|
||||
.map(url -> ObjectUtils.doOperationSafely(() -> url.toURI()))
|
||||
.map(uri -> ObjectUtils.doOperationSafely(() -> new File(uri)))
|
||||
.filter(File::isFile)
|
||||
.map(File::getAbsolutePath);
|
||||
}
|
||||
|
||||
private static Optional<File> locateKeyStoreInFileSystem() {
|
||||
return locateKeyStoreInFileSystem(FileSystemUtils.WORKING_DIRECTORY);
|
||||
}
|
||||
|
||||
private static Optional<File> locateKeyStoreInFileSystem(File directory) {
|
||||
return locateKeyStoreInFileSystem(directory, TRUSTED_KEYSTORE_FILENAME);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private static Optional<File> locateKeyStoreInFileSystem(File directory, String keystoreFilename) {
|
||||
|
||||
Assert.isTrue(directory != null && directory.isDirectory(),
|
||||
String.format("[%s] is not a valid directory", directory));
|
||||
|
||||
//System.err.printf("Searching [%s]...%n", directory);
|
||||
|
||||
for (File file : nullSafeArray(directory.listFiles(), File.class)) {
|
||||
|
||||
//System.err.printf("Testing [%s]...%n", file);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
|
||||
Optional<File> theFile = locateKeyStoreInFileSystem(file, keystoreFilename);
|
||||
|
||||
if (theFile.isPresent()) {
|
||||
return theFile;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (file.getName().equals(keystoreFilename)) {
|
||||
return Optional.of(file);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopGemFireServer() {
|
||||
System.clearProperty(GEMFIRE_CACHE_SERVER_PORT_PROPERTY);
|
||||
stop(gemfireServer);
|
||||
}
|
||||
|
||||
@javax.annotation.Resource(name = "Echo")
|
||||
private Region<String, String> echo;
|
||||
|
||||
@Test
|
||||
public void clientServerCommunicationsSuccessful() {
|
||||
|
||||
assertThat(this.echo).isNotNull();
|
||||
assertThat(this.echo.get("Hello")).isEqualTo("Hello");
|
||||
assertThat(this.echo.get("Test")).isEqualTo("Test");
|
||||
assertThat(this.echo.get("Good-Bye")).isEqualTo("Good-Bye");
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
static class GemFireClientConfiguration {
|
||||
|
||||
@Bean
|
||||
ClientCacheConfigurer clientCachePoolPortConfigurer(
|
||||
@Value("${" + GEMFIRE_CACHE_SERVER_PORT_PROPERTY + ":40404}") int port) {
|
||||
|
||||
return (bean, clientCacheFactoryBean) -> clientCacheFactoryBean.setServers(
|
||||
Collections.singletonList(new ConnectionEndpoint("localhost", port)));
|
||||
}
|
||||
|
||||
@Bean("Echo")
|
||||
public ClientRegionFactoryBean<String, String> echoRegion(GemFireCache gemfireCache) {
|
||||
|
||||
ClientRegionFactoryBean<String, String> echoRegion = new ClientRegionFactoryBean<>();
|
||||
|
||||
echoRegion.setCache(gemfireCache);
|
||||
echoRegion.setClose(false);
|
||||
echoRegion.setShortcut(ClientRegionShortcut.PROXY);
|
||||
|
||||
return echoRegion;
|
||||
}
|
||||
}
|
||||
|
||||
@EnableSsl
|
||||
@CacheServerApplication(name = "AutoConfiguredSslIntegrationTests", logLevel = GEMFIRE_LOG_LEVEL)
|
||||
static class GemFireServerConfiguration {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(GemFireServerConfiguration.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
PeerCacheConfigurer cacheServerSslConfigurer(
|
||||
@Value("${javax.net.ssl.keyStore:trusted.keystore}") String keystoreLocation) {
|
||||
|
||||
return (beanName, bean) -> {
|
||||
bean.getProperties().setProperty("ssl-keystore", keystoreLocation);
|
||||
bean.getProperties().setProperty("ssl-truststore", keystoreLocation);
|
||||
};
|
||||
}
|
||||
|
||||
@Bean("Echo")
|
||||
public PartitionedRegionFactoryBean<String, String> echoRegion(GemFireCache gemfireCache) {
|
||||
|
||||
PartitionedRegionFactoryBean<String, String> echoRegion = new PartitionedRegionFactoryBean<>();
|
||||
|
||||
echoRegion.setCache(gemfireCache);
|
||||
echoRegion.setCacheLoader(EchoCacheLoader.INSTANCE);
|
||||
echoRegion.setClose(false);
|
||||
echoRegion.setPersistent(false);
|
||||
|
||||
return echoRegion;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Spring Boot application.properties for testing
|
||||
spring.data.gemfire.security.ssl.keystore.password=s3cr3t
|
||||
spring.data.gemfire.security.ssl.truststore.password=s3cr3t
|
||||
BIN
geode-spring-boot-starter/src/test/resources/trusted.keystore
Normal file
BIN
geode-spring-boot-starter/src/test/resources/trusted.keystore
Normal file
Binary file not shown.
Reference in New Issue
Block a user