This is an automated email from the ASF dual-hosted git repository. liubao pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git
The following commit(s) were added to refs/heads/master by this push: new 5ff9fa07b [SCB-2863]support zookeeper authentication (#4292) 5ff9fa07b is described below commit 5ff9fa07b75151a5c9fac1dd98cb18e399153b69 Author: liubao68 <bi...@qq.com> AuthorDate: Tue Apr 2 20:37:43 2024 +0800 [SCB-2863]support zookeeper authentication (#4292) --- .../config/zookeeper/ZookeeperClient.java | 48 +++++++++++++++++++-- .../config/zookeeper/ZookeeperConfig.java | 12 ++++++ .../registry/zookeeper/ZookeeperDiscovery.java | 48 +++++++++++++++++++-- .../registry/zookeeper/ZookeeperRegistration.java | 49 ++++++++++++++++++++-- .../zookeeper/ZookeeperRegistryProperties.java | 20 +++++++++ 5 files changed, 168 insertions(+), 9 deletions(-) diff --git a/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperClient.java b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperClient.java index 56d9ff7b8..32554923e 100644 --- a/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperClient.java +++ b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperClient.java @@ -24,6 +24,9 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + import org.apache.commons.lang3.StringUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; @@ -31,6 +34,7 @@ import org.apache.curator.framework.recipes.cache.CuratorCache; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.servicecomb.config.BootStrapProperties; import org.apache.servicecomb.config.zookeeper.ZookeeperDynamicPropertiesSource.UpdateHandler; +import org.apache.zookeeper.server.auth.DigestLoginModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; @@ -38,6 +42,29 @@ import org.springframework.core.env.Environment; import org.springframework.core.io.ByteArrayResource; public class ZookeeperClient { + static class ZookeeperSASLConfig extends Configuration { + AppConfigurationEntry entry; + + public ZookeeperSASLConfig(String username, + String password) { + Map<String, String> options = new HashMap<>(); + options.put("username", username); + options.put("password", password); + this.entry = new AppConfigurationEntry( + DigestLoginModule.class.getName(), + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, + options + ); + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + AppConfigurationEntry[] array = new AppConfigurationEntry[1]; + array[0] = entry; + return array; + } + } + private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperClient.class); public static final String PATH_ENVIRONMENT = "/servicecomb/config/environment/%s"; @@ -70,6 +97,7 @@ public class ZookeeperClient { private Map<String, Object> allLast = new HashMap<>(); + public ZookeeperClient(UpdateHandler updateHandler, Environment environment) { this.updateHandler = updateHandler; this.zookeeperConfig = new ZookeeperConfig(environment); @@ -77,9 +105,23 @@ public class ZookeeperClient { } public void refreshZookeeperConfig() throws Exception { - CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperConfig.getConnectString(), - zookeeperConfig.getSessionTimeoutMillis(), zookeeperConfig.getConnectionTimeoutMillis(), - new ExponentialBackoffRetry(1000, 3)); + CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() + .connectString(zookeeperConfig.getConnectString()) + .sessionTimeoutMs(zookeeperConfig.getSessionTimeoutMillis()) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)); + String authSchema = zookeeperConfig.getAuthSchema(); + if (StringUtils.isNotEmpty(authSchema)) { + if (!"digest".equals(authSchema)) { + throw new IllegalStateException("Not supported schema now. " + authSchema); + } + if (zookeeperConfig.getAuthInfo() == null) { + throw new IllegalStateException("Auth info can not be empty. "); + } + + String[] authInfo = zookeeperConfig.getAuthInfo().split(":"); + Configuration.setConfiguration(new ZookeeperSASLConfig(authInfo[0], authInfo[1])); + } + CuratorFramework client = builder.build(); client.start(); String env = BootStrapProperties.readServiceEnvironment(environment); diff --git a/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperConfig.java b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperConfig.java index 090ba15f3..074939c58 100644 --- a/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperConfig.java +++ b/dynamic-config/config-zookeeper/src/main/java/org/apache/servicecomb/config/zookeeper/ZookeeperConfig.java @@ -27,6 +27,10 @@ public class ZookeeperConfig { public static final String PROPERTY_CONNECTION_TIMEOUT = "servicecomb.config.zk.connection-timeout-mills"; + public static final String PROPERTY_AUTH_SCHEMA = "servicecomb.config.zk.authentication-schema"; + + public static final String PROPERTY_AUTH_INFO = "servicecomb.config.zk.authentication-info"; + private final Environment environment; public ZookeeperConfig(Environment environment) { @@ -44,4 +48,12 @@ public class ZookeeperConfig { public int getConnectionTimeoutMillis() { return environment.getProperty(PROPERTY_CONNECTION_TIMEOUT, int.class, 1000); } + + public String getAuthSchema() { + return environment.getProperty(PROPERTY_AUTH_SCHEMA); + } + + public String getAuthInfo() { + return environment.getProperty(PROPERTY_AUTH_INFO); + } } diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscovery.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscovery.java index fdd8ce078..4d871b3a1 100644 --- a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscovery.java +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperDiscovery.java @@ -16,12 +16,16 @@ */ package org.apache.servicecomb.registry.zookeeper; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + import org.apache.commons.lang3.StringUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; @@ -37,12 +41,36 @@ import org.apache.curator.x.discovery.details.ServiceCacheListener; import org.apache.servicecomb.config.BootStrapProperties; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; import org.apache.servicecomb.registry.api.Discovery; +import org.apache.zookeeper.server.auth.DigestLoginModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; public class ZookeeperDiscovery implements Discovery<ZookeeperDiscoveryInstance> { + static class ZookeeperSASLConfig extends Configuration { + AppConfigurationEntry entry; + + public ZookeeperSASLConfig(String username, + String password) { + Map<String, String> options = new HashMap<>(); + options.put("username", username); + options.put("password", password); + this.entry = new AppConfigurationEntry( + DigestLoginModule.class.getName(), + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, + options + ); + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + AppConfigurationEntry[] array = new AppConfigurationEntry[1]; + array[0] = entry; + return array; + } + } + private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperDiscovery.class); private final Map<String, ServiceCache<ZookeeperInstance>> serviceDiscoveries = @@ -145,9 +173,23 @@ public class ZookeeperDiscovery implements Discovery<ZookeeperDiscoveryInstance> @Override public void run() { - client = CuratorFrameworkFactory.newClient(zookeeperRegistryProperties.getConnectString(), - zookeeperRegistryProperties.getSessionTimeoutMillis(), zookeeperRegistryProperties.getConnectionTimeoutMillis(), - new ExponentialBackoffRetry(1000, 3)); + CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() + .connectString(zookeeperRegistryProperties.getConnectString()) + .sessionTimeoutMs(zookeeperRegistryProperties.getSessionTimeoutMillis()) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)); + String authSchema = zookeeperRegistryProperties.getAuthenticationSchema(); + if (StringUtils.isNotEmpty(authSchema)) { + if (!"digest".equals(authSchema)) { + throw new IllegalStateException("Not supported schema now. " + authSchema); + } + if (zookeeperRegistryProperties.getAuthenticationInfo() == null) { + throw new IllegalStateException("Auth info can not be empty. "); + } + + String[] authInfo = zookeeperRegistryProperties.getAuthenticationInfo().split(":"); + Configuration.setConfiguration(new ZookeeperSASLConfig(authInfo[0], authInfo[1])); + } + client = builder.build(); client.start(); } diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistration.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistration.java index e7c8c1aa6..1e819926a 100644 --- a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistration.java +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistration.java @@ -16,8 +16,13 @@ */ package org.apache.servicecomb.registry.zookeeper; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + import org.apache.commons.lang3.StringUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; @@ -32,10 +37,34 @@ import org.apache.servicecomb.config.DataCenterProperties; import org.apache.servicecomb.registry.api.DataCenterInfo; import org.apache.servicecomb.registry.api.MicroserviceInstanceStatus; import org.apache.servicecomb.registry.api.Registration; +import org.apache.zookeeper.server.auth.DigestLoginModule; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; public class ZookeeperRegistration implements Registration<ZookeeperRegistrationInstance> { + static class ZookeeperSASLConfig extends Configuration { + AppConfigurationEntry entry; + + public ZookeeperSASLConfig(String username, + String password) { + Map<String, String> options = new HashMap<>(); + options.put("username", username); + options.put("password", password); + this.entry = new AppConfigurationEntry( + DigestLoginModule.class.getName(), + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, + options + ); + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + AppConfigurationEntry[] array = new AppConfigurationEntry[1]; + array[0] = entry; + return array; + } + } + private Environment environment; private ZookeeperRegistryProperties zookeeperRegistryProperties; @@ -99,9 +128,23 @@ public class ZookeeperRegistration implements Registration<ZookeeperRegistration @Override public void run() { - client = CuratorFrameworkFactory.newClient(zookeeperRegistryProperties.getConnectString(), - zookeeperRegistryProperties.getSessionTimeoutMillis(), zookeeperRegistryProperties.getConnectionTimeoutMillis(), - new ExponentialBackoffRetry(1000, 3)); + CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() + .connectString(zookeeperRegistryProperties.getConnectString()) + .sessionTimeoutMs(zookeeperRegistryProperties.getSessionTimeoutMillis()) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)); + String authSchema = zookeeperRegistryProperties.getAuthenticationSchema(); + if (StringUtils.isNotEmpty(authSchema)) { + if (!"digest".equals(authSchema)) { + throw new IllegalStateException("Not supported schema now. " + authSchema); + } + if (zookeeperRegistryProperties.getAuthenticationInfo() == null) { + throw new IllegalStateException("Auth info can not be empty. "); + } + + String[] authInfo = zookeeperRegistryProperties.getAuthenticationInfo().split(":"); + Configuration.setConfiguration(new ZookeeperDiscovery.ZookeeperSASLConfig(authInfo[0], authInfo[1])); + } + client = builder.build(); client.start(); JsonInstanceSerializer<ZookeeperInstance> serializer = new JsonInstanceSerializer<>(ZookeeperInstance.class); diff --git a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistryProperties.java b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistryProperties.java index f1fa0a773..cea946d99 100644 --- a/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistryProperties.java +++ b/service-registry/registry-zookeeper/src/main/java/org/apache/servicecomb/registry/zookeeper/ZookeeperRegistryProperties.java @@ -23,6 +23,10 @@ public class ZookeeperRegistryProperties { private String connectString = "zookeeper://127.0.0.1:2181"; + private String authenticationSchema; + + private String authenticationInfo; + private int connectionTimeoutMillis = 1000; private int sessionTimeoutMillis = 60000; @@ -76,4 +80,20 @@ public class ZookeeperRegistryProperties { public void setEnableSwaggerRegistration(boolean enableSwaggerRegistration) { this.enableSwaggerRegistration = enableSwaggerRegistration; } + + public String getAuthenticationSchema() { + return authenticationSchema; + } + + public void setAuthenticationSchema(String authenticationSchema) { + this.authenticationSchema = authenticationSchema; + } + + public String getAuthenticationInfo() { + return authenticationInfo; + } + + public void setAuthenticationInfo(String authenticationInfo) { + this.authenticationInfo = authenticationInfo; + } }