diff --git a/.gitignore b/.gitignore
index 704fcd5cd..ed568a959 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,3 +54,4 @@ applog/
*/backup
/backup
backup
+*/tls
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19c4a239f..d6ea8f23a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,3 +23,4 @@
- [fix: polaris.discovery.heartbeat.enabled not effective.](https://github.com/Tencent/spring-cloud-tencent/pull/1694)
- [feat: support config ratelimit addresses and remote task interval.](https://github.com/Tencent/spring-cloud-tencent/pull/1695)
- [docs:optimize tsf example.](https://github.com/Tencent/spring-cloud-tencent/pull/1711)
+- [feat:support TSF certificate manager.](https://github.com/Tencent/spring-cloud-tencent/pull/1716)
diff --git a/spring-cloud-starter-tencent-all/pom.xml b/spring-cloud-starter-tencent-all/pom.xml
index 975f99bd9..3758dd093 100644
--- a/spring-cloud-starter-tencent-all/pom.xml
+++ b/spring-cloud-starter-tencent-all/pom.xml
@@ -84,5 +84,10 @@
com.tencent.cloud
spring-cloud-starter-tencent-fault-injection-plugin
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-tsf-tls-plugin
+
diff --git a/spring-cloud-starter-tencent-polaris-config/pom.xml b/spring-cloud-starter-tencent-polaris-config/pom.xml
index 018d12f60..99d4f6609 100644
--- a/spring-cloud-starter-tencent-polaris-config/pom.xml
+++ b/spring-cloud-starter-tencent-polaris-config/pom.xml
@@ -19,6 +19,12 @@
com.tencent.cloud
spring-cloud-tencent-polaris-context
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-tsf-tls-plugin
+ true
+
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java
index 795d99b2a..f21285a70 100644
--- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java
@@ -19,12 +19,16 @@ package com.tencent.cloud.polaris.config.adapter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import com.tencent.cloud.plugin.tsf.tls.utils.SyncUtils;
import com.tencent.cloud.polaris.config.config.ConfigFileGroup;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
+import com.tencent.cloud.polaris.context.config.extend.tsf.TsfTlsProperties;
import com.tencent.polaris.api.utils.ClassUtils;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.api.utils.StringUtils;
@@ -38,6 +42,7 @@ import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
+import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import static com.tencent.cloud.polaris.config.utils.PolarisPropertySourceUtils.loadGroupPolarisPropertySource;
@@ -100,6 +105,8 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
}
// load tsf default config group
initTsfConfigGroups(compositePropertySource);
+ // load tsf tls properties if need.
+ initTsfTlsPropertySource(compositePropertySource);
return compositePropertySource;
}
finally {
@@ -229,6 +236,90 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
}
}
+ void initTsfTlsPropertySource(CompositePropertySource compositePropertySource) {
+ String address = System.getProperty("MESH_CITADEL_ADDR", System.getenv("MESH_CITADEL_ADDR"));
+ if (StringUtils.isNotBlank(address)
+ && (StringUtils.equals("tsf", environment.getProperty("server.ssl.bundle"))
+ || "tsf".equals(compositePropertySource.getProperty(("server.ssl.bundle"))))
+ && ClassUtils.isClassPresent("com.tencent.cloud.plugin.tsf.tls.utils.SyncUtils")
+ && !SyncUtils.isInitialized()) {
+ // get common name
+ Object commonName = compositePropertySource.getProperty("spring.cloud.polaris.service");
+ if (commonName == null) {
+ commonName = compositePropertySource.getProperty("spring.cloud.polaris.discovery.service");
+ }
+ if (commonName == null) {
+ commonName = compositePropertySource.getProperty("spring.application.name");
+ }
+ if (commonName == null) {
+ commonName = environment.getProperty("spring.cloud.polaris.service");
+ }
+ if (commonName == null) {
+ commonName = environment.getProperty("spring.cloud.polaris.discovery.service");
+ }
+ if (commonName == null) {
+ commonName = environment.getProperty("spring.application.name");
+ }
+ // get certPath
+ String certPath = System.getProperty("MESH_CITADEL_CERT", System.getenv("MESH_CITADEL_CERT"));
+ // get token
+ String token = System.getProperty("tsf_token", System.getenv("tsf_token"));
+ // get validityDuration
+ Object validityDuration = compositePropertySource.getProperty("spring.cloud.polaris.tls.validityDuration");
+ if (validityDuration == null) {
+ validityDuration = environment.getProperty("spring.cloud.polaris.tls.validityDuration", Long.class, TsfTlsProperties.DEFAULT_VALIDITY_DURATION);
+ }
+ if (validityDuration instanceof String) {
+ validityDuration = Long.valueOf((String) validityDuration);
+ }
+ // get refreshBefore
+ Object refreshBefore = compositePropertySource.getProperty("spring.cloud.polaris.tls.refreshBefore");
+ if (refreshBefore == null) {
+ refreshBefore = environment.getProperty("spring.cloud.polaris.tls.refreshBefore", Long.class, TsfTlsProperties.DEFAULT_REFRESH_BEFORE);
+ }
+ if (refreshBefore instanceof String) {
+ refreshBefore = Long.valueOf((String) refreshBefore);
+ }
+ // get watchInterval
+ Object watchInterval = compositePropertySource.getProperty("spring.cloud.polaris.tls.watchInterval");
+ if (watchInterval == null) {
+ watchInterval = environment.getProperty("spring.cloud.polaris.tls.watchInterval", Long.class, TsfTlsProperties.DEFAULT_WATCH_INTERVAL);
+ }
+ if (watchInterval instanceof String) {
+ watchInterval = Long.valueOf((String) watchInterval);
+ }
+ SyncUtils.init((String) commonName, address, certPath, token, (Long) validityDuration, (Long) refreshBefore, (Long) watchInterval);
+ if (SyncUtils.isVerified()) {
+ Map tlsEnvProperties = new HashMap<>();
+ // set ssl
+ Object clientAuth = compositePropertySource.getProperty("server.ssl.client-auth");
+ if (clientAuth == null) {
+ clientAuth = environment.getProperty("server.ssl.client-auth", "want");
+ }
+ tlsEnvProperties.put("server.ssl.client-auth", clientAuth);
+ Object protocol = compositePropertySource.getProperty("spring.cloud.polaris.discovery.protocol");
+ if (protocol == null) {
+ protocol = environment.getProperty("spring.cloud.polaris.discovery.protocol", "https");
+ }
+ tlsEnvProperties.put("spring.cloud.polaris.discovery.protocol", protocol);
+ tlsEnvProperties.put("tsf.discovery.scheme", protocol);
+ // set tsf spring ssl bundle
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.reload-on-update", "true");
+ if (StringUtils.isNotBlank(SyncUtils.getPemKeyStoreCertPath()) && StringUtils.isNotBlank(SyncUtils.getPemKeyStoreKeyPath())) {
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.keystore.certificate", SyncUtils.getPemKeyStoreCertPath());
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.keystore.private-key", SyncUtils.getPemKeyStoreKeyPath());
+ }
+ if (StringUtils.isNotBlank(SyncUtils.getPemTrustStoreCertPath())) {
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.truststore.certificate", SyncUtils.getPemTrustStoreCertPath());
+ }
+
+ // process environment
+ MapPropertySource propertySource = new MapPropertySource("tsf-tls-config", tlsEnvProperties);
+ compositePropertySource.addPropertySource(propertySource);
+ }
+ }
+ }
+
private void initCustomPolarisConfigFiles(CompositePropertySource compositePropertySource, List configFileGroups) {
String namespace = polarisContextProperties.getNamespace();
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePuller.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePuller.java
index 90a3483a0..eb6212f88 100644
--- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePuller.java
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePuller.java
@@ -19,12 +19,16 @@ package com.tencent.cloud.polaris.config.adapter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import com.tencent.cloud.plugin.tsf.tls.utils.SyncUtils;
import com.tencent.cloud.polaris.config.config.ConfigFileGroup;
import com.tencent.cloud.polaris.config.configdata.PolarisConfigDataLoader;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
+import com.tencent.cloud.polaris.context.config.extend.tsf.TsfTlsProperties;
import com.tencent.polaris.api.utils.ClassUtils;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.api.utils.StringUtils;
@@ -35,6 +39,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.CompositePropertySource;
+import org.springframework.core.env.MapPropertySource;
import static com.tencent.cloud.polaris.config.utils.PolarisPropertySourceUtils.loadGroupPolarisPropertySource;
import static com.tencent.cloud.polaris.config.utils.PolarisPropertySourceUtils.loadPolarisPropertySource;
@@ -164,6 +169,79 @@ public final class PolarisConfigFilePuller {
}
}
+ /**
+ * Init TSF TLS property source.
+ * @param compositePropertySource compositePropertySource
+ */
+ public void initTsfTlsPropertySource(CompositePropertySource compositePropertySource,
+ TsfTlsProperties tsfTlsProperties, String serviceName) {
+ String address = System.getProperty("MESH_CITADEL_ADDR", System.getenv("MESH_CITADEL_ADDR"));
+ if (StringUtils.isNotBlank(address)
+ && (StringUtils.equals("tsf", System.getProperty("server.ssl.bundle"))
+ || "tsf".equals(compositePropertySource.getProperty(("server.ssl.bundle"))))
+ && ClassUtils.isClassPresent("com.tencent.cloud.plugin.tsf.tls.utils.SyncUtils")
+ && !SyncUtils.isInitialized()) {
+ // get certPath
+ String certPath = System.getProperty("MESH_CITADEL_CERT", System.getenv("MESH_CITADEL_CERT"));
+ // get token
+ String token = System.getProperty("tsf_token", System.getenv("tsf_token"));
+ // get validityDuration
+ Object validityDuration = compositePropertySource.getProperty("spring.cloud.polaris.tls.validityDuration");
+ if (validityDuration == null) {
+ validityDuration = tsfTlsProperties.getValidityDuration();
+ }
+ if (validityDuration instanceof String) {
+ validityDuration = Long.valueOf((String) validityDuration);
+ }
+ // get refreshBefore
+ Object refreshBefore = compositePropertySource.getProperty("spring.cloud.polaris.tls.refreshBefore");
+ if (refreshBefore == null) {
+ refreshBefore = tsfTlsProperties.getRefreshBefore();
+ }
+ if (refreshBefore instanceof String) {
+ refreshBefore = Long.valueOf((String) refreshBefore);
+ }
+ // get watchInterval
+ Object watchInterval = compositePropertySource.getProperty("spring.cloud.polaris.tls.watchInterval");
+ if (watchInterval == null) {
+ watchInterval = tsfTlsProperties.getWatchInterval();
+ }
+ if (watchInterval instanceof String) {
+ watchInterval = Long.valueOf((String) watchInterval);
+ }
+ SyncUtils.init(serviceName, address, certPath, token, (Long) validityDuration, (Long) refreshBefore, (Long) watchInterval);
+ if (SyncUtils.isVerified()) {
+ Map tlsEnvProperties = new HashMap<>();
+ // set ssl
+ Object clientAuth = compositePropertySource.getProperty("server.ssl.client-auth");
+ if (clientAuth == null) {
+ clientAuth = System.getProperty("server.ssl.client-auth", "want");
+ }
+ tlsEnvProperties.put("server.ssl.client-auth", clientAuth);
+ Object protocol = compositePropertySource.getProperty("spring.cloud.polaris.discovery.protocol");
+ if (protocol == null) {
+ protocol = System.getProperty("spring.cloud.polaris.discovery.protocol", "https");
+ }
+ tlsEnvProperties.put("spring.cloud.polaris.discovery.protocol", protocol);
+ tlsEnvProperties.put("tsf.discovery.scheme", protocol);
+
+ // set tsf spring ssl bundle
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.reload-on-update", "true");
+ if (StringUtils.isNotBlank(SyncUtils.getPemKeyStoreCertPath()) && StringUtils.isNotBlank(SyncUtils.getPemKeyStoreKeyPath())) {
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.keystore.certificate", SyncUtils.getPemKeyStoreCertPath());
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.keystore.private-key", SyncUtils.getPemKeyStoreKeyPath());
+ }
+ if (StringUtils.isNotBlank(SyncUtils.getPemTrustStoreCertPath())) {
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.truststore.certificate", SyncUtils.getPemTrustStoreCertPath());
+ }
+
+ // process environment
+ MapPropertySource propertySource = new MapPropertySource("tsf-tls-config-data", tlsEnvProperties);
+ compositePropertySource.addPropertySource(propertySource);
+ }
+ }
+ }
+
private List getInternalConfigFiles(
String[] activeProfiles, String[] defaultProfiles, String serviceName) {
String namespace = polarisContextProperties.getNamespace();
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoader.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoader.java
index 1f619088c..3483795c8 100644
--- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoader.java
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoader.java
@@ -132,6 +132,8 @@ public class PolarisConfigDataLoader implements ConfigDataLoader result = new ArrayList<>();
boolean optional = location.isOptional();
String groupFileName = getRealGroupFileName(location);
String serviceName = loadPolarisConfigProperties(resolverContext,
- String.class, "spring.application.name");
+ String.class, "spring.cloud.polaris.discovery.service");
+ if (StringUtils.isBlank(serviceName)) {
+ serviceName = loadPolarisConfigProperties(resolverContext,
+ String.class, "spring.cloud.polaris.service");
+ }
+ if (StringUtils.isBlank(serviceName)) {
+ serviceName = loadPolarisConfigProperties(resolverContext,
+ String.class, "spring.application.name");
+ }
if (StringUtils.isBlank(serviceName)) {
serviceName = "application";
log.warn("No spring.application.name found, defaulting to 'application'");
@@ -233,6 +254,7 @@ public class PolarisConfigDataLocationResolver implements
polarisConfigProperties,
polarisCryptoConfigProperties,
polarisContextProperties,
+ tsfTlsProperties,
profiles, optional,
fileName, groupName, serviceName
);
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataResource.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataResource.java
index a6b740950..5d396abd1 100644
--- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataResource.java
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataResource.java
@@ -22,6 +22,7 @@ import java.util.Objects;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import com.tencent.cloud.polaris.config.config.PolarisCryptoConfigProperties;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
+import com.tencent.cloud.polaris.context.config.extend.tsf.TsfTlsProperties;
import org.springframework.boot.context.config.ConfigData;
import org.springframework.boot.context.config.ConfigDataResource;
@@ -40,6 +41,8 @@ public class PolarisConfigDataResource extends ConfigDataResource {
private final PolarisContextProperties polarisContextProperties;
+ private final TsfTlsProperties tsfTlsProperties;
+
private final Profiles profiles;
private final boolean optional;
@@ -53,11 +56,13 @@ public class PolarisConfigDataResource extends ConfigDataResource {
public PolarisConfigDataResource(PolarisConfigProperties polarisConfigProperties,
PolarisCryptoConfigProperties polarisCryptoConfigProperties,
PolarisContextProperties polarisContextProperties,
+ TsfTlsProperties tsfTlsProperties,
Profiles profiles, boolean optional,
String fileName, String groupName, String serviceName) {
this.polarisConfigProperties = polarisConfigProperties;
this.polarisCryptoConfigProperties = polarisCryptoConfigProperties;
this.polarisContextProperties = polarisContextProperties;
+ this.tsfTlsProperties = tsfTlsProperties;
this.profiles = profiles;
this.optional = optional;
this.fileName = fileName;
@@ -77,6 +82,10 @@ public class PolarisConfigDataResource extends ConfigDataResource {
return polarisContextProperties;
}
+ public TsfTlsProperties getTsfTlsProperties() {
+ return tsfTlsProperties;
+ }
+
public Profiles getProfiles() {
return profiles;
}
@@ -110,6 +119,7 @@ public class PolarisConfigDataResource extends ConfigDataResource {
polarisConfigProperties.equals(that.polarisConfigProperties) &&
polarisCryptoConfigProperties.equals(that.polarisCryptoConfigProperties) &&
polarisContextProperties.equals(that.polarisContextProperties) &&
+ tsfTlsProperties.equals(that.tsfTlsProperties) &&
profiles.equals(that.profiles) &&
fileName.equals(that.fileName) &&
groupName.equals(that.groupName) &&
@@ -118,7 +128,7 @@ public class PolarisConfigDataResource extends ConfigDataResource {
@Override
public int hashCode() {
- return Objects.hash(polarisConfigProperties, polarisCryptoConfigProperties, polarisContextProperties, profiles,
- optional, fileName, groupName, serviceName);
+ return Objects.hash(polarisConfigProperties, polarisCryptoConfigProperties, polarisContextProperties,
+ tsfTlsProperties, profiles, optional, fileName, groupName, serviceName);
}
}
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java
index 7ac4f11ae..f17cf29fa 100644
--- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java
@@ -22,7 +22,6 @@ import java.util.Collections;
import java.util.Map;
import com.tencent.cloud.common.constant.OrderConstant;
-import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties;
@@ -126,10 +125,6 @@ public class ConsulDiscoveryConfigModifier implements PolarisConfigModifier {
String.valueOf(consulDiscoveryProperties.isPreferIpAddress()));
metadata.put(ConsulConstant.MetadataMapKey.IP_ADDRESS_KEY, consulDiscoveryProperties.getHostname());
}
- if (tsfCoreProperties != null) {
- // tags
- metadata.put(ConsulConstant.MetadataMapKey.TAGS_KEY, JacksonUtils.serialize2Json(tsfCoreProperties.getTsfTags()));
- }
configuration.getGlobal().getServerConnectors().add(serverConnectorConfig);
// discovery
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/tsf/TsfDiscoveryRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/tsf/TsfDiscoveryRegistryAutoConfiguration.java
index 137aab48c..0bcc9c3c7 100644
--- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/tsf/TsfDiscoveryRegistryAutoConfiguration.java
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/tsf/TsfDiscoveryRegistryAutoConfiguration.java
@@ -18,6 +18,7 @@
package com.tencent.cloud.polaris.registry.tsf;
import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled;
+import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties;
import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties;
@@ -68,4 +69,11 @@ public class TsfDiscoveryRegistryAutoConfiguration {
public TsfApiPolarisRegistrationCustomizer tsfApiPolarisRegistrationCustomizer(ApplicationContext context) {
return new TsfApiPolarisRegistrationCustomizer(context);
}
+
+ @Bean
+ @ConditionalOnMissingBean
+ public TsfTagsRegistrationCustomizer tsfTagsRegistrationCustomizer(TsfCoreProperties tsfCoreProperties,
+ PolarisDiscoveryProperties polarisDiscoveryProperties) {
+ return new TsfTagsRegistrationCustomizer(tsfCoreProperties, polarisDiscoveryProperties);
+ }
}
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/tsf/TsfTagsRegistrationCustomizer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/tsf/TsfTagsRegistrationCustomizer.java
new file mode 100644
index 000000000..3e6b8f402
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/tsf/TsfTagsRegistrationCustomizer.java
@@ -0,0 +1,64 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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 com.tencent.cloud.polaris.registry.tsf;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
+import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
+import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties;
+import com.tencent.cloud.polaris.registry.PolarisRegistration;
+import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer;
+import com.tencent.polaris.api.utils.StringUtils;
+
+import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.TAGS_KEY;
+
+/**
+ * @author Haotian Zhang
+ */
+public class TsfTagsRegistrationCustomizer implements PolarisRegistrationCustomizer {
+
+ private final TsfCoreProperties tsfCoreProperties;
+
+ private final PolarisDiscoveryProperties polarisDiscoveryProperties;
+
+ public TsfTagsRegistrationCustomizer(TsfCoreProperties tsfCoreProperties, PolarisDiscoveryProperties polarisDiscoveryProperties) {
+ this.tsfCoreProperties = tsfCoreProperties;
+ this.polarisDiscoveryProperties = polarisDiscoveryProperties;
+ }
+
+ @Override
+ public void customize(PolarisRegistration registration) {
+ if (tsfCoreProperties == null) {
+ return;
+ }
+
+ String protocol = ApplicationContextAwareUtils.getProperties("tsf.discovery.scheme",
+ ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.discovery.protocol", "http"));
+ if (StringUtils.isNotBlank(protocol)) {
+ tsfCoreProperties.setScheme(protocol);
+ polarisDiscoveryProperties.setProtocol(protocol);
+ }
+ Map metadata = registration.getExtendedMetadata()
+ .computeIfAbsent(TAGS_KEY, k -> new HashMap<>());
+ for (String tag : tsfCoreProperties.getTsfTags()) {
+ metadata.put(TAGS_KEY, tag);
+ }
+ }
+}
diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml
index 689000c07..5919c69ca 100644
--- a/spring-cloud-tencent-coverage/pom.xml
+++ b/spring-cloud-tencent-coverage/pom.xml
@@ -106,6 +106,12 @@
spring-cloud-starter-tencent-fault-injection-plugin
${revision}
+
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-tsf-tls-plugin
+ ${revision}
+
diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml
index 053d14568..5e99e5205 100644
--- a/spring-cloud-tencent-dependencies/pom.xml
+++ b/spring-cloud-tencent-dependencies/pom.xml
@@ -214,6 +214,12 @@
${revision}
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-tsf-tls-plugin
+ ${revision}
+
+
org.springdoc
diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml b/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml
index 026d8b065..b6e40cfb6 100644
--- a/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml
+++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml
@@ -31,5 +31,10 @@
org.springframework.cloud
spring-cloud-starter-bootstrap
+
+
+ io.github.openfeign
+ feign-hc5
+
\ No newline at end of file
diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java
index 87694e5b2..6c6871337 100644
--- a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java
+++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java
@@ -17,11 +17,30 @@
package com.tencent.cloud.tsf.demo.consumer;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.net.ssl.SSLContext;
+
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
+import org.apache.hc.client5.http.io.HttpClientConnectionManager;
+import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
+import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
+import org.apache.hc.core5.ssl.SSLContextBuilder;
+
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.ssl.SslBundles;
+import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.tsf.annotation.EnableTsf;
import org.springframework.web.client.RestTemplate;
@@ -33,9 +52,43 @@ public class ConsumerApplication {
SpringApplication.run(ConsumerApplication.class, args);
}
- @LoadBalanced
@Bean
- public RestTemplate restTemplate() {
- return new RestTemplate();
+ @RefreshScope
+ @ConditionalOnProperty(value = "server.ssl.bundle", havingValue = "tsf")
+ public HttpClientConnectionManager connectionManagerWithSSL(SslBundles sslBundles) {
+ SSLContext sslContext = sslBundles.getBundle("tsf").createSslContext();
+ SSLContext.setDefault(sslContext);
+ return PoolingHttpClientConnectionManagerBuilder.create()
+ .setSSLSocketFactory(new SSLConnectionSocketFactory(
+ sslContext,
+ NoopHostnameVerifier.INSTANCE
+ ))
+ .build();
+ }
+
+ @Bean
+ @ConditionalOnExpression("'${server.ssl.bundle:}' != 'tsf'")
+ public HttpClientConnectionManager connectionManager() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
+ SSLContext sslContext = SSLContextBuilder.create()
+ .loadTrustMaterial(null, (chain, authType) -> true)
+ .build();
+ return PoolingHttpClientConnectionManagerBuilder.create()
+ .setSSLSocketFactory(new SSLConnectionSocketFactory(
+ sslContext,
+ NoopHostnameVerifier.INSTANCE
+ ))
+ .build();
+ }
+
+ @Bean
+ @LoadBalanced
+ public RestTemplate restTemplate(
+ RestTemplateBuilder builder, HttpClientConnectionManager connectionManager) {
+ return builder
+ .requestFactory(() -> new HttpComponentsClientHttpRequestFactory(
+ HttpClients.custom()
+ .setConnectionManager(connectionManager)
+ .build()))
+ .build();
}
}
diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml
index eb7a01b09..7236c2952 100644
--- a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml
+++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml
@@ -3,8 +3,6 @@ server:
spring:
application:
name: consumer-demo
- config:
- import: optional:polaris
feign:
tsf:
diff --git a/spring-cloud-tencent-examples/tsf-example/msgw-scg/src/main/java/com/tencent/cloud/tsf/msgw/scg/ScgApplication.java b/spring-cloud-tencent-examples/tsf-example/msgw-scg/src/main/java/com/tencent/cloud/tsf/msgw/scg/ScgApplication.java
index bdb9766d8..5f119aafe 100644
--- a/spring-cloud-tencent-examples/tsf-example/msgw-scg/src/main/java/com/tencent/cloud/tsf/msgw/scg/ScgApplication.java
+++ b/spring-cloud-tencent-examples/tsf-example/msgw-scg/src/main/java/com/tencent/cloud/tsf/msgw/scg/ScgApplication.java
@@ -17,8 +17,23 @@
package com.tencent.cloud.tsf.msgw.scg;
+import java.time.Duration;
+
+import javax.net.ssl.SSLException;
+
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import reactor.netty.http.client.HttpClient;
+import reactor.netty.resources.ConnectionProvider;
+
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.ssl.SslBundle;
+import org.springframework.boot.ssl.SslBundles;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Bean;
import org.springframework.tsf.annotation.EnableTsf;
/**
@@ -31,4 +46,29 @@ public class ScgApplication {
public static void main(String[] args) {
SpringApplication.run(ScgApplication.class, args);
}
+
+ @Bean
+ @RefreshScope
+ @ConditionalOnProperty(value = "server.ssl.bundle", havingValue = "tsf")
+ public HttpClient httpClient(SslBundles sslBundles) throws SSLException {
+ // 自定义连接池
+ ConnectionProvider connectionProvider = ConnectionProvider.builder("customPool")
+ .maxConnections(500)
+ .pendingAcquireTimeout(Duration.ofSeconds(10))
+ .build();
+
+ // 配置 SSL 上下文
+ SslBundle sslBundle = sslBundles.getBundle("tsf");
+
+ SslContext sslContext = SslContextBuilder.forClient()
+ .keyManager(sslBundle.getManagers().getKeyManagerFactory())
+ .trustManager(sslBundle.getManagers().getTrustManagerFactory())
+ .trustManager(InsecureTrustManagerFactory.INSTANCE)
+ .build();
+
+ // 自定义 HttpClient
+ return HttpClient.create(connectionProvider)
+ .responseTimeout(Duration.ofSeconds(5))
+ .secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
+ }
}
diff --git a/spring-cloud-tencent-plugin-starters/pom.xml b/spring-cloud-tencent-plugin-starters/pom.xml
index 28f294aa6..149ece160 100644
--- a/spring-cloud-tencent-plugin-starters/pom.xml
+++ b/spring-cloud-tencent-plugin-starters/pom.xml
@@ -24,6 +24,7 @@
spring-cloud-starter-tencent-multi-discovery-plugin
spring-cloud-starter-tencent-traffic-mirroring-plugin
spring-cloud-starter-tencent-fault-injection-plugin
+ spring-cloud-starter-tencent-tsf-tls-plugin
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/pom.xml
new file mode 100644
index 000000000..70f179f41
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/pom.xml
@@ -0,0 +1,20 @@
+
+
+ spring-cloud-tencent-plugin-starters
+ com.tencent.cloud
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+ spring-cloud-starter-tencent-tsf-tls-plugin
+ Spring Cloud Tencent TSF TLS Plugin
+
+
+
+
+ com.tencent.cloud
+ spring-cloud-tencent-rpc-enhancement
+
+
+
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/TlsEnvironmentPostProcessor.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/TlsEnvironmentPostProcessor.java
new file mode 100644
index 000000000..75121652e
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/TlsEnvironmentPostProcessor.java
@@ -0,0 +1,100 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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 com.tencent.cloud.plugin.tsf.tls;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.tencent.cloud.plugin.tsf.tls.utils.SyncUtils;
+import com.tencent.cloud.polaris.context.config.extend.tsf.TsfTlsProperties;
+import com.tencent.polaris.api.utils.ClassUtils;
+import com.tencent.polaris.api.utils.StringUtils;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.env.EnvironmentPostProcessor;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.MapPropertySource;
+
+/**
+ * Environment post processor for polaris tls.
+ *
+ * @author Haotian Zhang
+ */
+public class TlsEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
+ @Override
+ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
+ String address = environment.getProperty("MESH_CITADEL_ADDR");
+ if (StringUtils.isNotBlank(address)
+ && StringUtils.equals("tsf", environment.getProperty("server.ssl.bundle"))
+ && ClassUtils.isClassPresent("com.tencent.cloud.plugin.tsf.tls.utils.SyncUtils")
+ && !ClassUtils.isClassPresent("com.tencent.cloud.polaris.config.adapter.PolarisConfigFileLocator")) {
+ // get common name
+ String commonName = environment.getProperty("spring.cloud.polaris.service");
+ if (StringUtils.isBlank(commonName)) {
+ commonName = environment.getProperty("spring.cloud.polaris.discovery.service");
+ }
+ if (StringUtils.isBlank(commonName)) {
+ commonName = environment.getProperty("spring.application.name");
+ }
+ // get certPath
+ String certPath = environment.getProperty("MESH_CITADEL_CERT");
+ // get token
+ String token = environment.getProperty("tsf_token");
+ // get validityDuration
+ Long validityDuration = environment.getProperty("spring.cloud.polaris.tls.validityDuration", Long.class, TsfTlsProperties.DEFAULT_VALIDITY_DURATION);
+ // get refreshBefore
+ Long refreshBefore = environment.getProperty("spring.cloud.polaris.tls.refreshBefore", Long.class, TsfTlsProperties.DEFAULT_REFRESH_BEFORE);
+ // get watchInterval
+ Long watchInterval = environment.getProperty("spring.cloud.polaris.tls.watchInterval", Long.class, TsfTlsProperties.DEFAULT_WATCH_INTERVAL);
+ SyncUtils.init(commonName, address, certPath, token, validityDuration, refreshBefore, watchInterval);
+ System.setProperty("server.ssl.bundle", "tsf");
+ if (SyncUtils.isVerified()) {
+ Map tlsEnvProperties = new HashMap<>();
+ // set ssl
+ String clientAuth = environment.getProperty("server.ssl.client-auth", "want");
+ tlsEnvProperties.put("server.ssl.client-auth", clientAuth);
+ System.setProperty("server.ssl.client-auth", clientAuth);
+ String protocol = environment.getProperty("spring.cloud.polaris.discovery.protocol", "https");
+ tlsEnvProperties.put("spring.cloud.polaris.discovery.protocol", protocol);
+ System.setProperty("spring.cloud.polaris.discovery.protocol", protocol);
+ tlsEnvProperties.put("tsf.discovery.scheme", protocol);
+ System.setProperty("tsf.discovery.scheme", protocol);
+
+ // set tsf spring ssl bundle
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.reload-on-update", "true");
+ if (StringUtils.isNotBlank(SyncUtils.getPemKeyStoreCertPath()) && StringUtils.isNotBlank(SyncUtils.getPemKeyStoreKeyPath())) {
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.keystore.certificate", SyncUtils.getPemKeyStoreCertPath());
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.keystore.private-key", SyncUtils.getPemKeyStoreKeyPath());
+ }
+ if (StringUtils.isNotBlank(SyncUtils.getPemTrustStoreCertPath())) {
+ tlsEnvProperties.put("spring.ssl.bundle.pem.tsf.truststore.certificate", SyncUtils.getPemTrustStoreCertPath());
+ }
+
+ // process environment
+ MapPropertySource propertySource = new MapPropertySource("tsf-tls-properties", tlsEnvProperties);
+ environment.getPropertySources().addFirst(propertySource);
+ }
+ }
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+}
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/TlsReadyApplicationListener.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/TlsReadyApplicationListener.java
new file mode 100644
index 000000000..39a248a3a
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/TlsReadyApplicationListener.java
@@ -0,0 +1,63 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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 com.tencent.cloud.plugin.tsf.tls;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.springframework.boot.context.event.ApplicationStartedEvent;
+import org.springframework.boot.ssl.NoSuchSslBundleException;
+import org.springframework.boot.ssl.SslBundles;
+import org.springframework.cloud.context.refresh.ContextRefresher;
+import org.springframework.context.ApplicationListener;
+
+/**
+ * Application listener for tls init.
+ *
+ * @author Haotian Zhang
+ */
+public class TlsReadyApplicationListener implements ApplicationListener {
+
+ private static final Logger log = LoggerFactory.getLogger(TlsReadyApplicationListener.class);
+
+ private final AtomicBoolean isSet = new AtomicBoolean(false);
+
+ @Override
+ public void onApplicationEvent(@NotNull ApplicationStartedEvent event) {
+ SslBundles sslBundles = ApplicationContextAwareUtils.getBeanIfExists(SslBundles.class);
+ ContextRefresher contextRefresher = ApplicationContextAwareUtils.getBeanIfExists(ContextRefresher.class);
+ try {
+ if (sslBundles != null && contextRefresher != null && isSet.compareAndSet(false, true)) {
+ try {
+ sslBundles.getBundle("tsf");
+ sslBundles.addBundleUpdateHandler("tsf", sslBundle -> contextRefresher.refresh());
+ }
+ catch (NoSuchSslBundleException e) {
+ log.warn("tsf ssl bundle is not registered.");
+ }
+ }
+ }
+ catch (Throwable throwable) {
+ log.warn("tsf ssl bundle is not registered correctly.", throwable);
+ }
+ }
+}
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/config/TsfTlsAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/config/TsfTlsAutoConfiguration.java
new file mode 100644
index 000000000..295736c33
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/config/TsfTlsAutoConfiguration.java
@@ -0,0 +1,39 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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 com.tencent.cloud.plugin.tsf.tls.config;
+
+import com.tencent.cloud.plugin.tsf.tls.TlsReadyApplicationListener;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Auto configuration for TSF TLS.
+ *
+ * @author Haotian Zhang
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnProperty(value = "server.ssl.bundle", havingValue = "tsf")
+public class TsfTlsAutoConfiguration {
+
+ @Bean
+ public TlsReadyApplicationListener tlsReadyApplicationListener() {
+ return new TlsReadyApplicationListener();
+ }
+}
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/utils/SyncUtils.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/utils/SyncUtils.java
new file mode 100644
index 000000000..fb7823dc5
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/java/com/tencent/cloud/plugin/tsf/tls/utils/SyncUtils.java
@@ -0,0 +1,147 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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 com.tencent.cloud.plugin.tsf.tls.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import com.tencent.polaris.api.config.ConfigProvider;
+import com.tencent.polaris.api.config.consumer.OutlierDetectionConfig;
+import com.tencent.polaris.api.config.plugin.DefaultPlugins;
+import com.tencent.polaris.api.plugin.certificate.CertFile;
+import com.tencent.polaris.api.plugin.certificate.CertFileKey;
+import com.tencent.polaris.api.utils.CollectionUtils;
+import com.tencent.polaris.api.utils.StringUtils;
+import com.tencent.polaris.certificate.api.core.CertificateAPI;
+import com.tencent.polaris.certificate.factory.CertificateAPIFactory;
+import com.tencent.polaris.client.api.SDKContext;
+import com.tencent.polaris.factory.ConfigAPIFactory;
+import com.tencent.polaris.factory.config.ConfigurationImpl;
+import com.tencent.polaris.plugins.certificate.tsf.TsfCertificateManagerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utils for sync.
+ *
+ * @author Haotian Zhang
+ */
+public final class SyncUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(SyncUtils.class);
+ private static final Map pemFileMap = new HashMap<>();
+ private volatile static SDKContext certificateSDKContext;
+ private volatile static CertificateAPI certificateAPI;
+
+ private SyncUtils() {
+
+ }
+
+ public static void init(String commonName, String address, String certPath, String token, Long validityDuration,
+ Long refreshBefore, Long watchInterval) {
+ log.info("begin init SyncUtils with commonName: {}, address: {}, certPath: {}, token: {}", commonName, address, certPath, token);
+ try {
+ if (!isInitialized() && StringUtils.isNotBlank(commonName) && StringUtils.isNotBlank(address)) {
+ initCertificateSDKContext(commonName, address, certPath, token, validityDuration, refreshBefore, watchInterval);
+ log.info("init SyncUtils with commonName: {}, address: {}, certPath: {}, token: {} successfully", commonName, address, certPath, token);
+ }
+ }
+ catch (Throwable throwable) {
+ log.error("init SyncUtils with commonName: {}, address: {}, certPath: {}, token: {} failed.", commonName, address, certPath, token, throwable);
+ }
+ }
+
+ private static void initCertificateSDKContext(String commonName, String address, String certPath, String token,
+ Long validityDuration, Long refreshBefore, Long watchInterval) {
+ // 1. Read user-defined polaris.yml configuration
+ ConfigurationImpl configuration = (ConfigurationImpl) ConfigAPIFactory
+ .defaultConfig(ConfigProvider.DEFAULT_CONFIG);
+
+ // 2. Override user-defined polaris.yml configuration with SCT configuration
+ configuration.getGlobal().getAPI().setReportEnable(false);
+ configuration.getGlobal().getStatReporter().setEnable(false);
+ configuration.getConsumer().getOutlierDetection().setWhen(OutlierDetectionConfig.When.never);
+ configuration.getGlobal().getCertificate().setEnable(true);
+ configuration.getGlobal().getCertificate().setCommonName(commonName);
+ configuration.getGlobal().getCertificate().setPluginName(DefaultPlugins.TSF_CERTIFICATE_MANAGER);
+ if (validityDuration != null) {
+ configuration.getGlobal().getCertificate().setValidityDuration(validityDuration);
+ }
+ if (refreshBefore != null) {
+ configuration.getGlobal().getCertificate().setRefreshBefore(refreshBefore);
+ }
+ if (watchInterval != null) {
+ configuration.getGlobal().getCertificate().setWatchInterval(watchInterval);
+ }
+ TsfCertificateManagerConfig tsfCertificateManagerConfig = new TsfCertificateManagerConfig();
+ tsfCertificateManagerConfig.setAddress(address);
+ tsfCertificateManagerConfig.setCertPath(certPath);
+ tsfCertificateManagerConfig.setToken(token);
+ configuration.getGlobal().getCertificate()
+ .setPluginConfig(DefaultPlugins.TSF_CERTIFICATE_MANAGER, tsfCertificateManagerConfig);
+
+ certificateSDKContext = SDKContext.initContextByConfig(configuration);
+ certificateSDKContext.init();
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ try {
+ if (Objects.nonNull(certificateSDKContext)) {
+ certificateSDKContext.destroy();
+ certificateSDKContext = null;
+ }
+ log.info("Polaris SDK certificate context is destroyed.");
+ }
+ catch (Throwable throwable) {
+ log.info("Polaris SDK certificate context is destroyed failed.", throwable);
+ }
+ }));
+ log.info("create Polaris certificate SDK context successfully.");
+
+ certificateAPI = CertificateAPIFactory.createCertificateAPIByContext(certificateSDKContext);
+ pemFileMap.putAll(certificateAPI.getPemFileMap());
+ }
+
+ public static boolean isInitialized() {
+ return certificateSDKContext != null && certificateAPI != null;
+ }
+
+ public static boolean isVerified() {
+ return isInitialized() && CollectionUtils.isNotEmpty(certificateAPI.getPemFileMap());
+ }
+
+ public static String getPemKeyStoreCertPath() {
+ if (pemFileMap.containsKey(CertFileKey.PemKeyStoreCertPath)) {
+ return pemFileMap.get(CertFileKey.PemKeyStoreCertPath).getPath();
+ }
+ return null;
+ }
+
+ public static String getPemKeyStoreKeyPath() {
+ if (pemFileMap.containsKey(CertFileKey.PrivateKeyFile)) {
+ return pemFileMap.get(CertFileKey.PrivateKeyFile).getPath();
+ }
+ return null;
+ }
+
+ public static String getPemTrustStoreCertPath() {
+ if (pemFileMap.containsKey(CertFileKey.PemTrustStoreCertPath)) {
+ return pemFileMap.get(CertFileKey.PemTrustStoreCertPath).getPath();
+ }
+ return null;
+ }
+}
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..9fe401eda
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.env.EnvironmentPostProcessor=\
+ com.tencent.cloud.plugin.tsf.tls.TlsEnvironmentPostProcessor
diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..fddd05434
--- /dev/null
+++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-tsf-tls-plugin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.tencent.cloud.plugin.tsf.tls.config.TsfTlsAutoConfiguration
diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java
index 9c8bd38ae..d06323720 100644
--- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java
+++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java
@@ -29,6 +29,7 @@ import com.tencent.cloud.polaris.context.admin.PolarisAdminProperties;
import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties;
import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties;
import com.tencent.cloud.polaris.context.config.extend.tsf.TsfInstanceMetadataProvider;
+import com.tencent.cloud.polaris.context.config.extend.tsf.TsfTlsProperties;
import com.tencent.cloud.polaris.context.event.PushGatewayEventReporterConfigModifier;
import com.tencent.cloud.polaris.context.event.PushGatewayEventReporterProperties;
import com.tencent.cloud.polaris.context.listener.PolarisContextApplicationEventListener;
@@ -113,6 +114,12 @@ public class PolarisContextAutoConfiguration {
return new TsfCoreProperties();
}
+ @Bean
+ @ConditionalOnMissingBean
+ public TsfTlsProperties tsfTlsProperties() {
+ return new TsfTlsProperties();
+ }
+
@Bean
@ConditionalOnMissingBean
public TsfInstanceMetadataProvider tsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) {
diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java
index 25f5a891a..6c89fa366 100644
--- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java
+++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java
@@ -89,6 +89,8 @@ public class PolarisContextProperties {
@Value("${spring.cloud.polaris.service:${spring.application.name:}}")
private String service;
+ private Long apiTimeout = 1000L;
+
public Configuration configuration(List modifierList, Supplier ipAddressSupplier, Supplier portSupplier) {
// 1. Read user-defined polaris.yml configuration
ConfigurationImpl configuration = (ConfigurationImpl) ConfigAPIFactory
@@ -105,6 +107,7 @@ public class PolarisContextProperties {
}
configuration.getGlobal().getAPI().setBindIP(defaultHost);
+ configuration.getGlobal().getAPI().setTimeout(apiTimeout);
Collection modifiers = modifierList;
modifiers = modifiers.stream()
@@ -183,6 +186,14 @@ public class PolarisContextProperties {
this.service = service;
}
+ public Long getApiTimeout() {
+ return apiTimeout;
+ }
+
+ public void setApiTimeout(Long apiTimeout) {
+ this.apiTimeout = apiTimeout;
+ }
+
@Override
public String toString() {
return "PolarisContextProperties{" +
@@ -194,6 +205,7 @@ public class PolarisContextProperties {
", enabled=" + enabled +
", namespace='" + namespace + '\'' +
((StringUtils.isBlank(this.service)) ? "" : ", service='" + service + '\'') +
+ ", apiTimeout=" + apiTimeout +
'}';
}
}
diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java
index 8fa0afd88..705a2df1d 100644
--- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java
+++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java
@@ -223,8 +223,6 @@ public class TsfCoreProperties {
if (StringUtils.isNotBlank(getInstanceGroup())) {
tags.add("group=" + getInstanceGroup());
}
- //store the secure flag in the tags so that clients will be able to figure out whether to use http or https automatically
- tags.add("secure=" + getScheme().equalsIgnoreCase("https"));
return tags;
}
diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfTlsProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfTlsProperties.java
new file mode 100644
index 000000000..8dd746fc1
--- /dev/null
+++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfTlsProperties.java
@@ -0,0 +1,112 @@
+/*
+ * Tencent is pleased to support the open source community by making spring-cloud-tencent available.
+ *
+ * Copyright (C) 2021 Tencent. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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 com.tencent.cloud.polaris.context.config.extend.tsf;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Properties for polaris tls.
+ *
+ * @author Haotian Zhang
+ */
+@ConfigurationProperties(prefix = "spring.cloud.polaris.tls")
+public class TsfTlsProperties {
+
+ /**
+ * default validity duration.
+ */
+ public static final long DEFAULT_VALIDITY_DURATION = 30 * 24 * 60 * 60 * 1000L;
+ /**
+ * default refresh before.
+ */
+ public static final long DEFAULT_REFRESH_BEFORE = 24 * 60 * 60 * 1000L;
+ /**
+ * default watch interval.
+ */
+ public static final long DEFAULT_WATCH_INTERVAL = 60 * 60 * 1000L;
+
+ private Long validityDuration = DEFAULT_VALIDITY_DURATION;
+
+ private Long refreshBefore = DEFAULT_REFRESH_BEFORE;
+
+ private Long watchInterval = DEFAULT_WATCH_INTERVAL;
+
+ private Tsf tsf = new Tsf();
+
+ public Long getValidityDuration() {
+ return validityDuration;
+ }
+
+ public void setValidityDuration(Long validityDuration) {
+ this.validityDuration = validityDuration;
+ }
+
+ public Long getRefreshBefore() {
+ return refreshBefore;
+ }
+
+ public void setRefreshBefore(Long refreshBefore) {
+ this.refreshBefore = refreshBefore;
+ }
+
+ public Long getWatchInterval() {
+ return watchInterval;
+ }
+
+ public void setWatchInterval(Long watchInterval) {
+ this.watchInterval = watchInterval;
+ }
+
+ public Tsf getTsf() {
+ return tsf;
+ }
+
+ public void setTsf(Tsf tsf) {
+ this.tsf = tsf;
+ }
+
+ @Override
+ public String toString() {
+ return "TsfTlsProperties{" +
+ "validityDuration=" + validityDuration +
+ ", refreshBefore=" + refreshBefore +
+ ", watchInterval=" + watchInterval +
+ ", tsf=" + tsf +
+ '}';
+ }
+
+ public static class Tsf {
+
+ private String address;
+
+ public String getAddress() {
+ return address;
+ }
+
+ void setAddress(String address) {
+ this.address = address;
+ }
+
+ @Override
+ public String toString() {
+ return "Tsf{" +
+ "address='" + address + '\'' +
+ '}';
+ }
+ }
+}