Polish and refactor some SSL internals
Polish and refactor some of the internal SSL code to make it easier to add additional functionality in the future.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.boot.autoconfigure.ssl;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.springframework.boot.ssl.pem.PemContent;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Helper utility to manage a single bundle content configuration property. May possibly
|
||||
* contain PEM content, a location or a directory search pattern.
|
||||
*
|
||||
* @param name the configuration property name (excluding any prefix)
|
||||
* @param value the configuration property value
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
record BundleContentProperty(String name, String value) {
|
||||
|
||||
/**
|
||||
* Return if the property value is PEM content.
|
||||
* @return if the value is PEM content
|
||||
*/
|
||||
boolean isPemContent() {
|
||||
return PemContent.isPresentInText(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if there is any property value present.
|
||||
* @return if the value is present
|
||||
*/
|
||||
boolean hasValue() {
|
||||
return StringUtils.hasText(this.value);
|
||||
}
|
||||
|
||||
private URL toUrl() throws FileNotFoundException {
|
||||
Assert.state(!isPemContent(), "Value contains PEM content");
|
||||
return ResourceUtils.getURL(this.value);
|
||||
}
|
||||
|
||||
Path toWatchPath() {
|
||||
return toPath();
|
||||
}
|
||||
|
||||
private Path toPath() {
|
||||
try {
|
||||
URL url = toUrl();
|
||||
Assert.state(isFileUrl(url), () -> "Vaule '%s' is not a file URL".formatted(url));
|
||||
return Path.of(url.toURI()).toAbsolutePath();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Unable to convert '%s' property to a path".formatted(this.name), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFileUrl(URL url) {
|
||||
return "file".equalsIgnoreCase(url.getProtocol());
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ public class PemSslBundleProperties extends SslBundleProperties {
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* Location or content of the certificate in PEM format.
|
||||
* Location or content of the certificate or certificate chain in PEM format.
|
||||
*/
|
||||
private String certificate;
|
||||
|
||||
|
||||
@@ -99,7 +99,35 @@ public final class PropertiesSslBundle implements SslBundle {
|
||||
* @return an {@link SslBundle} instance
|
||||
*/
|
||||
public static SslBundle get(PemSslBundleProperties properties) {
|
||||
return new PropertiesSslBundle(asSslStoreBundle(properties), properties);
|
||||
try {
|
||||
PemSslStore keyStore = getPemSslStore("keystore", properties.getKeystore());
|
||||
if (keyStore != null) {
|
||||
keyStore = keyStore.withAlias(properties.getKey().getAlias())
|
||||
.withPassword(properties.getKey().getPassword());
|
||||
}
|
||||
PemSslStore trustStore = getPemSslStore("truststore", properties.getTruststore());
|
||||
SslStoreBundle storeBundle = new PemSslStoreBundle(keyStore, trustStore);
|
||||
return new PropertiesSslBundle(storeBundle, properties);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static PemSslStore getPemSslStore(String propertyName, PemSslBundleProperties.Store properties)
|
||||
throws IOException {
|
||||
PemSslStore pemSslStore = PemSslStore.load(asPemSslStoreDetails(properties));
|
||||
if (properties.isVerifyKeys()) {
|
||||
CertificateMatcher certificateMatcher = new CertificateMatcher(pemSslStore.privateKey());
|
||||
Assert.state(certificateMatcher.matchesAny(pemSslStore.certificates()),
|
||||
"Private key matches none of the certificates in the chain");
|
||||
}
|
||||
return pemSslStore;
|
||||
}
|
||||
|
||||
private static PemSslStoreDetails asPemSslStoreDetails(PemSslBundleProperties.Store properties) {
|
||||
return new PemSslStoreDetails(properties.getType(), properties.getCertificate(), properties.getPrivateKey(),
|
||||
properties.getPrivateKeyPassword());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,38 +136,8 @@ public final class PropertiesSslBundle implements SslBundle {
|
||||
* @return an {@link SslBundle} instance
|
||||
*/
|
||||
public static SslBundle get(JksSslBundleProperties properties) {
|
||||
return new PropertiesSslBundle(asSslStoreBundle(properties), properties);
|
||||
}
|
||||
|
||||
private static SslStoreBundle asSslStoreBundle(PemSslBundleProperties properties) {
|
||||
PemSslStore keyStore = asPemSslStore(properties.getKeystore());
|
||||
if (keyStore != null) {
|
||||
keyStore = keyStore.withAlias(properties.getKey().getAlias())
|
||||
.withPassword(properties.getKey().getPassword());
|
||||
}
|
||||
PemSslStore trustStore = asPemSslStore(properties.getTruststore());
|
||||
return new PemSslStoreBundle(keyStore, trustStore);
|
||||
}
|
||||
|
||||
private static PemSslStore asPemSslStore(PemSslBundleProperties.Store properties) {
|
||||
try {
|
||||
PemSslStoreDetails details = asStoreDetails(properties);
|
||||
PemSslStore pemSslStore = PemSslStore.load(details);
|
||||
if (properties.isVerifyKeys()) {
|
||||
CertificateMatcher certificateMatcher = new CertificateMatcher(pemSslStore.privateKey());
|
||||
Assert.state(certificateMatcher.matchesAny(pemSslStore.certificates()),
|
||||
"Private key matches none of the certificates in the chain");
|
||||
}
|
||||
return pemSslStore;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static PemSslStoreDetails asStoreDetails(PemSslBundleProperties.Store properties) {
|
||||
return new PemSslStoreDetails(properties.getType(), properties.getCertificate(), properties.getPrivateKey(),
|
||||
properties.getPrivateKeyPassword());
|
||||
SslStoreBundle storeBundle = asSslStoreBundle(properties);
|
||||
return new PropertiesSslBundle(storeBundle, properties);
|
||||
}
|
||||
|
||||
private static SslStoreBundle asSslStoreBundle(JksSslBundleProperties properties) {
|
||||
|
||||
@@ -16,20 +16,17 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.ssl;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundleRegistry;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link SslBundleRegistrar} that registers SSL bundles based
|
||||
@@ -41,8 +38,6 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
class SslPropertiesBundleRegistrar implements SslBundleRegistrar {
|
||||
|
||||
private static final Pattern PEM_CONTENT = Pattern.compile("-+BEGIN\\s+[^-]*-+", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private final SslProperties.Bundles properties;
|
||||
|
||||
private final FileWatcher fileWatcher;
|
||||
@@ -54,70 +49,58 @@ class SslPropertiesBundleRegistrar implements SslBundleRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerBundles(SslBundleRegistry registry) {
|
||||
registerBundles(registry, this.properties.getPem(), PropertiesSslBundle::get, this::getLocations);
|
||||
registerBundles(registry, this.properties.getJks(), PropertiesSslBundle::get, this::getLocations);
|
||||
registerBundles(registry, this.properties.getPem(), PropertiesSslBundle::get, this::watchedPemPaths);
|
||||
registerBundles(registry, this.properties.getJks(), PropertiesSslBundle::get, this::watchedJksPaths);
|
||||
}
|
||||
|
||||
private <P extends SslBundleProperties> void registerBundles(SslBundleRegistry registry, Map<String, P> properties,
|
||||
Function<P, SslBundle> bundleFactory, Function<P, Set<Location>> locationsSupplier) {
|
||||
Function<P, SslBundle> bundleFactory, Function<P, Set<Path>> watchedPaths) {
|
||||
properties.forEach((bundleName, bundleProperties) -> {
|
||||
SslBundle bundle = bundleFactory.apply(bundleProperties);
|
||||
registry.registerBundle(bundleName, bundle);
|
||||
if (bundleProperties.isReloadOnUpdate()) {
|
||||
Set<Path> paths = locationsSupplier.apply(bundleProperties)
|
||||
.stream()
|
||||
.filter(Location::hasValue)
|
||||
.map((location) -> toPath(bundleName, location))
|
||||
.collect(Collectors.toSet());
|
||||
this.fileWatcher.watch(paths,
|
||||
() -> registry.updateBundle(bundleName, bundleFactory.apply(bundleProperties)));
|
||||
Supplier<SslBundle> bundleSupplier = () -> bundleFactory.apply(bundleProperties);
|
||||
try {
|
||||
registry.registerBundle(bundleName, bundleSupplier.get());
|
||||
if (bundleProperties.isReloadOnUpdate()) {
|
||||
Supplier<Set<Path>> pathsSupplier = () -> watchedPaths.apply(bundleProperties);
|
||||
watchForUpdates(registry, bundleName, pathsSupplier, bundleSupplier);
|
||||
}
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
throw new IllegalStateException("Unable to register SSL bundle '%s'".formatted(bundleName), ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Set<Location> getLocations(JksSslBundleProperties properties) {
|
||||
JksSslBundleProperties.Store keystore = properties.getKeystore();
|
||||
JksSslBundleProperties.Store truststore = properties.getTruststore();
|
||||
Set<Location> locations = new LinkedHashSet<>();
|
||||
locations.add(new Location("keystore.location", keystore.getLocation()));
|
||||
locations.add(new Location("truststore.location", truststore.getLocation()));
|
||||
return locations;
|
||||
}
|
||||
|
||||
private Set<Location> getLocations(PemSslBundleProperties properties) {
|
||||
PemSslBundleProperties.Store keystore = properties.getKeystore();
|
||||
PemSslBundleProperties.Store truststore = properties.getTruststore();
|
||||
Set<Location> locations = new LinkedHashSet<>();
|
||||
locations.add(new Location("keystore.private-key", keystore.getPrivateKey()));
|
||||
locations.add(new Location("keystore.certificate", keystore.getCertificate()));
|
||||
locations.add(new Location("truststore.private-key", truststore.getPrivateKey()));
|
||||
locations.add(new Location("truststore.certificate", truststore.getCertificate()));
|
||||
return locations;
|
||||
}
|
||||
|
||||
private Path toPath(String bundleName, Location watchableLocation) {
|
||||
String value = watchableLocation.value();
|
||||
String field = watchableLocation.field();
|
||||
Assert.state(!PEM_CONTENT.matcher(value).find(),
|
||||
() -> "SSL bundle '%s' '%s' is not a URL and can't be watched".formatted(bundleName, field));
|
||||
private void watchForUpdates(SslBundleRegistry registry, String bundleName, Supplier<Set<Path>> pathsSupplier,
|
||||
Supplier<SslBundle> bundleSupplier) {
|
||||
try {
|
||||
URL url = ResourceUtils.getURL(value);
|
||||
Assert.state("file".equalsIgnoreCase(url.getProtocol()),
|
||||
() -> "SSL bundle '%s' '%s' URL '%s' doesn't point to a file".formatted(bundleName, field, url));
|
||||
return Path.of(url.toURI()).toAbsolutePath();
|
||||
this.fileWatcher.watch(pathsSupplier.get(), () -> registry.updateBundle(bundleName, bundleSupplier.get()));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException(
|
||||
"SSL bundle '%s' '%s' location '%s' cannot be watched".formatted(bundleName, field, value), ex);
|
||||
catch (RuntimeException ex) {
|
||||
throw new IllegalStateException("Unable to watch for reload on update", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private record Location(String field, String value) {
|
||||
private Set<Path> watchedJksPaths(JksSslBundleProperties properties) {
|
||||
List<BundleContentProperty> watched = new ArrayList<>();
|
||||
watched.add(new BundleContentProperty("keystore.location", properties.getKeystore().getLocation()));
|
||||
watched.add(new BundleContentProperty("truststore.location", properties.getTruststore().getLocation()));
|
||||
return watchedPaths(watched);
|
||||
}
|
||||
|
||||
boolean hasValue() {
|
||||
return StringUtils.hasText(this.value);
|
||||
}
|
||||
private Set<Path> watchedPemPaths(PemSslBundleProperties properties) {
|
||||
List<BundleContentProperty> watched = new ArrayList<>();
|
||||
watched.add(new BundleContentProperty("keystore.private-key", properties.getKeystore().getPrivateKey()));
|
||||
watched.add(new BundleContentProperty("keystore.certificate", properties.getKeystore().getCertificate()));
|
||||
watched.add(new BundleContentProperty("truststore.private-key", properties.getTruststore().getPrivateKey()));
|
||||
watched.add(new BundleContentProperty("truststore.certificate", properties.getTruststore().getCertificate()));
|
||||
return watchedPaths(watched);
|
||||
}
|
||||
|
||||
private Set<Path> watchedPaths(List<BundleContentProperty> properties) {
|
||||
return properties.stream()
|
||||
.filter(BundleContentProperty::hasValue)
|
||||
.map(BundleContentProperty::toWatchPath)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.boot.autoconfigure.ssl;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link BundleContentProperty}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class BundleContentPropertyTests {
|
||||
|
||||
private static final String PEM_TEXT = """
|
||||
-----BEGIN CERTIFICATE-----
|
||||
-----END CERTIFICATE-----
|
||||
""";
|
||||
|
||||
@TempDir
|
||||
Path temp;
|
||||
|
||||
@Test
|
||||
void isPemContentWhenValueIsPemTextReturnsTrue() {
|
||||
BundleContentProperty property = new BundleContentProperty("name", PEM_TEXT);
|
||||
assertThat(property.isPemContent()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPemContentWhenValueIsNotPemTextReturnsFalse() {
|
||||
BundleContentProperty property = new BundleContentProperty("name", "file.pem");
|
||||
assertThat(property.isPemContent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasValueWhenHasValueReturnsTrue() {
|
||||
BundleContentProperty property = new BundleContentProperty("name", "file.pem");
|
||||
assertThat(property.hasValue()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasValueWhenHasNullValueReturnsFalse() {
|
||||
BundleContentProperty property = new BundleContentProperty("name", null);
|
||||
assertThat(property.hasValue()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasValueWhenHasEmptyValueReturnsFalse() {
|
||||
BundleContentProperty property = new BundleContentProperty("name", "");
|
||||
assertThat(property.hasValue()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void toWatchPathWhenNotPathThrowsException() {
|
||||
BundleContentProperty property = new BundleContentProperty("name", PEM_TEXT);
|
||||
assertThatIllegalStateException().isThrownBy(property::toWatchPath)
|
||||
.withMessage("Unable to convert 'name' property to a path");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toWatchPathWhenPathReturnsPath() {
|
||||
Path file = this.temp.toAbsolutePath().resolve("file.txt");
|
||||
BundleContentProperty property = new BundleContentProperty("name", file.toString());
|
||||
assertThat(property.toWatchPath()).isEqualTo(file);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -106,7 +106,9 @@ class SslPropertiesBundleRegistrarTests {
|
||||
""".strip());
|
||||
this.properties.getBundle().getPem().put("bundle1", pem);
|
||||
assertThatIllegalStateException().isThrownBy(() -> this.registrar.registerBundles(this.registry))
|
||||
.withMessage("SSL bundle 'bundle1' 'keystore.certificate' is not a URL and can't be watched");
|
||||
.withMessageContaining("Unable to register SSL bundle 'bundle1'")
|
||||
.havingCause()
|
||||
.withMessage("Unable to watch for reload on update");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,7 +123,9 @@ class SslPropertiesBundleRegistrarTests {
|
||||
""".strip());
|
||||
this.properties.getBundle().getPem().put("bundle1", pem);
|
||||
assertThatIllegalStateException().isThrownBy(() -> this.registrar.registerBundles(this.registry))
|
||||
.withMessage("SSL bundle 'bundle1' 'keystore.private-key' is not a URL and can't be watched");
|
||||
.withMessageContaining("Unable to register SSL bundle 'bundle1'")
|
||||
.havingCause()
|
||||
.withMessage("Unable to watch for reload on update");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -145,7 +149,9 @@ class SslPropertiesBundleRegistrarTests {
|
||||
""".strip());
|
||||
this.properties.getBundle().getPem().put("bundle1", pem);
|
||||
assertThatIllegalStateException().isThrownBy(() -> this.registrar.registerBundles(this.registry))
|
||||
.withMessage("SSL bundle 'bundle1' 'truststore.certificate' is not a URL and can't be watched");
|
||||
.withMessageContaining("Unable to register SSL bundle 'bundle1'")
|
||||
.havingCause()
|
||||
.withMessage("Unable to watch for reload on update");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -160,7 +166,9 @@ class SslPropertiesBundleRegistrarTests {
|
||||
""".strip());
|
||||
this.properties.getBundle().getPem().put("bundle1", pem);
|
||||
assertThatIllegalStateException().isThrownBy(() -> this.registrar.registerBundles(this.registry))
|
||||
.withMessage("SSL bundle 'bundle1' 'truststore.private-key' is not a URL and can't be watched");
|
||||
.withMessageContaining("Unable to register SSL bundle 'bundle1'")
|
||||
.havingCause()
|
||||
.withMessage("Unable to watch for reload on update");
|
||||
}
|
||||
|
||||
private void pathEndingWith(Set<Path> paths, String... suffixes) {
|
||||
|
||||
@@ -105,8 +105,8 @@ public final class PemContent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load {@link PemContent} from the given content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL}).
|
||||
* Load {@link PemContent} from the given content (either the PEM content itself or a
|
||||
* reference to the resource to load).
|
||||
* @param content the content to load
|
||||
* @return a new {@link PemContent} instance
|
||||
* @throws IOException on IO error
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.boot.ssl.pem;
|
||||
|
||||
import java.security.KeyStore;
|
||||
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -30,12 +29,12 @@ import org.springframework.util.StringUtils;
|
||||
* @param password the password used
|
||||
* {@link KeyStore#setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[])
|
||||
* setting key entries} in the {@link KeyStore}
|
||||
* @param certificates the certificates content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL}). When a
|
||||
* {@link #privateKey() private key} is present this value is treated as a certificate
|
||||
* chain, otherwise it is treated a list of certificates that should all be registered.
|
||||
* @param privateKey the private key content (either the PEM content itself or something
|
||||
* that can be loaded by {@link ResourceUtils#getURL})
|
||||
* @param certificates the certificates content (either the PEM content itself or or a
|
||||
* reference to the resource to load). When a {@link #privateKey() private key} is present
|
||||
* this value is treated as a certificate chain, otherwise it is treated a list of
|
||||
* certificates that should all be registered.
|
||||
* @param privateKey the private key content (either the PEM content itself or a reference
|
||||
* to the resource to load)
|
||||
* @param privateKeyPassword a password used to decrypt an encrypted private key
|
||||
* @author Scott Frederick
|
||||
* @author Phillip Webb
|
||||
@@ -53,10 +52,10 @@ public record PemSslStoreDetails(String type, String alias, String password, Str
|
||||
* @param password the password used
|
||||
* {@link KeyStore#setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[])
|
||||
* setting key entries} in the {@link KeyStore}
|
||||
* @param certificates the certificate content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL})
|
||||
* @param privateKey the private key content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL})
|
||||
* @param certificates the certificate content (either the PEM content itself or a
|
||||
* reference to the resource to load)
|
||||
* @param privateKey the private key content (either the PEM content itself or a
|
||||
* reference to the resource to load)
|
||||
* @param privateKeyPassword a password used to decrypt an encrypted private key
|
||||
* @since 3.2.0
|
||||
*/
|
||||
@@ -67,10 +66,10 @@ public record PemSslStoreDetails(String type, String alias, String password, Str
|
||||
* Create a new {@link PemSslStoreDetails} instance.
|
||||
* @param type the key store type, for example {@code JKS} or {@code PKCS11}. A
|
||||
* {@code null} value will use {@link KeyStore#getDefaultType()}).
|
||||
* @param certificate the certificate content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL})
|
||||
* @param privateKey the private key content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL})
|
||||
* @param certificate the certificate content (either the PEM content itself or a
|
||||
* reference to the resource to load)
|
||||
* @param privateKey the private key content (either the PEM content itself or a
|
||||
* reference to the resource to load)
|
||||
* @param privateKeyPassword a password used to decrypt an encrypted private key
|
||||
*/
|
||||
public PemSslStoreDetails(String type, String certificate, String privateKey, String privateKeyPassword) {
|
||||
@@ -81,10 +80,10 @@ public record PemSslStoreDetails(String type, String alias, String password, Str
|
||||
* Create a new {@link PemSslStoreDetails} instance.
|
||||
* @param type the key store type, for example {@code JKS} or {@code PKCS11}. A
|
||||
* {@code null} value will use {@link KeyStore#getDefaultType()}).
|
||||
* @param certificate the certificate content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL})
|
||||
* @param privateKey the private key content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL})
|
||||
* @param certificate the certificate content (either the PEM content itself or a
|
||||
* reference to the resource to load)
|
||||
* @param privateKey the private key content (either the PEM content itself or a
|
||||
* reference to the resource to load)
|
||||
*/
|
||||
public PemSslStoreDetails(String type, String certificate, String privateKey) {
|
||||
this(type, certificate, privateKey, null);
|
||||
@@ -155,8 +154,8 @@ public record PemSslStoreDetails(String type, String alias, String password, Str
|
||||
* certificate. <b>Note:</b> This method doesn't actually check if the provided value
|
||||
* only contains a single certificate. It is functionally equivalent to
|
||||
* {@link #forCertificates(String)}.
|
||||
* @param certificate the certificate content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL})
|
||||
* @param certificate the certificate content (either the PEM content itself or a
|
||||
* reference to the resource to load)
|
||||
* @return a new {@link PemSslStoreDetails} instance.
|
||||
*/
|
||||
public static PemSslStoreDetails forCertificate(String certificate) {
|
||||
@@ -166,8 +165,8 @@ public record PemSslStoreDetails(String type, String alias, String password, Str
|
||||
/**
|
||||
* Factory method to create a new {@link PemSslStoreDetails} instance for the given
|
||||
* certificates.
|
||||
* @param certificates the certificates content (either the PEM content itself or
|
||||
* something that can be loaded by {@link ResourceUtils#getURL})
|
||||
* @param certificates the certificates content (either the PEM content itself or a
|
||||
* reference to the resource to load)
|
||||
* @return a new {@link PemSslStoreDetails} instance.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user