change format for check style

This commit is contained in:
JiaLin
2020-07-26 02:01:59 +08:00
parent f28ea277f7
commit 67a6cbfe23
11 changed files with 670 additions and 618 deletions

View File

@@ -20,30 +20,37 @@
This project is a Spring configuration client.
]]>
</description>
<properties>
<spring.boot.version>2.4.0-M1</spring.boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<artifactId>spring-boot</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>${spring.boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
@@ -70,11 +77,13 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring.boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>${spring.boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
@@ -84,23 +93,21 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<version>${spring.boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>

View File

@@ -28,95 +28,98 @@ import org.springframework.util.SocketUtils;
public class AppRunner implements AutoCloseable {
private Class<?> appClass;
private Map<String, String> props;
private ConfigurableApplicationContext app;
public AppRunner(Class<?> appClass) {
this.appClass = appClass;
props = new LinkedHashMap<>();
}
public void property(String key, String value) {
props.put(key, value);
}
public void start() {
if (app == null) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(appClass);
builder.properties("spring.jmx.enabled=false");
builder.properties(String.format("server.port=%d", availabeTcpPort()));
builder.properties(props());
app = builder.build().run();
}
}
private int availabeTcpPort() {
return SocketUtils.findAvailableTcpPort();
}
private String [] props() {
List<String> result = new ArrayList<>();
for (String key : props.keySet()) {
String value = props.get(key);
result.add(String.format("%s=%s", key, value));
}
return result.toArray(new String [0]);
}
public void stop() {
if (app != null) {
app.stop();
app = null;
}
}
public ConfigurableApplicationContext app() {
return app;
}
public String getProperty(String key) {
return app.getEnvironment().getProperty(key);
}
public <T> T getBean(Class<T> type) {
return app.getBean(type);
}
public ApplicationContext parent() {
return app.getParent();
}
public <T> Map<String, T> getParentBeans(Class<T> type) {
return parent().getBeansOfType(type);
}
public int port() {
if (app == null) {
throw new RuntimeException("App is not running.");
}
return app.getEnvironment().getProperty("server.port", Integer.class, -1);
}
public String root() {
if (app == null) {
throw new RuntimeException("App is not running.");
}
String protocol = tlsEnabled() ? "https" : "http";
return String.format("%s://localhost:%d/", protocol, port());
}
private boolean tlsEnabled() {
return app.getEnvironment().getProperty("server.ssl.enabled", Boolean.class, false);
}
private Class<?> appClass;
private Map<String, String> props;
private ConfigurableApplicationContext app;
public AppRunner(Class<?> appClass) {
this.appClass = appClass;
props = new LinkedHashMap<>();
}
public void property(String key, String value) {
props.put(key, value);
}
public void start() {
if (app == null) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(appClass);
builder.properties("spring.jmx.enabled=false");
builder.properties(String.format("server.port=%d", availabeTcpPort()));
builder.properties(props());
app = builder.build().run();
}
}
private int availabeTcpPort() {
return SocketUtils.findAvailableTcpPort();
}
private String[] props() {
List<String> result = new ArrayList<>();
for (String key : props.keySet()) {
String value = props.get(key);
result.add(String.format("%s=%s", key, value));
}
return result.toArray(new String[0]);
}
public void stop() {
if (app != null) {
app.stop();
app = null;
}
}
public ConfigurableApplicationContext app() {
return app;
}
public String getProperty(String key) {
return app.getEnvironment().getProperty(key);
}
public <T> T getBean(Class<T> type) {
return app.getBean(type);
}
public ApplicationContext parent() {
return app.getParent();
}
public <T> Map<String, T> getParentBeans(Class<T> type) {
return parent().getBeansOfType(type);
}
public int port() {
if (app == null) {
throw new RuntimeException("App is not running.");
}
return app.getEnvironment().getProperty("server.port", Integer.class, -1);
}
public String root() {
if (app == null) {
throw new RuntimeException("App is not running.");
}
String protocol = tlsEnabled() ? "https" : "http";
return String.format("%s://localhost:%d/", protocol, port());
}
private boolean tlsEnabled() {
return app.getEnvironment().getProperty("server.ssl.enabled", Boolean.class,
false);
}
@Override
public void close() {
stop();
}
@Override
public void close() {
stop();
}
}

View File

@@ -24,61 +24,70 @@ import java.security.KeyStore;
import org.junit.BeforeClass;
public class BaseCertTest {
protected static final String KEY_STORE_PASSWORD = "test-key-store-password";
protected static final String KEY_PASSWORD = "test-key-password";
protected static final String WRONG_PASSWORD = "test-wrong-password";
protected static File caCert;
protected static File wrongCaCert;
protected static File serverCert;
protected static File clientCert;
protected static File wrongClientCert;
@BeforeClass
public static void createCertificates() throws Exception {
KeyTool tool = new KeyTool();
KeyAndCert ca = tool.createCA("MyCA");
KeyAndCert server = ca.sign("server");
KeyAndCert client = ca.sign("client");
caCert = saveCert(ca);
serverCert = saveKeyAndCert(server);
clientCert = saveKeyAndCert(client);
KeyAndCert wrongCa = tool.createCA("WrongCA");
KeyAndCert wrongClient = wrongCa.sign("client");
wrongCaCert = saveCert(wrongCa);
wrongClientCert = saveKeyAndCert(wrongClient);
System.setProperty("javax.net.ssl.trustStore", caCert.getAbsolutePath());
System.setProperty("javax.net.ssl.trustStorePassword", KEY_STORE_PASSWORD);
}
private static File saveKeyAndCert(KeyAndCert keyCert) throws Exception {
return saveKeyStore(keyCert.subject(), () -> keyCert.storeKeyAndCert(KEY_PASSWORD));
}
private static File saveCert(KeyAndCert keyCert) throws Exception {
return saveKeyStore(keyCert.subject(), () -> keyCert.storeCert());
}
private static File saveKeyStore(String prefix, KeyStoreSupplier func) throws Exception {
File result = File.createTempFile(prefix, ".p12");
result.deleteOnExit();
try (OutputStream output = new FileOutputStream(result)) {
KeyStore store = func.createKeyStore();
store.store(output, KEY_STORE_PASSWORD.toCharArray());
}
return result;
}
interface KeyStoreSupplier {
public KeyStore createKeyStore() throws Exception;
}
protected static final String KEY_STORE_PASSWORD = "test-key-store-password";
protected static final String KEY_PASSWORD = "test-key-password";
protected static final String WRONG_PASSWORD = "test-wrong-password";
protected static File caCert;
protected static File wrongCaCert;
protected static File serverCert;
protected static File clientCert;
protected static File wrongClientCert;
@BeforeClass
public static void createCertificates() throws Exception {
KeyTool tool = new KeyTool();
KeyAndCert ca = tool.createCA("MyCA");
KeyAndCert server = ca.sign("server");
KeyAndCert client = ca.sign("client");
caCert = saveCert(ca);
serverCert = saveKeyAndCert(server);
clientCert = saveKeyAndCert(client);
KeyAndCert wrongCa = tool.createCA("WrongCA");
KeyAndCert wrongClient = wrongCa.sign("client");
wrongCaCert = saveCert(wrongCa);
wrongClientCert = saveKeyAndCert(wrongClient);
System.setProperty("javax.net.ssl.trustStore", caCert.getAbsolutePath());
System.setProperty("javax.net.ssl.trustStorePassword", KEY_STORE_PASSWORD);
}
private static File saveKeyAndCert(KeyAndCert keyCert) throws Exception {
return saveKeyStore(keyCert.subject(),
() -> keyCert.storeKeyAndCert(KEY_PASSWORD));
}
private static File saveCert(KeyAndCert keyCert) throws Exception {
return saveKeyStore(keyCert.subject(), () -> keyCert.storeCert());
}
private static File saveKeyStore(String prefix, KeyStoreSupplier func)
throws Exception {
File result = File.createTempFile(prefix, ".p12");
result.deleteOnExit();
try (OutputStream output = new FileOutputStream(result)) {
KeyStore store = func.createKeyStore();
store.store(output, KEY_STORE_PASSWORD.toCharArray());
}
return result;
}
interface KeyStoreSupplier {
KeyStore createKeyStore() throws Exception;
}
}

View File

@@ -16,134 +16,130 @@
package org.springframework.cloud.config.client;
import static org.junit.Assert.*;
import java.io.File;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.config.server.EnableConfigServer;
import static org.assertj.core.api.Assertions.assertThat;
public class ConfigClientTest extends BaseCertTest {
private static TlsConfigServerRunner server;
@BeforeClass
public static void setupAll() throws Exception {
startConfigServer();
}
@AfterClass
public static void tearDownAll() {
stopConfigServer();
}
private static void startConfigServer() {
server = new TlsConfigServerRunner(TestConfigServer.class);
server.enableTls();
server.setKeyStore(serverCert, KEY_STORE_PASSWORD, "server", KEY_PASSWORD);
server.setTrustStore(caCert, KEY_STORE_PASSWORD);
server.start();
}
private static void stopConfigServer() {
server.stop();
}
@Test
public void clientCertCanWork() {
try (TlsConfigClientRunner client = createConfigClient()) {
enableTlsClient(client);
client.start();
assertEquals("dumb-value", client.getProperty("dumb.key"));
}
}
@Test
public void tlsClientCanBeDisabled() {
try (TlsConfigClientRunner client = createConfigClient()) {
enableTlsClient(client);
client.property("spring.cloud.config.enabled", "false");
client.start();
assertNull(client.getProperty("dumb.key"));
}
}
@Test
public void noCertCannotWork() {
try (TlsConfigClientRunner client = createConfigClient()) {
client.disableTls();
client.start();
assertNull(client.getProperty("dumb.key"));
}
}
@Test
public void wrongCertCannotWork() {
try (TlsConfigClientRunner client = createConfigClient()) {
enableTlsClient(client);
client.setKeyStore(wrongClientCert);
client.start();
assertNull(client.getProperty("dumb.key"));
}
}
@Test(expected = IllegalStateException.class)
public void wrongPasswordCauseFailure() {
TlsConfigClientRunner client = createConfigClient();
enableTlsClient(client);
client.setKeyStore(clientCert, WRONG_PASSWORD, WRONG_PASSWORD);
client.start();
}
@Test(expected = IllegalStateException.class)
public void nonExistKeyStoreCauseFailure() {
TlsConfigClientRunner client = createConfigClient();
enableTlsClient(client);
client.setKeyStore(new File("nonExistFile"));
client.start();
}
@Test
public void wrongTrustStoreCannotWork() {
try (TlsConfigClientRunner client = createConfigClient()) {
enableTlsClient(client);
client.setTrustStore(wrongCaCert);
client.start();
assertNull(client.getProperty("dumb.key"));
}
}
@Test
public void onlyOneLocator() {
try (TlsConfigClientRunner client = createConfigClient()) {
enableTlsClient(client);
client.start();
assertEquals(1, client.getParentBeans(ConfigServicePropertySourceLocator.class).size());
}
}
private TlsConfigClientRunner createConfigClient() {
return new TlsConfigClientRunner(TestApp.class, server);
}
private void enableTlsClient(TlsConfigClientRunner runner) {
runner.enableTls();
runner.setKeyStore(clientCert, KEY_STORE_PASSWORD, KEY_PASSWORD);
runner.setTrustStore(caCert, KEY_STORE_PASSWORD);
}
@SpringBootConfiguration
@EnableAutoConfiguration
public static class TestApp {}
@SpringBootConfiguration
@EnableAutoConfiguration
@EnableConfigServer
public static class TestConfigServer {}
private static TlsConfigServerRunner server;
@BeforeClass
public static void setupAll() throws Exception {
startConfigServer();
}
@AfterClass
public static void tearDownAll() {
stopConfigServer();
}
private static void startConfigServer() {
server = new TlsConfigServerRunner(TestConfigServer.class);
server.enableTls();
server.setKeyStore(serverCert, KEY_STORE_PASSWORD, "server", KEY_PASSWORD);
server.setTrustStore(caCert, KEY_STORE_PASSWORD);
server.start();
}
private static void stopConfigServer() {
server.stop();
}
@Test
public void clientCertCanWork() {
try (TlsConfigClientRunner client = createConfigClient()) {
enableTlsClient(client);
client.start();
assertThat(client.getProperty("dumb.key")).isEqualTo("dumb-value");
}
}
@Test
public void tlsClientCanBeDisabled() {
try (TlsConfigClientRunner client = createConfigClient()) {
enableTlsClient(client);
client.property("spring.cloud.config.enabled", "false");
client.start();
assertThat(client.getProperty("dumb.key")).isNull();
}
}
@Test
public void noCertCannotWork() {
try (TlsConfigClientRunner client = createConfigClient()) {
client.disableTls();
client.start();
assertThat(client.getProperty("dumb.key")).isNull();
}
}
@Test
public void wrongCertCannotWork() {
try (TlsConfigClientRunner client = createConfigClient()) {
enableTlsClient(client);
client.setKeyStore(wrongClientCert);
client.start();
assertThat(client.getProperty("dumb.key")).isNull();
}
}
@Test(expected = IllegalStateException.class)
public void wrongPasswordCauseFailure() {
TlsConfigClientRunner client = createConfigClient();
enableTlsClient(client);
client.setKeyStore(clientCert, WRONG_PASSWORD, WRONG_PASSWORD);
client.start();
}
@Test(expected = IllegalStateException.class)
public void nonExistKeyStoreCauseFailure() {
TlsConfigClientRunner client = createConfigClient();
enableTlsClient(client);
client.setKeyStore(new File("nonExistFile"));
client.start();
}
@Test
public void wrongTrustStoreCannotWork() {
try (TlsConfigClientRunner client = createConfigClient()) {
enableTlsClient(client);
client.setTrustStore(wrongCaCert);
client.start();
assertThat(client.getProperty("dumb.key")).isNull();
}
}
private TlsConfigClientRunner createConfigClient() {
return new TlsConfigClientRunner(TestApp.class, server);
}
private void enableTlsClient(TlsConfigClientRunner runner) {
runner.enableTls();
runner.setKeyStore(clientCert, KEY_STORE_PASSWORD, KEY_PASSWORD);
runner.setTrustStore(caCert, KEY_STORE_PASSWORD);
}
@SpringBootConfiguration
@EnableAutoConfiguration
public static class TestApp {
}
@SpringBootConfiguration
@EnableAutoConfiguration
@EnableConfigServer
public static class TestConfigServer {
}
}

View File

@@ -24,68 +24,71 @@ import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
public class KeyAndCert {
private KeyPair keyPair;
private X509Certificate certificate;
public KeyAndCert(KeyPair keyPair, X509Certificate certificate) {
this.keyPair = keyPair;
this.certificate = certificate;
}
public KeyPair keyPair() {
return keyPair;
}
public PublicKey publicKey() {
return keyPair.getPublic();
}
public PrivateKey privateKey() {
return keyPair.getPrivate();
}
public X509Certificate certificate() {
return certificate;
}
public String subject() {
String dn = certificate.getSubjectDN().getName();
int index = dn.indexOf('=');
return dn.substring(index + 1);
}
public KeyAndCert sign(String subject) throws Exception {
KeyTool tool = new KeyTool();
return tool.signCertificate(subject, this);
}
public KeyAndCert sign(KeyPair keyPair, String subject) throws Exception {
KeyTool tool = new KeyTool();
return tool.signCertificate(keyPair, subject, this);
}
public KeyStore storeKeyAndCert(String keyPassword) throws Exception {
KeyStore result = KeyStore.getInstance("PKCS12");
result.load(null);
result.setKeyEntry(subject(), keyPair.getPrivate(), keyPassword.toCharArray(), certChain());
return result;
}
private Certificate [] certChain() {
return new Certificate [] {certificate()};
}
public KeyStore storeCert() throws Exception {
return storeCert("PKCS12");
}
public KeyStore storeCert(String storeType) throws Exception {
KeyStore result = KeyStore.getInstance(storeType);
result.load(null);
result.setCertificateEntry(subject(), certificate());
return result;
}
private KeyPair keyPair;
private X509Certificate certificate;
public KeyAndCert(KeyPair keyPair, X509Certificate certificate) {
this.keyPair = keyPair;
this.certificate = certificate;
}
public KeyPair keyPair() {
return keyPair;
}
public PublicKey publicKey() {
return keyPair.getPublic();
}
public PrivateKey privateKey() {
return keyPair.getPrivate();
}
public X509Certificate certificate() {
return certificate;
}
public String subject() {
String dn = certificate.getSubjectDN().getName();
int index = dn.indexOf('=');
return dn.substring(index + 1);
}
public KeyAndCert sign(String subject) throws Exception {
KeyTool tool = new KeyTool();
return tool.signCertificate(subject, this);
}
public KeyAndCert sign(KeyPair keyPair, String subject) throws Exception {
KeyTool tool = new KeyTool();
return tool.signCertificate(keyPair, subject, this);
}
public KeyStore storeKeyAndCert(String keyPassword) throws Exception {
KeyStore result = KeyStore.getInstance("PKCS12");
result.load(null);
result.setKeyEntry(subject(), keyPair.getPrivate(), keyPassword.toCharArray(),
certChain());
return result;
}
private Certificate[] certChain() {
return new Certificate[] { certificate() };
}
public KeyStore storeCert() throws Exception {
return storeCert("PKCS12");
}
public KeyStore storeCert(String storeType) throws Exception {
KeyStore result = KeyStore.getInstance(storeType);
result.load(null);
result.setCertificateEntry(subject(), certificate());
return result;
}
}

View File

@@ -39,78 +39,88 @@ import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
public class KeyTool {
private static final long ONE_DAY = 1000L * 60L * 60L * 24L;
private static final long TEN_YEARS = ONE_DAY * 365L * 10L;
public KeyAndCert createCA(String ca) throws Exception {
KeyPair keyPair = createKeyPair();
X509Certificate certificate = createCert(keyPair, ca);
return new KeyAndCert(keyPair, certificate);
}
public KeyAndCert signCertificate(String subject, KeyAndCert signer) throws Exception {
return signCertificate(createKeyPair(), subject, signer);
}
public KeyAndCert signCertificate(KeyPair keyPair, String subject, KeyAndCert signer) throws Exception {
X509Certificate certificate = createCert(keyPair.getPublic(), signer.privateKey(), signer.subject(), subject);
KeyAndCert result = new KeyAndCert(keyPair, certificate);
return result;
}
public KeyPair createKeyPair() throws Exception {
return createKeyPair(1024);
}
public KeyPair createKeyPair(int keySize) throws Exception {
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(keySize, new SecureRandom());
return gen.generateKeyPair();
}
public X509Certificate createCert(KeyPair keyPair, String ca) throws Exception {
JcaX509v3CertificateBuilder builder = certBuilder(keyPair.getPublic(), ca, ca);
builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));
builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));
return signCert(builder, keyPair.getPrivate());
}
public X509Certificate createCert(PublicKey publicKey, PrivateKey privateKey, String issuer, String subject) throws Exception {
JcaX509v3CertificateBuilder builder = certBuilder(publicKey, issuer, subject);
builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature));
builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(false));
GeneralName [] names = new GeneralName [] { new GeneralName(GeneralName.dNSName, "localhost") };
builder.addExtension(Extension.subjectAlternativeName, false, GeneralNames.getInstance(new DERSequence(names)));
return signCert(builder, privateKey);
}
private JcaX509v3CertificateBuilder certBuilder(PublicKey publicKey, String issuer, String subject) {
X500Name issuerName = new X500Name(String.format("dc=%s", issuer));
X500Name subjectName = new X500Name(String.format("dc=%s", subject));
long now = System.currentTimeMillis();
BigInteger serialNum = BigInteger.valueOf(now);
Date notBefore = new Date(now - ONE_DAY);
Date notAfter = new Date(now + TEN_YEARS);
return new JcaX509v3CertificateBuilder(
issuerName,
serialNum,
notBefore,
notAfter,
subjectName,
publicKey);
}
private X509Certificate signCert(JcaX509v3CertificateBuilder builder, PrivateKey privateKey) throws Exception {
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
X509CertificateHolder holder = builder.build(signer);
return new JcaX509CertificateConverter().getCertificate(holder);
}
private static final long ONE_DAY = 1000L * 60L * 60L * 24L;
private static final long TEN_YEARS = ONE_DAY * 365L * 10L;
public KeyAndCert createCA(String ca) throws Exception {
KeyPair keyPair = createKeyPair();
X509Certificate certificate = createCert(keyPair, ca);
return new KeyAndCert(keyPair, certificate);
}
public KeyAndCert signCertificate(String subject, KeyAndCert signer)
throws Exception {
return signCertificate(createKeyPair(), subject, signer);
}
public KeyAndCert signCertificate(KeyPair keyPair, String subject, KeyAndCert signer)
throws Exception {
X509Certificate certificate = createCert(keyPair.getPublic(), signer.privateKey(),
signer.subject(), subject);
KeyAndCert result = new KeyAndCert(keyPair, certificate);
return result;
}
public KeyPair createKeyPair() throws Exception {
return createKeyPair(1024);
}
public KeyPair createKeyPair(int keySize) throws Exception {
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(keySize, new SecureRandom());
return gen.generateKeyPair();
}
public X509Certificate createCert(KeyPair keyPair, String ca) throws Exception {
JcaX509v3CertificateBuilder builder = certBuilder(keyPair.getPublic(), ca, ca);
builder.addExtension(Extension.keyUsage, true,
new KeyUsage(KeyUsage.keyCertSign));
builder.addExtension(Extension.basicConstraints, false,
new BasicConstraints(true));
return signCert(builder, keyPair.getPrivate());
}
public X509Certificate createCert(PublicKey publicKey, PrivateKey privateKey,
String issuer, String subject) throws Exception {
JcaX509v3CertificateBuilder builder = certBuilder(publicKey, issuer, subject);
builder.addExtension(Extension.keyUsage, true,
new KeyUsage(KeyUsage.digitalSignature));
builder.addExtension(Extension.basicConstraints, false,
new BasicConstraints(false));
GeneralName[] names = new GeneralName[] {
new GeneralName(GeneralName.dNSName, "localhost") };
builder.addExtension(Extension.subjectAlternativeName, false,
GeneralNames.getInstance(new DERSequence(names)));
return signCert(builder, privateKey);
}
private JcaX509v3CertificateBuilder certBuilder(PublicKey publicKey, String issuer,
String subject) {
X500Name issuerName = new X500Name(String.format("dc=%s", issuer));
X500Name subjectName = new X500Name(String.format("dc=%s", subject));
long now = System.currentTimeMillis();
BigInteger serialNum = BigInteger.valueOf(now);
Date notBefore = new Date(now - ONE_DAY);
Date notAfter = new Date(now + TEN_YEARS);
return new JcaX509v3CertificateBuilder(issuerName, serialNum, notBefore, notAfter,
subjectName, publicKey);
}
private X509Certificate signCert(JcaX509v3CertificateBuilder builder,
PrivateKey privateKey) throws Exception {
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA")
.build(privateKey);
X509CertificateHolder holder = builder.build(signer);
return new JcaX509CertificateConverter().getCertificate(holder);
}
}

View File

@@ -20,41 +20,42 @@ import java.io.File;
public class TlsConfigClientRunner extends AppRunner {
public TlsConfigClientRunner(Class<?> appClass, AppRunner server) {
super(appClass);
property("spring.cloud.config.uri", server.root());
property("spring.cloud.config.enabled", "true");
}
public void enableTls() {
property("spring.cloud.config.tls.enabled", "true");
}
public void disableTls() {
property("spring.cloud.config.tls.enabled", "false");
}
public void setKeyStore(File keyStore, String keyStorePassword, String keyPassword) {
property("spring.cloud.config.tls.key-store", pathOf(keyStore));
property("spring.cloud.config.tls.key-store-password", keyStorePassword);
property("spring.cloud.config.tls.key-password", keyPassword);
}
public void setKeyStore(File keyStore) {
property("spring.cloud.config.tls.key-store", pathOf(keyStore));
}
public void setTrustStore(File trustStore, String password) {
property("spring.cloud.config.tls.trust-store", pathOf(trustStore));
property("spring.cloud.config.tls.trust-store-password", password);
}
public void setTrustStore(File trustStore) {
property("spring.cloud.config.tls.trust-store", pathOf(trustStore));
}
private String pathOf(File file) {
return String.format("file:%s", file.getAbsolutePath());
}
public TlsConfigClientRunner(Class<?> appClass, AppRunner server) {
super(appClass);
property("spring.cloud.config.uri", server.root());
property("spring.cloud.config.enabled", "true");
}
public void enableTls() {
property("spring.cloud.config.tls.enabled", "true");
}
public void disableTls() {
property("spring.cloud.config.tls.enabled", "false");
}
public void setKeyStore(File keyStore, String keyStorePassword, String keyPassword) {
property("spring.cloud.config.tls.key-store", pathOf(keyStore));
property("spring.cloud.config.tls.key-store-password", keyStorePassword);
property("spring.cloud.config.tls.key-password", keyPassword);
}
public void setKeyStore(File keyStore) {
property("spring.cloud.config.tls.key-store", pathOf(keyStore));
}
public void setTrustStore(File trustStore, String password) {
property("spring.cloud.config.tls.trust-store", pathOf(trustStore));
property("spring.cloud.config.tls.trust-store-password", password);
}
public void setTrustStore(File trustStore) {
property("spring.cloud.config.tls.trust-store", pathOf(trustStore));
}
private String pathOf(File file) {
return String.format("file:%s", file.getAbsolutePath());
}
}

View File

@@ -20,32 +20,35 @@ import java.io.File;
public class TlsConfigServerRunner extends AppRunner {
public TlsConfigServerRunner(Class<?> appClass) {
super(appClass);
property("spring.profiles.active", "native");
property("spring.cloud.config.server.native.search-locations", "classpath:/test/config");
}
public void enableTls() {
property("server.ssl.enabled", "true");
property("server.ssl.client-auth", "need");
}
public void setKeyStore(File keyStore, String keyStorePassword, String key, String keyPassword) {
property("server.ssl.key-store", pathOf(keyStore));
property("server.ssl.key-store-type", "PKCS12");
property("server.ssl.key-store-password", keyStorePassword);
property("server.ssl.key-alias", key);
property("server.ssl.key-password", keyPassword);
}
public void setTrustStore(File trustStore, String password) {
property("server.ssl.trust-store", pathOf(trustStore));
property("server.ssl.trust-store-type", "PKCS12");
property("server.ssl.trust-store-password", password);
}
private String pathOf(File file) {
return String.format("file:%s", file.getAbsolutePath());
}
public TlsConfigServerRunner(Class<?> appClass) {
super(appClass);
property("spring.profiles.active", "native");
property("spring.cloud.config.server.native.search-locations",
"classpath:/test/config");
}
public void enableTls() {
property("server.ssl.enabled", "true");
property("server.ssl.client-auth", "need");
}
public void setKeyStore(File keyStore, String keyStorePassword, String key,
String keyPassword) {
property("server.ssl.key-store", pathOf(keyStore));
property("server.ssl.key-store-type", "PKCS12");
property("server.ssl.key-store-password", keyStorePassword);
property("server.ssl.key-alias", key);
property("server.ssl.key-password", keyPassword);
}
public void setTrustStore(File trustStore, String password) {
property("server.ssl.trust-store", pathOf(trustStore));
property("server.ssl.trust-store-type", "PKCS12");
property("server.ssl.trust-store-password", password);
}
private String pathOf(File file) {
return String.format("file:%s", file.getAbsolutePath());
}
}

View File

@@ -1 +1 @@
dumb.key=dumb-value
dumb.key=dumb-value

View File

@@ -33,6 +33,7 @@ import javax.annotation.PostConstruct;
import javax.net.ssl.SSLContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -110,9 +111,9 @@ public class ConfigClientProperties {
* Discovery properties.
*/
private Discovery discovery = new Discovery();
/**
* TLS properties
* TLS properties.
*/
private TLS tls = new TLS();
@@ -232,7 +233,7 @@ public class ConfigClientProperties {
public void setTls(TLS tls) {
this.tls = tls;
}
@PostConstruct
public void checkTlsStoreType() {
tls.checkStoreType();
@@ -444,37 +445,43 @@ public class ConfigClientProperties {
}
}
/**
* TLS properties
* TLS properties.
*/
public static class TLS {
private static final String DEFAULT_STORE_TYPE = "PKCS12";
private static final Map<String, String> EXTENSION_STORE_TYPES = extTypes();
private boolean enabled;
private static final String DEFAULT_STORE_TYPE = "PKCS12";
private static final Map<String, String> EXTENSION_STORE_TYPES = extTypes();
private boolean enabled;
private Resource keyStore;
private String keyStoreType;
private String keyStorePassword = "";
private String keyPassword = "";
private Resource trustStore;
private String trustStoreType;
private String trustStorePassword = "";
private static Map<String, String> extTypes() {
Map<String, String> result = new HashMap<>();
private String keyStoreType;
result.put("p12", "PKCS12");
result.put("pfx", "PKCS12");
result.put("jks", "JKS");
private String keyStorePassword = "";
return Collections.unmodifiableMap(result);
}
public boolean isEnabled() {
private String keyPassword = "";
private Resource trustStore;
private String trustStoreType;
private String trustStorePassword = "";
private static Map<String, String> extTypes() {
Map<String, String> result = new HashMap<>();
result.put("p12", "PKCS12");
result.put("pfx", "PKCS12");
result.put("jks", "JKS");
return Collections.unmodifiableMap(result);
}
public boolean isEnabled() {
return enabled;
}
@@ -537,113 +544,120 @@ public class ConfigClientProperties {
public void setTrustStorePassword(String trustStorePassword) {
this.trustStorePassword = trustStorePassword;
}
public char[] keyStorePassword() {
return keyStorePassword.toCharArray();
}
public char[] keyPassword() {
return keyPassword.toCharArray();
}
public char[] keyStorePassword() {
return keyStorePassword.toCharArray();
}
public char[] keyPassword() {
return keyPassword.toCharArray();
}
public char[] trustStorePassword() {
return trustStorePassword.toCharArray();
}
public void checkStoreType() {
if (keyStore != null && keyStoreType == null) {
keyStoreType = storeTypeOf(keyStore);
}
if (trustStore != null && trustStoreType == null) {
trustStoreType = storeTypeOf(trustStore);
}
}
return trustStorePassword.toCharArray();
}
private String storeTypeOf(Resource resource) {
String extension = fileExtensionOf(resource);
String type = EXTENSION_STORE_TYPES.get(extension);
public void checkStoreType() {
if (keyStore != null && keyStoreType == null) {
keyStoreType = storeTypeOf(keyStore);
}
if (trustStore != null && trustStoreType == null) {
trustStoreType = storeTypeOf(trustStore);
}
}
return (type == null) ? DEFAULT_STORE_TYPE : type;
}
private String storeTypeOf(Resource resource) {
String extension = fileExtensionOf(resource);
String type = EXTENSION_STORE_TYPES.get(extension);
private String fileExtensionOf(Resource resource) {
String name = resource.getFilename();
int index = name.lastIndexOf('.');
return (type == null) ? DEFAULT_STORE_TYPE : type;
}
return index < 0 ? "" : name.substring(index + 1).toLowerCase();
}
public SSLContext createSSLContext() throws GeneralSecurityException, IOException {
SSLContextBuilder builder = new SSLContextBuilder();
char[] keyPassword = keyPassword();
KeyStore keyStore = createKeyStore();
private String fileExtensionOf(Resource resource) {
String name = resource.getFilename();
int index = name.lastIndexOf('.');
try {
builder.loadKeyMaterial(keyStore, keyPassword);
} catch (UnrecoverableKeyException e) {
if (keyPassword.length == 0) {
// Retry if empty password, see https://rt.openssl.org/Ticket/Display.html?id=1497&user=guest&pass=guest
builder.loadKeyMaterial(keyStore, new char[]{'\0'});
} else {
throw e;
}
}
return index < 0 ? "" : name.substring(index + 1).toLowerCase();
}
KeyStore trust = createTrustStore();
if (trust != null) {
builder.loadTrustMaterial(trust, null);
}
public SSLContext createSSLContext()
throws GeneralSecurityException, IOException {
SSLContextBuilder builder = new SSLContextBuilder();
char[] keyPassword = keyPassword();
KeyStore keyStore = createKeyStore();
return builder.build();
}
try {
builder.loadKeyMaterial(keyStore, keyPassword);
}
catch (UnrecoverableKeyException e) {
if (keyPassword.length == 0) {
// Retry if empty password, see
// https://rt.openssl.org/Ticket/Display.html?id=1497&user=guest&pass=guest
builder.loadKeyMaterial(keyStore, new char[] { '\0' });
}
else {
throw e;
}
}
private KeyStore createKeyStore() throws GeneralSecurityException, IOException {
if (keyStore == null) {
throw new KeyStoreException("Keystore not specified.");
}
if (!keyStore.exists()) {
throw new KeyStoreException("Keystore not exists: " + keyStore);
}
KeyStore trust = createTrustStore();
if (trust != null) {
builder.loadTrustMaterial(trust, null);
}
KeyStore result = KeyStore.getInstance(keyStoreType);
char[] keyStorePassword = keyStorePassword();
return builder.build();
}
try {
loadKeyStore(result, keyStore, keyStorePassword);
} catch (IOException e) {
// Retry if empty password, see https://rt.openssl.org/Ticket/Display.html?id=1497&user=guest&pass=guest
if (keyStorePassword.length == 0) {
loadKeyStore(result, keyStore, new char[]{'\0'});
} else {
throw e;
}
}
private KeyStore createKeyStore() throws GeneralSecurityException, IOException {
if (keyStore == null) {
throw new KeyStoreException("Keystore not specified.");
}
if (!keyStore.exists()) {
throw new KeyStoreException("Keystore not exists: " + keyStore);
}
return result;
}
KeyStore result = KeyStore.getInstance(keyStoreType);
char[] keyStorePassword = keyStorePassword();
private static void loadKeyStore(KeyStore keyStore, Resource keyStoreResource, char[] keyStorePassword)
throws IOException, GeneralSecurityException
{
try (InputStream inputStream = keyStoreResource.getInputStream()) {
keyStore.load(inputStream, keyStorePassword);
}
}
try {
loadKeyStore(result, keyStore, keyStorePassword);
}
catch (IOException e) {
// Retry if empty password, see
// https://rt.openssl.org/Ticket/Display.html?id=1497&user=guest&pass=guest
if (keyStorePassword.length == 0) {
loadKeyStore(result, keyStore, new char[] { '\0' });
}
else {
throw e;
}
}
private KeyStore createTrustStore() throws GeneralSecurityException, IOException {
if (trustStore == null) {
return null;
}
if (!trustStore.exists()) {
throw new KeyStoreException("KeyStore not exists: " + trustStore);
}
return result;
}
private static void loadKeyStore(KeyStore keyStore, Resource keyStoreResource,
char[] keyStorePassword) throws IOException, GeneralSecurityException {
try (InputStream inputStream = keyStoreResource.getInputStream()) {
keyStore.load(inputStream, keyStorePassword);
}
}
private KeyStore createTrustStore() throws GeneralSecurityException, IOException {
if (trustStore == null) {
return null;
}
if (!trustStore.exists()) {
throw new KeyStoreException("KeyStore not exists: " + trustStore);
}
KeyStore result = KeyStore.getInstance(trustStoreType);
try (InputStream input = trustStore.getInputStream()) {
result.load(input, trustStorePassword());
}
return result;
}
KeyStore result = KeyStore.getInstance(trustStoreType);
try (InputStream input = trustStore.getInputStream()) {
result.load(input, trustStorePassword());
}
return result;
}
}
}

View File

@@ -33,6 +33,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginTrackedValue;
@@ -308,7 +309,7 @@ public class ConfigServicePropertySourceLocator implements PropertySourceLocator
if (client.getRequestConnectTimeout() < 0) {
throw new IllegalStateException("Invalid Value for Connect Timeout set.");
}
ClientHttpRequestFactory requestFactory = createHttpRquestFactory(client);
RestTemplate template = new RestTemplate(requestFactory);
Map<String, String> headers = new HashMap<>(client.getHeaders());
@@ -322,28 +323,33 @@ public class ConfigServicePropertySourceLocator implements PropertySourceLocator
return template;
}
private ClientHttpRequestFactory createHttpRquestFactory(ConfigClientProperties client) {
private ClientHttpRequestFactory createHttpRquestFactory(
ConfigClientProperties client) {
if (client.getTls().isEnabled()) {
try {
SSLContext sslContext = client.getTls().createSSLContext();
HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
HttpComponentsClientHttpRequestFactory result = new HttpComponentsClientHttpRequestFactory(httpClient);
result.setReadTimeout(client.getRequestReadTimeout());
result.setConnectTimeout(client.getRequestConnectTimeout());
return result;
} catch (GeneralSecurityException | IOException ex) {
SSLContext sslContext = client.getTls().createSSLContext();
HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext)
.build();
HttpComponentsClientHttpRequestFactory result = new HttpComponentsClientHttpRequestFactory(
httpClient);
result.setReadTimeout(client.getRequestReadTimeout());
result.setConnectTimeout(client.getRequestConnectTimeout());
return result;
}
catch (GeneralSecurityException | IOException ex) {
logger.error(ex);
throw new IllegalStateException("Failed to create config client with TLS.", ex);
throw new IllegalStateException(
"Failed to create config client with TLS.", ex);
}
}
SimpleClientHttpRequestFactory result = new SimpleClientHttpRequestFactory();
result.setReadTimeout(client.getRequestReadTimeout());
result.setConnectTimeout(client.getRequestConnectTimeout());
return result;
result.setReadTimeout(client.getRequestReadTimeout());
result.setConnectTimeout(client.getRequestConnectTimeout());
return result;
}
private void addAuthorizationToken(ConfigClientProperties configClientProperties,