Browse Source
Add auto-configuration for SSL bundles including new configuration
properties that can be used to define a bundle.
SSL bundle properties are provided under the `spring.ssl.bundle` key.
Currently `jks` and `pem` variants are support. Both are configured
as a `Map` where the bundle name is the key.
A typical example would be:
spring:
ssl:
bundle:
pem:
mybundle
key:
password: secret
keystore:
certificate: classpath:mycert.pem
private-key: classpath:mykey.pem
A `SslBundleRegistrar` interface is also provided to allow programmatic
contributions to the auto-configured `SslBundleRegistry`.
See gh-34814
pull/35107/head
12 changed files with 845 additions and 0 deletions
@ -0,0 +1,108 @@
@@ -0,0 +1,108 @@
|
||||
/* |
||||
* 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 org.springframework.boot.ssl.jks.JksSslStoreBundle; |
||||
|
||||
/** |
||||
* {@link SslBundleProperties} for Java keystores. |
||||
* |
||||
* @author Scott Frederick |
||||
* @author Phillip Webb |
||||
* @since 3.1.0 |
||||
* @see JksSslStoreBundle |
||||
*/ |
||||
public class JksSslBundleProperties extends SslBundleProperties { |
||||
|
||||
/** |
||||
* Keystore properties. |
||||
*/ |
||||
private final Store keystore = new Store(); |
||||
|
||||
/** |
||||
* Truststore properties. |
||||
*/ |
||||
private final Store truststore = new Store(); |
||||
|
||||
public Store getKeystore() { |
||||
return this.keystore; |
||||
} |
||||
|
||||
public Store getTruststore() { |
||||
return this.truststore; |
||||
} |
||||
|
||||
/** |
||||
* Store properties. |
||||
*/ |
||||
public static class Store { |
||||
|
||||
/** |
||||
* Type of the store to create, e.g. JKS. |
||||
*/ |
||||
private String type; |
||||
|
||||
/** |
||||
* Provider for the store. |
||||
*/ |
||||
private String provider; |
||||
|
||||
/** |
||||
* Location of the resource containing the store content. |
||||
*/ |
||||
private String location; |
||||
|
||||
/** |
||||
* Password used to access the store. |
||||
*/ |
||||
private String password; |
||||
|
||||
public String getType() { |
||||
return this.type; |
||||
} |
||||
|
||||
public void setType(String type) { |
||||
this.type = type; |
||||
} |
||||
|
||||
public String getProvider() { |
||||
return this.provider; |
||||
} |
||||
|
||||
public void setProvider(String provider) { |
||||
this.provider = provider; |
||||
} |
||||
|
||||
public String getLocation() { |
||||
return this.location; |
||||
} |
||||
|
||||
public void setLocation(String location) { |
||||
this.location = location; |
||||
} |
||||
|
||||
public String getPassword() { |
||||
return this.password; |
||||
} |
||||
|
||||
public void setPassword(String password) { |
||||
this.password = password; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,95 @@
@@ -0,0 +1,95 @@
|
||||
/* |
||||
* 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 org.springframework.boot.ssl.pem.PemSslStoreBundle; |
||||
|
||||
/** |
||||
* {@link SslBundleProperties} for PEM-encoded certificates and private keys. |
||||
* |
||||
* @author Scott Frederick |
||||
* @author Phillip Webb |
||||
* @since 3.1.0 |
||||
* @see PemSslStoreBundle |
||||
*/ |
||||
public class PemSslBundleProperties extends SslBundleProperties { |
||||
|
||||
/** |
||||
* Keystore properties. |
||||
*/ |
||||
private Store keystore = new Store(); |
||||
|
||||
/** |
||||
* Truststore properties. |
||||
*/ |
||||
private Store truststore = new Store(); |
||||
|
||||
public Store getKeystore() { |
||||
return this.keystore; |
||||
} |
||||
|
||||
public Store getTruststore() { |
||||
return this.truststore; |
||||
} |
||||
|
||||
/** |
||||
* Store properties. |
||||
*/ |
||||
public static class Store { |
||||
|
||||
/** |
||||
* Type of the store to create, e.g. JKS. |
||||
*/ |
||||
String type; |
||||
|
||||
/** |
||||
* Location or content of the certificate in PEM format. |
||||
*/ |
||||
String certificate; |
||||
|
||||
/** |
||||
* Location or content of the private key in PEM format. |
||||
*/ |
||||
String privateKey; |
||||
|
||||
public String getType() { |
||||
return this.type; |
||||
} |
||||
|
||||
public void setType(String type) { |
||||
this.type = type; |
||||
} |
||||
|
||||
public String getCertificate() { |
||||
return this.certificate; |
||||
} |
||||
|
||||
public void setCertificate(String certificate) { |
||||
this.certificate = certificate; |
||||
} |
||||
|
||||
public String getPrivateKey() { |
||||
return this.privateKey; |
||||
} |
||||
|
||||
public void setPrivateKey(String privateKey) { |
||||
this.privateKey = privateKey; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,131 @@
@@ -0,0 +1,131 @@
|
||||
/* |
||||
* 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 org.springframework.boot.autoconfigure.ssl.SslBundleProperties.Key; |
||||
import org.springframework.boot.ssl.SslBundle; |
||||
import org.springframework.boot.ssl.SslBundleKey; |
||||
import org.springframework.boot.ssl.SslManagerBundle; |
||||
import org.springframework.boot.ssl.SslOptions; |
||||
import org.springframework.boot.ssl.SslStoreBundle; |
||||
import org.springframework.boot.ssl.jks.JksSslStoreBundle; |
||||
import org.springframework.boot.ssl.jks.JksSslStoreDetails; |
||||
import org.springframework.boot.ssl.pem.PemSslStoreBundle; |
||||
import org.springframework.boot.ssl.pem.PemSslStoreDetails; |
||||
|
||||
/** |
||||
* {@link SslBundle} backed by {@link JksSslBundleProperties} or |
||||
* {@link PemSslBundleProperties}. |
||||
* |
||||
* @author Scott Frederick |
||||
* @author Phillip Webb |
||||
* @since 3.1.0 |
||||
*/ |
||||
public final class PropertiesSslBundle implements SslBundle { |
||||
|
||||
private final SslStoreBundle stores; |
||||
|
||||
private final SslBundleKey key; |
||||
|
||||
private final SslOptions options; |
||||
|
||||
private final String protocol; |
||||
|
||||
private final SslManagerBundle managers; |
||||
|
||||
private PropertiesSslBundle(SslStoreBundle stores, SslBundleProperties properties) { |
||||
this.stores = stores; |
||||
this.key = asSslKeyReference(properties.getKey()); |
||||
this.options = asSslOptions(properties.getOptions()); |
||||
this.protocol = properties.getProtocol(); |
||||
this.managers = SslManagerBundle.from(this.stores, this.key); |
||||
} |
||||
|
||||
private static SslBundleKey asSslKeyReference(Key key) { |
||||
return (key != null) ? SslBundleKey.of(key.getPassword(), key.getAlias()) : SslBundleKey.NONE; |
||||
} |
||||
|
||||
private static SslOptions asSslOptions(SslBundleProperties.Options properties) { |
||||
return (properties != null) ? SslOptions.of(properties.getCiphers(), properties.getEnabledProtocols()) |
||||
: SslOptions.NONE; |
||||
} |
||||
|
||||
@Override |
||||
public SslStoreBundle getStores() { |
||||
return this.stores; |
||||
} |
||||
|
||||
@Override |
||||
public SslBundleKey getKey() { |
||||
return this.key; |
||||
} |
||||
|
||||
@Override |
||||
public SslOptions getOptions() { |
||||
return this.options; |
||||
} |
||||
|
||||
@Override |
||||
public String getProtocol() { |
||||
return this.protocol; |
||||
} |
||||
|
||||
@Override |
||||
public SslManagerBundle getManagers() { |
||||
return this.managers; |
||||
} |
||||
|
||||
/** |
||||
* Get an {@link SslBundle} for the given {@link PemSslBundleProperties}. |
||||
* @param properties the source properties |
||||
* @return an {@link SslBundle} instance |
||||
*/ |
||||
public static SslBundle get(PemSslBundleProperties properties) { |
||||
return new PropertiesSslBundle(asSslStoreBundle(properties), properties); |
||||
} |
||||
|
||||
/** |
||||
* Get an {@link SslBundle} for the given {@link JksSslBundleProperties}. |
||||
* @param properties the source properties |
||||
* @return an {@link SslBundle} instance |
||||
*/ |
||||
public static SslBundle get(JksSslBundleProperties properties) { |
||||
return new PropertiesSslBundle(asSslStoreBundle(properties), properties); |
||||
} |
||||
|
||||
private static SslStoreBundle asSslStoreBundle(PemSslBundleProperties properties) { |
||||
PemSslStoreDetails keyStoreDetails = asStoreDetails(properties.getKeystore()); |
||||
PemSslStoreDetails trustStoreDetails = asStoreDetails(properties.getTruststore()); |
||||
return new PemSslStoreBundle(keyStoreDetails, trustStoreDetails, properties.getKey().getAlias()); |
||||
} |
||||
|
||||
private static PemSslStoreDetails asStoreDetails(PemSslBundleProperties.Store properties) { |
||||
return new PemSslStoreDetails(properties.getType(), properties.getCertificate(), properties.getPrivateKey()); |
||||
} |
||||
|
||||
private static SslStoreBundle asSslStoreBundle(JksSslBundleProperties properties) { |
||||
JksSslStoreDetails keyStoreDetails = asStoreDetails(properties.getKeystore()); |
||||
JksSslStoreDetails trustStoreDetails = asStoreDetails(properties.getTruststore()); |
||||
return new JksSslStoreBundle(keyStoreDetails, trustStoreDetails); |
||||
} |
||||
|
||||
private static JksSslStoreDetails asStoreDetails(JksSslBundleProperties.Store properties) { |
||||
return new JksSslStoreDetails(properties.getType(), properties.getProvider(), properties.getLocation(), |
||||
properties.getPassword()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
/* |
||||
* 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.util.List; |
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.boot.ssl.DefaultSslBundleRegistry; |
||||
import org.springframework.boot.ssl.SslBundleRegistry; |
||||
import org.springframework.boot.ssl.SslBundles; |
||||
import org.springframework.context.annotation.Bean; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for SSL. |
||||
* |
||||
* @author Scott Frederick |
||||
* @since 3.1.0 |
||||
*/ |
||||
@AutoConfiguration |
||||
@EnableConfigurationProperties(SslProperties.class) |
||||
public class SslAutoConfiguration { |
||||
|
||||
SslAutoConfiguration() { |
||||
} |
||||
|
||||
@Bean |
||||
public SslPropertiesBundleRegistrar sslPropertiesSslBundleRegistrar(SslProperties sslProperties) { |
||||
return new SslPropertiesBundleRegistrar(sslProperties); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean({ SslBundleRegistry.class, SslBundles.class }) |
||||
public DefaultSslBundleRegistry sslBundleRegistry(List<SslBundleRegistrar> sslBundleRegistrars) { |
||||
DefaultSslBundleRegistry registry = new DefaultSslBundleRegistry(); |
||||
sslBundleRegistrars.forEach((registrar) -> registrar.registerBundles(registry)); |
||||
return registry; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,124 @@
@@ -0,0 +1,124 @@
|
||||
/* |
||||
* 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.util.Set; |
||||
|
||||
import org.springframework.boot.ssl.SslBundle; |
||||
|
||||
/** |
||||
* Base class for SSL Bundle properties. |
||||
* |
||||
* @author Scott Frederick |
||||
* @author Phillip Webb |
||||
* @since 3.1.0 |
||||
* @see SslBundle |
||||
*/ |
||||
public abstract class SslBundleProperties { |
||||
|
||||
/** |
||||
* Key details for the bundle. |
||||
*/ |
||||
private final Key key = new Key(); |
||||
|
||||
/** |
||||
* Options for the SLL connection. |
||||
*/ |
||||
private final Options options = new Options(); |
||||
|
||||
/** |
||||
* SSL Protocol to use. |
||||
*/ |
||||
private String protocol = SslBundle.DEFAULT_PROTOCOL; |
||||
|
||||
public Key getKey() { |
||||
return this.key; |
||||
} |
||||
|
||||
public Options getOptions() { |
||||
return this.options; |
||||
} |
||||
|
||||
public String getProtocol() { |
||||
return this.protocol; |
||||
} |
||||
|
||||
public void setProtocol(String protocol) { |
||||
this.protocol = protocol; |
||||
} |
||||
|
||||
public static class Options { |
||||
|
||||
/** |
||||
* Supported SSL ciphers. |
||||
*/ |
||||
private Set<String> ciphers; |
||||
|
||||
/** |
||||
* Enabled SSL protocols. |
||||
*/ |
||||
private Set<String> enabledProtocols; |
||||
|
||||
public Set<String> getCiphers() { |
||||
return this.ciphers; |
||||
} |
||||
|
||||
public void setCiphers(Set<String> ciphers) { |
||||
this.ciphers = ciphers; |
||||
} |
||||
|
||||
public Set<String> getEnabledProtocols() { |
||||
return this.enabledProtocols; |
||||
} |
||||
|
||||
public void setEnabledProtocols(Set<String> enabledProtocols) { |
||||
this.enabledProtocols = enabledProtocols; |
||||
} |
||||
|
||||
} |
||||
|
||||
public static class Key { |
||||
|
||||
/** |
||||
* The password used to access the key in the key store. |
||||
*/ |
||||
private String password; |
||||
|
||||
/** |
||||
* The alias that identifies the key in the key store. |
||||
*/ |
||||
private String alias; |
||||
|
||||
public String getPassword() { |
||||
return this.password; |
||||
} |
||||
|
||||
public void setPassword(String password) { |
||||
this.password = password; |
||||
} |
||||
|
||||
public String getAlias() { |
||||
return this.alias; |
||||
} |
||||
|
||||
public void setAlias(String alias) { |
||||
this.alias = alias; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
/* |
||||
* 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 org.springframework.boot.ssl.SslBundle; |
||||
import org.springframework.boot.ssl.SslBundleRegistry; |
||||
|
||||
/** |
||||
* Interface to be implemented by types that register {@link SslBundle} instances with an |
||||
* {@link SslBundleRegistry}. |
||||
* |
||||
* @author Scott Frederick |
||||
* @since 3.1.0 |
||||
*/ |
||||
@FunctionalInterface |
||||
public interface SslBundleRegistrar { |
||||
|
||||
/** |
||||
* Callback method for registering {@link SslBundle}s with an |
||||
* {@link SslBundleRegistry}. |
||||
* @param registry the registry that accepts {@code SslBundle}s |
||||
*/ |
||||
void registerBundles(SslBundleRegistry registry); |
||||
|
||||
} |
||||
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
/* |
||||
* 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.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty; |
||||
|
||||
/** |
||||
* Properties for centralized SSL trust material configuration. |
||||
* |
||||
* @author Scott Frederick |
||||
* @since 3.1.0 |
||||
*/ |
||||
@ConfigurationProperties(prefix = "spring.ssl") |
||||
public class SslProperties { |
||||
|
||||
/** |
||||
* SSL bundles. |
||||
*/ |
||||
private final Bundles bundle = new Bundles(); |
||||
|
||||
public Bundles getBundle() { |
||||
return this.bundle; |
||||
} |
||||
|
||||
/** |
||||
* Properties to define SSL Bundles. |
||||
*/ |
||||
public static class Bundles { |
||||
|
||||
/** |
||||
* PEM-encoded SSL trust material. |
||||
*/ |
||||
@NestedConfigurationProperty |
||||
private final Map<String, PemSslBundleProperties> pem = new LinkedHashMap<>(); |
||||
|
||||
/** |
||||
* Java keystore SSL trust material. |
||||
*/ |
||||
@NestedConfigurationProperty |
||||
private final Map<String, JksSslBundleProperties> jks = new LinkedHashMap<>(); |
||||
|
||||
public Map<String, PemSslBundleProperties> getPem() { |
||||
return this.pem; |
||||
} |
||||
|
||||
public Map<String, JksSslBundleProperties> getJks() { |
||||
return this.jks; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
/* |
||||
* 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.util.Map; |
||||
import java.util.function.Function; |
||||
|
||||
import org.springframework.boot.ssl.SslBundle; |
||||
import org.springframework.boot.ssl.SslBundleRegistry; |
||||
|
||||
/** |
||||
* A {@link SslBundleRegistrar} that registers SSL bundles based |
||||
* {@link SslProperties#getBundle() configuration properties}. |
||||
* |
||||
* @author Scott Frederick |
||||
* @author Phillip Webb |
||||
*/ |
||||
class SslPropertiesBundleRegistrar implements SslBundleRegistrar { |
||||
|
||||
private final SslProperties.Bundles properties; |
||||
|
||||
SslPropertiesBundleRegistrar(SslProperties properties) { |
||||
this.properties = properties.getBundle(); |
||||
} |
||||
|
||||
@Override |
||||
public void registerBundles(SslBundleRegistry registry) { |
||||
registerBundles(registry, this.properties.getPem(), PropertiesSslBundle::get); |
||||
registerBundles(registry, this.properties.getJks(), PropertiesSslBundle::get); |
||||
} |
||||
|
||||
private <P extends SslBundleProperties> void registerBundles(SslBundleRegistry registry, Map<String, P> properties, |
||||
Function<P, SslBundle> bundleFactory) { |
||||
properties.forEach((bundleName, bundleProperties) -> registry.registerBundle(bundleName, |
||||
bundleFactory.apply(bundleProperties))); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
/* |
||||
* 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. |
||||
*/ |
||||
|
||||
/** |
||||
* Auto-configuration for SSL bundles. |
||||
*/ |
||||
package org.springframework.boot.autoconfigure.ssl; |
||||
@ -0,0 +1,145 @@
@@ -0,0 +1,145 @@
|
||||
/* |
||||
* 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.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations; |
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.boot.ssl.SslBundle; |
||||
import org.springframework.boot.ssl.SslBundleRegistry; |
||||
import org.springframework.boot.ssl.SslBundles; |
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link SslAutoConfiguration}. |
||||
* |
||||
* @author Scott Frederick |
||||
* @author Phillip Webb |
||||
*/ |
||||
class SslAutoConfigurationTests { |
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() |
||||
.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class)); |
||||
|
||||
@Test |
||||
void sslBundlesCreatedWithNoConfiguration() { |
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(SslBundleRegistry.class)); |
||||
} |
||||
|
||||
@Test |
||||
void sslBundlesCreatedWithCertificates() { |
||||
List<String> propertyValues = new ArrayList<>(); |
||||
propertyValues.add("spring.ssl.bundle.pem.first.key.alias=alias1"); |
||||
propertyValues.add("spring.ssl.bundle.pem.first.key.password=secret1"); |
||||
propertyValues.add("spring.ssl.bundle.pem.first.keystore.certificate=cert1.pem"); |
||||
propertyValues.add("spring.ssl.bundle.pem.first.keystore.private-key=key1.pem"); |
||||
propertyValues.add("spring.ssl.bundle.pem.first.keystore.type=JKS"); |
||||
propertyValues.add("spring.ssl.bundle.pem.first.truststore.type=PKCS12"); |
||||
propertyValues.add("spring.ssl.bundle.pem.second.key.alias=alias2"); |
||||
propertyValues.add("spring.ssl.bundle.pem.second.key.password=secret2"); |
||||
propertyValues.add("spring.ssl.bundle.pem.second.keystore.certificate=cert2.pem"); |
||||
propertyValues.add("spring.ssl.bundle.pem.second.keystore.private-key=key2.pem"); |
||||
propertyValues.add("spring.ssl.bundle.pem.second.keystore.type=PKCS12"); |
||||
propertyValues.add("spring.ssl.bundle.pem.second.truststore.certificate=ca.pem"); |
||||
propertyValues.add("spring.ssl.bundle.pem.second.truststore.private-key=ca-key.pem"); |
||||
propertyValues.add("spring.ssl.bundle.pem.second.truststore.type=JKS"); |
||||
this.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> { |
||||
assertThat(context).hasSingleBean(SslBundles.class); |
||||
SslBundles bundles = context.getBean(SslBundles.class); |
||||
SslBundle first = bundles.getBundle("first"); |
||||
assertThat(first).isNotNull(); |
||||
assertThat(first.getStores()).isNotNull(); |
||||
assertThat(first.getManagers()).isNotNull(); |
||||
assertThat(first.getKey().getAlias()).isEqualTo("alias1"); |
||||
assertThat(first.getKey().getPassword()).isEqualTo("secret1"); |
||||
assertThat(first.getStores()).extracting("keyStoreDetails").extracting("type").isEqualTo("JKS"); |
||||
assertThat(first.getStores()).extracting("trustStoreDetails").extracting("type").isEqualTo("PKCS12"); |
||||
SslBundle second = bundles.getBundle("second"); |
||||
assertThat(second).isNotNull(); |
||||
assertThat(second.getStores()).isNotNull(); |
||||
assertThat(second.getManagers()).isNotNull(); |
||||
assertThat(second.getKey().getAlias()).isEqualTo("alias2"); |
||||
assertThat(second.getKey().getPassword()).isEqualTo("secret2"); |
||||
assertThat(second.getStores()).extracting("keyStoreDetails").extracting("type").isEqualTo("PKCS12"); |
||||
assertThat(second.getStores()).extracting("trustStoreDetails").extracting("type").isEqualTo("JKS"); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
void sslBundlesCreatedWithCustomSslBundle() { |
||||
List<String> propertyValues = new ArrayList<>(); |
||||
propertyValues.add("custom.ssl.key.alias=alias1"); |
||||
propertyValues.add("custom.ssl.key.password=secret1"); |
||||
propertyValues.add("custom.ssl.keystore.type=JKS"); |
||||
propertyValues.add("custom.ssl.truststore.type=PKCS12"); |
||||
this.contextRunner.withUserConfiguration(CustomSslBundleConfiguration.class) |
||||
.withPropertyValues(propertyValues.toArray(String[]::new)) |
||||
.run((context) -> { |
||||
assertThat(context).hasSingleBean(SslBundles.class); |
||||
SslBundles bundles = context.getBean(SslBundles.class); |
||||
SslBundle first = bundles.getBundle("custom"); |
||||
assertThat(first).isNotNull(); |
||||
assertThat(first.getStores()).isNotNull(); |
||||
assertThat(first.getManagers()).isNotNull(); |
||||
assertThat(first.getKey().getAlias()).isEqualTo("alias1"); |
||||
assertThat(first.getKey().getPassword()).isEqualTo("secret1"); |
||||
assertThat(first.getStores()).extracting("keyStoreDetails").extracting("type").isEqualTo("JKS"); |
||||
assertThat(first.getStores()).extracting("trustStoreDetails").extracting("type").isEqualTo("PKCS12"); |
||||
}); |
||||
} |
||||
|
||||
@Configuration |
||||
@EnableConfigurationProperties(CustomSslProperties.class) |
||||
public static class CustomSslBundleConfiguration { |
||||
|
||||
@Bean |
||||
public SslBundleRegistrar customSslBundlesRegistrar(CustomSslProperties properties) { |
||||
return new CustomSslBundlesRegistrar(properties); |
||||
} |
||||
|
||||
} |
||||
|
||||
@ConfigurationProperties("custom.ssl") |
||||
static class CustomSslProperties extends PemSslBundleProperties { |
||||
|
||||
} |
||||
|
||||
static class CustomSslBundlesRegistrar implements SslBundleRegistrar { |
||||
|
||||
private final CustomSslProperties properties; |
||||
|
||||
CustomSslBundlesRegistrar(CustomSslProperties properties) { |
||||
this.properties = properties; |
||||
} |
||||
|
||||
@Override |
||||
public void registerBundles(SslBundleRegistry registry) { |
||||
registry.registerBundle("custom", PropertiesSslBundle.get(this.properties)); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue