Skip to content

Commit 307c0af

Browse files
committed
[PR requested change] Add SSL
1 parent 363497e commit 307c0af

File tree

43 files changed

+2451
-604
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2451
-604
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*
2+
* Copyright 2012-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.pulsar;
18+
19+
import java.io.FileNotFoundException;
20+
import java.util.Arrays;
21+
import java.util.Set;
22+
import java.util.stream.Collectors;
23+
24+
import org.springframework.boot.autoconfigure.ssl.JksSslBundleProperties;
25+
import org.springframework.boot.autoconfigure.ssl.JksSslBundleProperties.Store;
26+
import org.springframework.boot.autoconfigure.ssl.PemSslBundleProperties;
27+
import org.springframework.boot.autoconfigure.ssl.SslProperties;
28+
import org.springframework.boot.context.properties.PropertyMapper;
29+
import org.springframework.boot.ssl.SslBundle;
30+
import org.springframework.boot.ssl.SslBundles;
31+
import org.springframework.boot.ssl.SslOptions;
32+
import org.springframework.boot.ssl.SslStoreBundle;
33+
import org.springframework.boot.ssl.jks.JksSslStoreBundle;
34+
import org.springframework.boot.ssl.pem.PemSslStoreBundle;
35+
import org.springframework.util.Assert;
36+
import org.springframework.util.ResourceUtils;
37+
38+
/**
39+
* Configures the SSL settings on {@link ClientBuilderSslSettings}.
40+
*
41+
* @author Chris Bono
42+
* @since 3.2.0
43+
*/
44+
public class ClientBuilderSslConfigurer {
45+
46+
private final SslBundles sslBundles;
47+
48+
private final SslProperties sslProperties;
49+
50+
/**
51+
* Construct a configurer using the specified SSL bundle and properties.
52+
* @param sslBundles optional ssl bundles configured for the application
53+
* @param sslProperties optional ssl properties for the application
54+
*/
55+
public ClientBuilderSslConfigurer(SslBundles sslBundles, SslProperties sslProperties) {
56+
this.sslBundles = sslBundles;
57+
this.sslProperties = sslProperties;
58+
}
59+
60+
/**
61+
* Applies the specified SSL properties to the specified client SSL builder.
62+
* @param clientBuilderSslSettings the ssl builder
63+
* @param clientSslProperties the ssl properties
64+
*/
65+
public void applySsl(ClientBuilderSslSettings<?> clientBuilderSslSettings,
66+
SslConfigProperties clientSslProperties) {
67+
if (!clientSslProperties.isEnabled()) {
68+
return;
69+
}
70+
clientBuilderSslSettings.enableTls(true);
71+
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
72+
map.from(clientSslProperties::isVerifyHostname).to(clientBuilderSslSettings::enableTlsHostnameVerification);
73+
map.from(clientSslProperties::getAllowInsecureConnection)
74+
.to(clientBuilderSslSettings::allowTlsInsecureConnection);
75+
if (clientSslProperties.getBundle() == null) {
76+
return;
77+
}
78+
Assert.state(this.sslBundles != null, "SSL enabled but no SSL bundles configured");
79+
Assert.state(this.sslProperties != null, "SSL enabled but no SSL properties configured");
80+
String bundleName = clientSslProperties.getBundle();
81+
SslBundle sslBundle = this.sslBundles.getBundle(bundleName);
82+
SslOptions sslOptions = sslBundle.getOptions();
83+
if (sslOptions.getCiphers() != null) {
84+
Set<String> tlsCiphers = Arrays.stream(sslOptions.getCiphers()).collect(Collectors.toSet());
85+
clientBuilderSslSettings.tlsCiphers(tlsCiphers);
86+
}
87+
if (sslOptions.getEnabledProtocols() != null) {
88+
Set<String> tlsProtocols = Arrays.stream(sslOptions.getEnabledProtocols()).collect(Collectors.toSet());
89+
clientBuilderSslSettings.tlsProtocols(tlsProtocols);
90+
}
91+
SslType sslBundleType = SslType.forSslStoreBundle(sslBundle.getStores());
92+
switch (sslBundleType) {
93+
case JKS -> applyJksSslProperties(clientBuilderSslSettings, map, bundleName);
94+
case PEM -> applyPemSslProperties(clientBuilderSslSettings, map, bundleName);
95+
case UNSUPPORTED -> throw new IllegalArgumentException(
96+
"Unsupported store bundle type %s".formatted(sslBundle.getStores().getClass().getName()));
97+
}
98+
}
99+
100+
private void applyJksSslProperties(ClientBuilderSslSettings<?> clientBuilderSslSettings, PropertyMapper map,
101+
String bundleName) {
102+
clientBuilderSslSettings.useKeyStoreTls(true);
103+
// Dip down into the ssl props for the info we need to set on the client builder
104+
JksSslBundleProperties jksProperties = this.sslProperties.getBundle().getJks().get(bundleName);
105+
Assert.state(jksProperties != null,
106+
() -> "SslStoreBundle is JKS but unable to find 'spring.ssl.bundle.jks.%s.*' properties"
107+
.formatted(bundleName));
108+
Store trustStore = jksProperties.getTruststore();
109+
map.from(trustStore::getType).to(clientBuilderSslSettings::tlsTrustStoreType);
110+
map.from(trustStore::getLocation).as(this::resolvePath).to(clientBuilderSslSettings::tlsTrustStorePath);
111+
map.from(trustStore::getPassword).to(clientBuilderSslSettings::tlsTrustStorePassword);
112+
map.from(trustStore::getProvider).to(clientBuilderSslSettings::sslProvider);
113+
Store keyStore = jksProperties.getKeystore();
114+
map.from(keyStore::getType).to(clientBuilderSslSettings::tlsKeyStoreType);
115+
map.from(keyStore::getLocation).as(this::resolvePath).to(clientBuilderSslSettings::tlsKeyStorePath);
116+
map.from(keyStore::getPassword).to(clientBuilderSslSettings::tlsKeyStorePassword);
117+
// Key store provider overrides trust store provider
118+
map.from(keyStore::getProvider).to(clientBuilderSslSettings::sslProvider);
119+
}
120+
121+
private void applyPemSslProperties(ClientBuilderSslSettings<?> clientBuilderSslSettings, PropertyMapper map,
122+
String bundleName) {
123+
// Dip down into the properties for the info we need to set on the client builder
124+
PemSslBundleProperties pemProperties = this.sslProperties.getBundle().getPem().get(bundleName);
125+
Assert.state(pemProperties != null,
126+
() -> "SslStoreBundle is PEM but unable to find 'spring.ssl.bundle.pem.%s.*' properties"
127+
.formatted(bundleName));
128+
PemSslBundleProperties.Store trustStore = pemProperties.getTruststore();
129+
map.from(trustStore::getCertificate).as(this::resolvePath).to(clientBuilderSslSettings::tlsTrustCertsFilePath);
130+
PemSslBundleProperties.Store keyStore = pemProperties.getKeystore();
131+
map.from(keyStore::getPrivateKey).as(this::resolvePath).to(clientBuilderSslSettings::tlsKeyFilePath);
132+
map.from(keyStore::getCertificate).as(this::resolvePath).to(clientBuilderSslSettings::tlsCertificateFilePath);
133+
}
134+
135+
/**
136+
* Resolves a location into an actual path. The Pulsar client builders TLS related
137+
* methods all expect the locations passed in to be file paths. Adding this resolve
138+
* allows us to use 'classpath:' locations.
139+
* @param resourceLocation the location of the resource
140+
* @return path to the resource
141+
*/
142+
private String resolvePath(String resourceLocation) {
143+
try {
144+
return ResourceUtils.getURL(resourceLocation).getPath();
145+
}
146+
catch (FileNotFoundException ex) {
147+
throw new RuntimeException(ex);
148+
}
149+
}
150+
151+
enum SslType {
152+
153+
JKS, PEM, UNSUPPORTED;
154+
155+
static SslType forSslStoreBundle(SslStoreBundle sslStoreBundle) {
156+
if (sslStoreBundle instanceof JksSslStoreBundle) {
157+
return SslType.JKS;
158+
}
159+
if (sslStoreBundle instanceof PemSslStoreBundle) {
160+
return SslType.PEM;
161+
}
162+
return UNSUPPORTED;
163+
}
164+
165+
}
166+
167+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*
2+
* Copyright 2012-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.pulsar;
18+
19+
import java.util.Set;
20+
21+
import org.apache.pulsar.client.admin.PulsarAdminBuilder;
22+
import org.apache.pulsar.client.api.ClientBuilder;
23+
24+
/**
25+
* Adapts a client builder's SSL settings. The Pulsar {@link ClientBuilder} and
26+
* {@link PulsarAdminBuilder} do not share a common interface for SSL settings eventhough
27+
* they have the same exact properties. This allows them to be treated the same and
28+
* therefore the SSL logic can be in a single place.
29+
*
30+
* @param <T> the client builder
31+
* @author Chris Bono
32+
* @since 3.2.0
33+
*/
34+
public interface ClientBuilderSslSettings<T> {
35+
36+
/**
37+
* Returns the adapted client builder.
38+
* @return the adapted client builder
39+
*/
40+
T adaptedClientBuilder();
41+
42+
/**
43+
* Configure whether to use TLS encryption on the connection <i>(default: true if
44+
* serviceUrl starts with "pulsar+ssl://", false otherwise)</i>.
45+
* @param enableTls whether to enable tls
46+
* @return the client builder instance
47+
*/
48+
T enableTls(boolean enableTls);
49+
50+
/**
51+
* Set the path to the TLS key file.
52+
* @param tlsKeyFilePath the path to the tls key file
53+
* @return the client builder instance
54+
*/
55+
T tlsKeyFilePath(String tlsKeyFilePath);
56+
57+
/**
58+
* Set the path to the TLS certificate file.
59+
* @param tlsCertificateFilePath the path to the tls cert file
60+
* @return the client builder instance
61+
*/
62+
T tlsCertificateFilePath(String tlsCertificateFilePath);
63+
64+
/**
65+
* Set the path to the trusted TLS certificate file.
66+
* @param tlsTrustCertsFilePath the path to the tls trust certs file
67+
* @return the client builder instance
68+
*/
69+
T tlsTrustCertsFilePath(String tlsTrustCertsFilePath);
70+
71+
/**
72+
* Configure whether the Pulsar client accept untrusted TLS certificate from broker
73+
* <i>(default: false)</i>.
74+
* @param allowTlsInsecureConnection whether to accept a untrusted TLS certificate
75+
* @return the client builder instance
76+
*/
77+
T allowTlsInsecureConnection(boolean allowTlsInsecureConnection);
78+
79+
/**
80+
* It allows to validate hostname verification when client connects to broker over
81+
* tls. It validates incoming x509 certificate and matches provided hostname(CN/SAN)
82+
* with expected broker's host name. It follows RFC 2818, 3.1. Server Identity
83+
* hostname verification.
84+
* @param enableTlsHostnameVerification whether to enable TLS hostname verification
85+
* @return the client builder instance
86+
* @see <a href="https://tools.ietf.org/html/rfc2818">RFC 818</a>
87+
*/
88+
T enableTlsHostnameVerification(boolean enableTlsHostnameVerification);
89+
90+
/**
91+
* If Tls is enabled, whether to use KeyStore type as tls configuration parameter.
92+
* False means use default pem type configuration.
93+
* @param useKeyStoreTls whether to use key store for tls
94+
* @return the client builder instance
95+
*/
96+
T useKeyStoreTls(boolean useKeyStoreTls);
97+
98+
/**
99+
* The name of the security provider used for SSL connections. Default value is the
100+
* default security provider of the JVM.
101+
* @param sslProvider the ssl provider
102+
* @return the client builder instance
103+
*/
104+
T sslProvider(String sslProvider);
105+
106+
/**
107+
* The file format of the key store file.
108+
* @param tlsKeyStoreType the tls key store file format
109+
* @return the client builder instance
110+
*/
111+
T tlsKeyStoreType(String tlsKeyStoreType);
112+
113+
/**
114+
* The location of the key store file.
115+
* @param tlsKeyStorePath the path to the tls key store
116+
* @return the client builder instance
117+
*/
118+
T tlsKeyStorePath(String tlsKeyStorePath);
119+
120+
/**
121+
* The store password for the key store file.
122+
* @param tlsKeyStorePassword the password for the tls key store
123+
* @return the client builder instance
124+
*/
125+
T tlsKeyStorePassword(String tlsKeyStorePassword);
126+
127+
/**
128+
* The file format of the trust store file.
129+
* @param tlsTrustStoreType the tls trust store file format
130+
* @return the client builder instance
131+
*/
132+
T tlsTrustStoreType(String tlsTrustStoreType);
133+
134+
/**
135+
* The location of the trust store file.
136+
* @param tlsTrustStorePath the path to the tls trust store
137+
* @return the client builder instance
138+
*/
139+
T tlsTrustStorePath(String tlsTrustStorePath);
140+
141+
/**
142+
* The store password for the trust store file.
143+
* @param tlsTrustStorePassword the password for the tls trust store
144+
* @return the client builder instance
145+
*/
146+
T tlsTrustStorePassword(String tlsTrustStorePassword);
147+
148+
/**
149+
* A list of cipher suites. This is a named combination of authentication, encryption,
150+
* MAC and key exchange algorithm used to negotiate the security settings for a
151+
* network connection using TLS or SSL network protocol. By default, all the available
152+
* cipher suites are supported.
153+
* @param tlsCiphers the tls ciphers
154+
* @return the client builder instance
155+
*/
156+
T tlsCiphers(Set<String> tlsCiphers);
157+
158+
/**
159+
* The SSL protocol used to generate the SSLContext. Default setting is TLS, which is
160+
* fine for most cases. Allowed values in recent JVMs are TLS, TLSv1.3, TLSv1.2 and
161+
* TLSv1.1.
162+
* @param tlsProtocols the enabled protocols
163+
* @return the client builder instance
164+
*/
165+
T tlsProtocols(Set<String> tlsProtocols);
166+
167+
}

0 commit comments

Comments
 (0)