From ce379d5e31ea4bbdfa856045f9171bc78a988a85 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 28 Jun 2023 13:07:33 +0100 Subject: [PATCH 1/8] Update RSA library version --- spring-cloud-commons-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-commons-dependencies/pom.xml b/spring-cloud-commons-dependencies/pom.xml index ef27c26b..af5e1263 100644 --- a/spring-cloud-commons-dependencies/pom.xml +++ b/spring-cloud-commons-dependencies/pom.xml @@ -15,7 +15,7 @@ spring-cloud-commons-dependencies Spring Cloud Commons Dependencies - 1.0.12.RELEASE + 1.1.0 From 0a531d2930c36a555ee51970b68bc7400fbc58c1 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 28 Jun 2023 12:30:00 +0000 Subject: [PATCH 2/8] Remove obsolete code --- .../context/encrypt/EncryptorFactory.java | 38 +------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java index 71bf521c..82369935 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java @@ -16,18 +16,6 @@ package org.springframework.cloud.context.encrypt; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.regex.Pattern; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.openssl.MiscPEMGenerator; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.util.io.pem.PemObjectGenerator; -import org.bouncycastle.util.io.pem.PemWriter; - import org.springframework.security.crypto.encrypt.Encryptors; import org.springframework.security.crypto.encrypt.TextEncryptor; import org.springframework.security.rsa.crypto.RsaSecretEncryptor; @@ -38,8 +26,6 @@ import org.springframework.security.rsa.crypto.RsaSecretEncryptor; */ public class EncryptorFactory { - private static final Pattern NEWLINE_ESCAPE_PATTERN = Pattern.compile("\\r|\\n"); - private String salt = "deadbeef"; public EncryptorFactory() { @@ -54,9 +40,9 @@ public class EncryptorFactory { TextEncryptor encryptor; if (data.contains("RSA PRIVATE KEY")) { + encryptor = new RsaSecretEncryptor(data); + try { - String normalizedPemData = normalizePem(data); - encryptor = new RsaSecretEncryptor(NEWLINE_ESCAPE_PATTERN.matcher(normalizedPemData).replaceAll("")); } catch (IllegalArgumentException e) { throw new KeyFormatException(e); @@ -73,24 +59,4 @@ public class EncryptorFactory { return encryptor; } - private String normalizePem(String data) { - PEMKeyPair pemKeyPair = null; - try (PEMParser pemParser = new PEMParser(new StringReader(data))) { - pemKeyPair = (PEMKeyPair) pemParser.readObject(); - PrivateKeyInfo privateKeyInfo = pemKeyPair.getPrivateKeyInfo(); - - StringWriter textWriter = new StringWriter(); - try (PemWriter pemWriter = new PemWriter(textWriter)) { - PemObjectGenerator pemObjectGenerator = new MiscPEMGenerator(privateKeyInfo); - - pemWriter.writeObject(pemObjectGenerator); - pemWriter.flush(); - return textWriter.toString(); - } - } - catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); - } - } - } From f0ccaf01aca260a30db2fde05d309d7922a75522 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 28 Jun 2023 12:30:00 +0000 Subject: [PATCH 3/8] Remove obsolete code --- .../context/encrypt/EncryptorFactory.java | 44 +------------------ 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java index 71bf521c..7ad230d0 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java @@ -16,18 +16,6 @@ package org.springframework.cloud.context.encrypt; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.regex.Pattern; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.openssl.MiscPEMGenerator; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.util.io.pem.PemObjectGenerator; -import org.bouncycastle.util.io.pem.PemWriter; - import org.springframework.security.crypto.encrypt.Encryptors; import org.springframework.security.crypto.encrypt.TextEncryptor; import org.springframework.security.rsa.crypto.RsaSecretEncryptor; @@ -38,8 +26,6 @@ import org.springframework.security.rsa.crypto.RsaSecretEncryptor; */ public class EncryptorFactory { - private static final Pattern NEWLINE_ESCAPE_PATTERN = Pattern.compile("\\r|\\n"); - private String salt = "deadbeef"; public EncryptorFactory() { @@ -53,15 +39,7 @@ public class EncryptorFactory { TextEncryptor encryptor; if (data.contains("RSA PRIVATE KEY")) { - - try { - String normalizedPemData = normalizePem(data); - encryptor = new RsaSecretEncryptor(NEWLINE_ESCAPE_PATTERN.matcher(normalizedPemData).replaceAll("")); - } - catch (IllegalArgumentException e) { - throw new KeyFormatException(e); - } - + encryptor = new RsaSecretEncryptor(data); } else if (data.startsWith("ssh-rsa") || data.contains("RSA PUBLIC KEY")) { throw new KeyFormatException(); @@ -73,24 +51,4 @@ public class EncryptorFactory { return encryptor; } - private String normalizePem(String data) { - PEMKeyPair pemKeyPair = null; - try (PEMParser pemParser = new PEMParser(new StringReader(data))) { - pemKeyPair = (PEMKeyPair) pemParser.readObject(); - PrivateKeyInfo privateKeyInfo = pemKeyPair.getPrivateKeyInfo(); - - StringWriter textWriter = new StringWriter(); - try (PemWriter pemWriter = new PemWriter(textWriter)) { - PemObjectGenerator pemObjectGenerator = new MiscPEMGenerator(privateKeyInfo); - - pemWriter.writeObject(pemObjectGenerator); - pemWriter.flush(); - return textWriter.toString(); - } - } - catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); - } - } - } From 2e8631b12739f8ae5cc9ec28d9574da3ec405b68 Mon Sep 17 00:00:00 2001 From: Olga MaciaszekSharma Date: Wed, 28 Jun 2023 14:48:22 +0200 Subject: [PATCH 4/8] Call `get(Request request)` on delegates by default. --- .../main/asciidoc/spring-cloud-commons.adoc | 2 +- .../loadbalancer/LoadBalancerProperties.java | 28 ++----------------- ...renceServiceInstanceListSupplierTests.java | 1 - ...ghtedServiceInstanceListSupplierTests.java | 1 - ...renceServiceInstanceListSupplierTests.java | 1 - 5 files changed, 4 insertions(+), 29 deletions(-) diff --git a/docs/src/main/asciidoc/spring-cloud-commons.adoc b/docs/src/main/asciidoc/spring-cloud-commons.adoc index 58cc2808..080c2753 100644 --- a/docs/src/main/asciidoc/spring-cloud-commons.adoc +++ b/docs/src/main/asciidoc/spring-cloud-commons.adoc @@ -1375,7 +1375,7 @@ The per-client configuration properties work for most of the properties, apart f NOTE: For the properties where maps where already used, where you can specify a different value per-client without using the `clients` keyword (for example, `hints`, `health-check.path`), we have kept that behaviour in order to keep the library backwards compatible. It will be modified in the next major release. -NOTE: Starting with `4.0.4`, we have introduced the `callGetWithRequestOnDelegates` flag in `LoadBalancerProperties`. If this flag is set to `true`, `ServiceInstanceListSupplier#get(Request request)` method will be implemented to call `delegate.get(request)` in classes assignable from `DelegatingServiceInstanceListSupplier` that don't already implement that method, with the exclusion of `CachingServiceInstanceListSupplier` and `HealthCheckServiceInstanceListSupplier`, which should be placed in the instance supplier hierarchy directly after the supplier performing instance retrieval over the network, before any request-based filtering is done. For `4.0.x` the flag is set to `false` by default, however, since `4.1.0` it's going to be set to `true` by default. +NOTE: Starting with `4.1.0`, we have introduced the `callGetWithRequestOnDelegates` flag in `LoadBalancerProperties`. If this flag is set to `true`, `ServiceInstanceListSupplier#get(Request request)` method will be implemented to call `delegate.get(request)` in classes assignable from `DelegatingServiceInstanceListSupplier` that don't already implement that method, with the exclusion of `CachingServiceInstanceListSupplier` and `HealthCheckServiceInstanceListSupplier`, which should be placed in the instance supplier hierarchy directly after the supplier performing instance retrieval over the network, before any request-based filtering is done. It is set to `true` by default. === AOT and Native Image Support diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerProperties.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerProperties.java index 0e2c2121..dd93f89a 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerProperties.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerProperties.java @@ -80,10 +80,10 @@ public class LoadBalancerProperties { * method, with the exclusion of {@code CachingServiceInstanceListSupplier} and * {@code HealthCheckServiceInstanceListSupplier}, which should be placed in the * instance supplier hierarchy directly after the supplier performing instance - * retrieval over the network, before any request-based filtering is done. Note: in - * 4.1, this behaviour will become the default + * retrieval over the network, before any request-based filtering is done, + * {@code true} by default. */ - private boolean callGetWithRequestOnDelegates; + private boolean callGetWithRequestOnDelegates = true; public HealthCheck getHealthCheck() { return healthCheck; @@ -138,32 +138,10 @@ public class LoadBalancerProperties { return xForwarded; } - /** - * If this flag is set to {@code true}, - * {@code ServiceInstanceListSupplier#get(Request request)} method will be implemented - * to call {@code delegate.get(request)} in classes assignable from - * {@code DelegatingServiceInstanceListSupplier} that don't already implement that - * method, with the exclusion of {@code CachingServiceInstanceListSupplier} and - * {@code HealthCheckServiceInstanceListSupplier}, which should be placed in the - * instance supplier hierarchy directly after the supplier performing instance - * retrieval over the network, before any request-based filtering is done. Note: in - * 4.1, this behaviour will become the default - */ public boolean isCallGetWithRequestOnDelegates() { return callGetWithRequestOnDelegates; } - /** - * If this flag is set to {@code true}, - * {@code ServiceInstanceListSupplier#get(Request request)} method will be implemented - * to call {@code delegate.get(request)} in classes assignable from - * {@code DelegatingServiceInstanceListSupplier} that don't already implement that - * method, with the exclusion of {@code CachingServiceInstanceListSupplier} and - * {@code HealthCheckServiceInstanceListSupplier}, which should be placed in the - * instance supplier hierarchy directly after the supplier performing instance - * retrieval over the network, before any request-based filtering is done. Note: in - * 4.1, this behaviour will become the default - */ public void setCallGetWithRequestOnDelegates(boolean callGetWithRequestOnDelegates) { this.callGetWithRequestOnDelegates = callGetWithRequestOnDelegates; } diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java index 81995b89..cb29c871 100644 --- a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java +++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/SameInstancePreferenceServiceInstanceListSupplierTests.java @@ -62,7 +62,6 @@ class SameInstancePreferenceServiceInstanceListSupplierTests { @BeforeEach void setUp() { LoadBalancerProperties properties = new LoadBalancerProperties(); - properties.setCallGetWithRequestOnDelegates(true); when(loadBalancerClientFactory.getProperties(any())).thenReturn(properties); supplier = new SameInstancePreferenceServiceInstanceListSupplier(delegate, loadBalancerClientFactory); } diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/WeightedServiceInstanceListSupplierTests.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/WeightedServiceInstanceListSupplierTests.java index 58c00682..94c35020 100644 --- a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/WeightedServiceInstanceListSupplierTests.java +++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/WeightedServiceInstanceListSupplierTests.java @@ -188,7 +188,6 @@ class WeightedServiceInstanceListSupplierTests { void shouldCallGetRequestOnDelegate() { LoadBalancerClientFactory loadBalancerClientFactory = mock(LoadBalancerClientFactory.class); LoadBalancerProperties properties = new LoadBalancerProperties(); - properties.setCallGetWithRequestOnDelegates(true); when(loadBalancerClientFactory.getProperties(any())).thenReturn(properties); ServiceInstance one = serviceInstance("test-1", Collections.emptyMap()); ServiceInstance two = serviceInstance("test-2", Collections.emptyMap()); diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/ZonePreferenceServiceInstanceListSupplierTests.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/ZonePreferenceServiceInstanceListSupplierTests.java index f04c9ba8..cea7bde2 100644 --- a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/ZonePreferenceServiceInstanceListSupplierTests.java +++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/core/ZonePreferenceServiceInstanceListSupplierTests.java @@ -70,7 +70,6 @@ class ZonePreferenceServiceInstanceListSupplierTests { @BeforeEach void setUp() { LoadBalancerProperties properties = new LoadBalancerProperties(); - properties.setCallGetWithRequestOnDelegates(true); when(loadBalancerClientFactory.getProperties(any())).thenReturn(properties); supplier = new ZonePreferenceServiceInstanceListSupplier(delegate, zoneConfig, loadBalancerClientFactory); } From e090bd234fee680801defdb4c1d65a1b002d5299 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 28 Jun 2023 14:46:08 +0000 Subject: [PATCH 5/8] Fix dependencies --- spring-cloud-commons-dependencies/pom.xml | 2 +- .../springframework/cloud/context/encrypt/EncryptorFactory.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-cloud-commons-dependencies/pom.xml b/spring-cloud-commons-dependencies/pom.xml index af5e1263..c4f526a0 100644 --- a/spring-cloud-commons-dependencies/pom.xml +++ b/spring-cloud-commons-dependencies/pom.xml @@ -15,7 +15,7 @@ spring-cloud-commons-dependencies Spring Cloud Commons Dependencies - 1.1.0 + 1.1.1 diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java index 7ad230d0..1064704b 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/encrypt/EncryptorFactory.java @@ -39,7 +39,7 @@ public class EncryptorFactory { TextEncryptor encryptor; if (data.contains("RSA PRIVATE KEY")) { - encryptor = new RsaSecretEncryptor(data); + encryptor = new RsaSecretEncryptor(data.replaceAll("\\n *", "")); } else if (data.startsWith("ssh-rsa") || data.contains("RSA PUBLIC KEY")) { throw new KeyFormatException(); From 78b96e6160bc33f4713efc24fcf6d739d13f1408 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 28 Jun 2023 15:05:35 +0000 Subject: [PATCH 6/8] Add bouncycastle in test scope (temporarily?) --- spring-cloud-commons/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spring-cloud-commons/pom.xml b/spring-cloud-commons/pom.xml index 6fcfa118..4fc9ba42 100644 --- a/spring-cloud-commons/pom.xml +++ b/spring-cloud-commons/pom.xml @@ -187,5 +187,11 @@ micrometer-observation-test test + + org.bouncycastle + bcpkix-jdk18on + 1.74 + test + From f1840b51d07bef3fc6b33164e4a26532d5caaca2 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 28 Jun 2023 15:39:44 +0000 Subject: [PATCH 7/8] Move certs into files --- spring-cloud-commons/pom.xml | 6 - .../cloud/configuration/KeyAndCert.java | 93 -------------- .../cloud/configuration/KeyTool.java | 113 ------------------ .../configuration/SSHContextFactoryTests.java | 58 ++------- .../src/test/resources/MyCA.p12 | Bin 0 -> 822 bytes .../src/test/resources/MyCert.p12 | Bin 0 -> 1736 bytes 6 files changed, 8 insertions(+), 262 deletions(-) delete mode 100644 spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/KeyAndCert.java delete mode 100644 spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/KeyTool.java create mode 100644 spring-cloud-commons/src/test/resources/MyCA.p12 create mode 100644 spring-cloud-commons/src/test/resources/MyCert.p12 diff --git a/spring-cloud-commons/pom.xml b/spring-cloud-commons/pom.xml index 4fc9ba42..6fcfa118 100644 --- a/spring-cloud-commons/pom.xml +++ b/spring-cloud-commons/pom.xml @@ -187,11 +187,5 @@ micrometer-observation-test test - - org.bouncycastle - bcpkix-jdk18on - 1.74 - test - diff --git a/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/KeyAndCert.java b/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/KeyAndCert.java deleted file mode 100644 index b3fb81ca..00000000 --- a/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/KeyAndCert.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2018-2019 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 - * - * https://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.cloud.configuration; - -import java.security.KeyPair; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.PublicKey; -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.getSubjectX500Principal().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; - } - -} diff --git a/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/KeyTool.java b/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/KeyTool.java deleted file mode 100644 index ea403d16..00000000 --- a/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/KeyTool.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2018-2019 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 - * - * https://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.cloud.configuration; - -import java.math.BigInteger; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; -import java.util.Date; - -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.BasicConstraints; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.KeyUsage; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; -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); - } - -} diff --git a/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/SSHContextFactoryTests.java b/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/SSHContextFactoryTests.java index 0732d399..6fbcc4c2 100644 --- a/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/SSHContextFactoryTests.java +++ b/spring-cloud-commons/src/test/java/org/springframework/cloud/configuration/SSHContextFactoryTests.java @@ -16,10 +16,7 @@ package org.springframework.cloud.configuration; -import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.security.GeneralSecurityException; import java.security.Key; import java.security.KeyStore; @@ -27,11 +24,10 @@ import java.security.cert.Certificate; import javax.net.ssl.SSLContext; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import static org.assertj.core.api.Assertions.assertThat; @@ -42,60 +38,22 @@ public class SSHContextFactoryTests { private static final String KEY_PASSWORD = "test-key-password"; - private static KeyAndCert ca; - - private static KeyAndCert cert; - - private static File keyStore; - - private static File trustStore; - private TlsProperties properties; - @BeforeAll - public static void createKeyStoreAndTrustStore() throws Exception { - KeyTool tool = new KeyTool(); - - ca = tool.createCA("MyCA"); - cert = ca.sign("MyCert"); - - keyStore = saveKeyAndCert(cert); - trustStore = saveCert(ca); - } - - 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; - } - @BeforeEach public void createProperties() { properties = new TlsProperties(); properties.setEnabled(true); - properties.setKeyStore(resourceOf(keyStore)); + properties.setKeyStore(resourceOf("MyCert.p12")); properties.setKeyStorePassword(KEY_STORE_PASSWORD); properties.setKeyPassword(KEY_PASSWORD); - properties.setTrustStore(resourceOf(trustStore)); + properties.setTrustStore(resourceOf("MyCA.p12")); properties.setTrustStorePassword(KEY_STORE_PASSWORD); } - private Resource resourceOf(File file) { - return new FileSystemResource(file); + private Resource resourceOf(String path) { + return new ClassPathResource(path); } @Test @@ -104,10 +62,10 @@ public class SSHContextFactoryTests { KeyStore store = factory.createKeyStore(); Certificate c = store.getCertificate("MyCert"); - assertThat(c).isEqualTo(cert.certificate()); + assertThat(c).isNotNull(); Key key = store.getKey("MyCert", KEY_PASSWORD.toCharArray()); - assertThat(key).isEqualTo(cert.privateKey()); + assertThat(key).isNotNull(); } @Test @@ -116,7 +74,7 @@ public class SSHContextFactoryTests { KeyStore store = factory.createTrustStore(); Certificate c = store.getCertificate("MyCA"); - assertThat(c).isEqualTo(ca.certificate()); + assertThat(c).isNotNull(); } @Test diff --git a/spring-cloud-commons/src/test/resources/MyCA.p12 b/spring-cloud-commons/src/test/resources/MyCA.p12 new file mode 100644 index 0000000000000000000000000000000000000000..ba068e07f1355b176b39e16629e751bb1a0c8228 GIT binary patch literal 822 zcmXqLVm4x8WHxAGy2Hk))#lOmotKfFaX}N)S(YZIlR)94KztA(#Rinx1Qc4w#K-`o zmLp^s4btEoR$hZh0}BL~$3UA!L@}VPME4x?=}C=$UZ$Pj*nT6B>lG7|x&RZSf&mX3 z2gGtFPF4m3SvJmuHV?*BW)?;*7J-k;ZZf>PtE8AMS7gofcAZ{B6O#d>hn$hq%VYU@ z6%UU55qh+`?OJPOh#jNbwAhCVY_i2~iiElDGFNL2Qx{wQ=;-g~69KY?zkL z4w85%!;~{yaBYp3miBk&yy=;L-fg$uv0ZaTLElsVNwa_J$T@HXdzvk=U%aOM_`@hc zi#r|9Dw_iyzl=?Ex-xzb|;h&F(pNJO1gY#+xtMU;b77 zz0a?Q`OAO5yZ$k|uD`PE)ce!ZTnkiAyc5awI4C^JHmNG$aNSBpmp?5wk9roU{&m{U zIq$^$|Npvs6ZftcJmwr4G^JgQZ)eHXJ-?VUbn?Ub#CVjYlV4OU0?BupcTbdUs*!(I;?`t&oAZyHvDy>u zv*$l}F=pRl{}yFty>M0GV<(0QN)uk6SiQaA@I3yzQ~vr*UNb}S1=H2}FOS`eba=h~ z)~PxtPeEUHgGbF0udljhp77Z6!)xY=mX7wxrMH&vdb8Pb-ZQ19aPjUwPR^*SsbM&5oAe lD>9TbWY@8X6vVlg|EyWCe)igfcY`FI_w1Q8>oq9J0s#1YaCQIy literal 0 HcmV?d00001 diff --git a/spring-cloud-commons/src/test/resources/MyCert.p12 b/spring-cloud-commons/src/test/resources/MyCert.p12 new file mode 100644 index 0000000000000000000000000000000000000000..ed30bb999ffb63fb2340d5ebf31a3191c622275e GIT binary patch literal 1736 zcma)6dpOez7~XF;*C9<;2`Rd;--cPJDON61xn-h>+)}C~jV=zqmXzxf(U^^ALRNE` zQp-syr<+`7a!nSpCn@*GIgaz3^XNH$o%6@{e9!m3-~0Xbz8?sopThwJ2%%4+RkkEJ zCQM@hC4dK^{gDvbcMBf-As~B?Srt z`hcXLqdK@1iJjWo`h+%M&vx2(!RU~ug(ex%a1{Y?|l~w9QSM_fe)<6fk?p{I0X66x~)^f#vZ8ak70DTrB>sdB-FoZa*f9v3Z2^ zIp~LRV^NjzP(QL;V=l0KGo#k#1-0u;TcM=D`**3w8bQ}k3vDCUNuKW4a$K_0eK4qR zZj*uOfEjH1?0TcAFSfeTyR?};JE)stlYo({(gPbmu1@dVh_Q_8J~O-dv=?e-fp`kNRDpVS8dLsKYr;~~*n>kF`7BWP{8l3c7ZAB6o+k7B zz1&<7e7(Kzi(|%#iC0eK7_!0evz`T9LT3IW3f)}gPTi%emCiD!oqC+OP;Nl7wbA@6 zFQ+&MCz^mw$?4=bm+CD}zX-SYUHkf}N*>PU>OPZ%1TW6Zv~xr!lXv6z51qK!?Z%~W z$=izUW2quzvG%>aKio76zJ87u)fZ7SYq;5Fy=vc2Nlpto=){%S^bRQLVll66Wsz0o zilNcZbJ$c8p^5K`WKhozBcyohwOzG=2wK6r;o-oi07PrG80gPO7l3*T@eDqqNDl&x+E_*zaaoDljP%$if0#oK{vm+Y;A#cSxP z!y;fYu%obG*csSa(BLPjgU2GZJM>*I+etL;Q0NCK@u!eU~^mzI>!iy<0VgnHos zY_WCxWPtyQRdr2cUqKi?B`W$tV%;uJ+UMwk>)ndx} z8`L?jEQL$G{>?r<7J#l)H74F83W{xXGq=SxW-%oJHp{{TwOT*2xmH!m z1}VC~)qV_ZOoItO=v%~pn6ANfRQVqX^(LQ~H{5!qs3n9b8Ml_73~McyIu#F|=oKNU z2j9KQzmU9>xx4wCM)0_wgDwXavsXUa?B<>8LV4b$I$39G$eL|DSVars$+_KXO^g*s zN5X=*x2Zm9V)=}nw}{6RM?8A({ILtI+uRygr_2IE2&4sanaO_9n({oQh-@ZU@-nMh zg}&2c?1jIzEnoCnYSs}@?+L7j6s@DWg+?h{;SQsgjY zmV^@Tu;a|$9{j2Od#Dkcn?+yo0Fr+>^h1Oo#uE`f1 zbq+O7DN!l{Mz-;8CHJ$kQOQB~cYQ-*nQAVa+`yH4ocnX)Ypa{ Date: Thu, 29 Jun 2023 10:27:16 +0200 Subject: [PATCH 8/8] Update config property info. --- docs/src/main/asciidoc/_configprops.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/_configprops.adoc b/docs/src/main/asciidoc/_configprops.adoc index 7185f92c..25b25fea 100644 --- a/docs/src/main/asciidoc/_configprops.adoc +++ b/docs/src/main/asciidoc/_configprops.adoc @@ -37,7 +37,7 @@ |spring.cloud.loadbalancer.cache.capacity | `+++256+++` | Initial cache capacity expressed as int. |spring.cloud.loadbalancer.cache.enabled | `+++true+++` | Enables Spring Cloud LoadBalancer caching mechanism. |spring.cloud.loadbalancer.cache.ttl | `+++35s+++` | Time To Live - time counted from writing of the record, after which cache entries are expired, expressed as a {@link Duration}. The property {@link String} has to be in keeping with the appropriate syntax as specified in Spring Boot StringToDurationConverter. @see StringToDurationConverter.java -|spring.cloud.loadbalancer.call-get-with-request-on-delegates | `+++false+++` | If this flag is set to {@code true}, {@code ServiceInstanceListSupplier#get(Request request)} method will be implemented to call {@code delegate.get(request)} in classes assignable from {@code DelegatingServiceInstanceListSupplier} that don't already implement that method, with the exclusion of {@code CachingServiceInstanceListSupplier} and {@code HealthCheckServiceInstanceListSupplier}, which should be placed in the instance supplier hierarchy directly after the supplier performing instance retrieval over the network, before any request-based filtering is done. Note: in 4.1, this behaviour will become the default +|spring.cloud.loadbalancer.call-get-with-request-on-delegates | `+++true+++` | If this flag is set to {@code true}, {@code ServiceInstanceListSupplier#get(Request request)} method will be implemented to call {@code delegate.get(request)} in classes assignable from {@code DelegatingServiceInstanceListSupplier} that don't already implement that method, with the exclusion of {@code CachingServiceInstanceListSupplier} and {@code HealthCheckServiceInstanceListSupplier}, which should be placed in the instance supplier hierarchy directly after the supplier performing instance retrieval over the network, before any request-based filtering is done, {@code true} by default. |spring.cloud.loadbalancer.clients | | |spring.cloud.loadbalancer.configurations | `+++default+++` | Enables a predefined LoadBalancer configuration. |spring.cloud.loadbalancer.eager-load.clients | | Names of the clients.