This is an automated email from the ASF dual-hosted git repository.

jianglongtao pushed a commit to branch fix-33341
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git

commit e1012c49c3f65a412804e6c7ddcaaf8272cec019
Author: Raigor <[email protected]>
AuthorDate: Tue Aug 20 11:30:42 2024 +0800

    Add password decorator (#2)
---
 mode/core/pom.xml                                  |   9 ++
 .../GlobalRuleConfigurationDecorator.java          | 112 +++++++++++++++++++++
 .../AuthorityRuleConfigurationDecorator.java       | 111 ++++++++++++++++++++
 .../decorator/password/AESPasswordDecorator.java   |  94 +++++++++++++++++
 .../mode/decorator/password/PasswordDecorator.java |  40 ++++++++
 .../mode/metadata/MetaDataContextsFactory.java     |  19 +++-
 .../password/AESPasswordDecoratorTest.java         |  39 +++++++
 .../subscriber/ConfigurationChangedSubscriber.java |  13 ++-
 .../ral/queryable/ExportMetaDataExecutor.java      |   8 +-
 .../ral/updatable/ImportMetaDataExecutor.java      |  33 ++++++
 10 files changed, 472 insertions(+), 6 deletions(-)

diff --git a/mode/core/pom.xml b/mode/core/pom.xml
index e0c6d8c7f9c..3d98fe808bf 100644
--- a/mode/core/pom.xml
+++ b/mode/core/pom.xml
@@ -42,11 +42,20 @@
             <artifactId>shardingsphere-metadata-core</artifactId>
             <version>${project.version}</version>
         </dependency>
+        
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
+        </dependency>
         <dependency>
             <groupId>com.zaxxer</groupId>
             <artifactId>HikariCP</artifactId>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
         
         <dependency>
             <groupId>org.apache.shardingsphere</groupId>
diff --git 
a/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/GlobalRuleConfigurationDecorator.java
 
b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/GlobalRuleConfigurationDecorator.java
new file mode 100644
index 00000000000..ade1cc54674
--- /dev/null
+++ 
b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/GlobalRuleConfigurationDecorator.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 com.sphereex.dbplusengine.mode.decorator;
+
+import 
com.sphereex.dbplusengine.mode.decorator.authority.AuthorityRuleConfigurationDecorator;
+import org.apache.shardingsphere.authority.config.AuthorityRuleConfiguration;
+import org.apache.shardingsphere.authority.rule.AuthorityRule;
+import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
+import org.apache.shardingsphere.infra.instance.InstanceContext;
+import 
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereStatistics;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Optional;
+
+/**
+ * Global rule configuration decorator.
+ */
+public final class GlobalRuleConfigurationDecorator {
+    
+    /**
+     * Decorate.
+     *
+     * @param instanceContext Instance context
+     * @param globalRuleConfigs global rule configurations
+     * @param statistics ShardingSphere statistics
+     * @return decorated rule configurations
+     */
+    public Collection<RuleConfiguration> decorate(final InstanceContext 
instanceContext, final Collection<RuleConfiguration> globalRuleConfigs,
+                                                  final 
ShardingSphereStatistics statistics) {
+        Collection<RuleConfiguration> result = new 
LinkedList<>(globalRuleConfigs);
+        if (!isDecorationNeeded(instanceContext, statistics)) {
+            return result;
+        }
+        Optional<AuthorityRuleConfiguration> authorityRuleConfig = 
getAuthorityRuleConfig(globalRuleConfigs);
+        if (!authorityRuleConfig.isPresent()) {
+            return result;
+        }
+        result.removeIf(each -> each instanceof AuthorityRuleConfiguration);
+        result.add(new 
AuthorityRuleConfigurationDecorator(statistics).decorate(authorityRuleConfig.get()));
+        return result;
+    }
+    
+    /**
+     * Restore.
+     *
+     * @param instanceContext Instance context
+     * @param globalRuleConfigs global rule configurations
+     * @param statistics ShardingSphere statistics
+     * @return original rule configuration
+     */
+    public Collection<RuleConfiguration> restore(final InstanceContext 
instanceContext, final Collection<RuleConfiguration> globalRuleConfigs, final 
ShardingSphereStatistics statistics) {
+        Collection<RuleConfiguration> result = new 
LinkedList<>(globalRuleConfigs);
+        if (!isDecorationNeeded(instanceContext, statistics)) {
+            return result;
+        }
+        Optional<AuthorityRuleConfiguration> authorityRuleConfig = 
getAuthorityRuleConfig(globalRuleConfigs);
+        if (!authorityRuleConfig.isPresent()) {
+            return result;
+        }
+        result.removeIf(each -> each instanceof AuthorityRuleConfiguration);
+        result.add(new 
AuthorityRuleConfigurationDecorator(statistics).restore(authorityRuleConfig.get()));
+        return result;
+    }
+    
+    /**
+     * Restore global rules.
+     *
+     * @param globalRules global rules
+     * @param statistics ShardingSphere statistics
+     * @param instanceContext Instance context
+     * @return original rule configuration
+     */
+    public Collection<ShardingSphereRule> restore(final 
Collection<ShardingSphereRule> globalRules, final ShardingSphereStatistics 
statistics, final InstanceContext instanceContext) {
+        Collection<ShardingSphereRule> result = new LinkedList<>(globalRules);
+        if (!isDecorationNeeded(instanceContext, statistics)) {
+            return result;
+        }
+        Optional<AuthorityRule> authorityRule = 
globalRules.stream().filter(each -> each instanceof AuthorityRule).map(each -> 
(AuthorityRule) each).findAny();
+        if (!authorityRule.isPresent()) {
+            return result;
+        }
+        result.removeIf(each -> each instanceof AuthorityRule);
+        AuthorityRuleConfiguration restoredRuleConfig = new 
AuthorityRuleConfigurationDecorator(statistics).restore(authorityRule.get().getConfiguration());
+        result.add(new AuthorityRule(restoredRuleConfig));
+        return result;
+    }
+    
+    private boolean isDecorationNeeded(final InstanceContext instanceContext, 
final ShardingSphereStatistics statistics) {
+        return instanceContext.isCluster() && 
statistics.containsDatabase("shardingsphere");
+    }
+    
+    private Optional<AuthorityRuleConfiguration> getAuthorityRuleConfig(final 
Collection<RuleConfiguration> globalRuleConfigs) {
+        return globalRuleConfigs.stream().filter(each -> each instanceof 
AuthorityRuleConfiguration).map(each -> (AuthorityRuleConfiguration) 
each).findAny();
+    }
+}
diff --git 
a/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/authority/AuthorityRuleConfigurationDecorator.java
 
b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/authority/AuthorityRuleConfigurationDecorator.java
new file mode 100644
index 00000000000..6e0937096fd
--- /dev/null
+++ 
b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/authority/AuthorityRuleConfigurationDecorator.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 com.sphereex.dbplusengine.mode.decorator.authority;
+
+import com.sphereex.dbplusengine.mode.decorator.password.AESPasswordDecorator;
+import org.apache.shardingsphere.authority.config.AuthorityRuleConfiguration;
+import 
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereRowData;
+import 
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereSchemaData;
+import 
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereStatistics;
+import 
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereTableData;
+import org.apache.shardingsphere.infra.metadata.user.Grantee;
+import org.apache.shardingsphere.infra.metadata.user.ShardingSphereUser;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+ * Authority rule configuration decorator.
+ */
+public final class AuthorityRuleConfigurationDecorator {
+    
+    private final AESPasswordDecorator passwordDecorator;
+    
+    public AuthorityRuleConfigurationDecorator(final ShardingSphereStatistics 
shardingSphereData) {
+        String shardingsphereSchemaName = "shardingsphere";
+        ShardingSphereSchemaData schemaData = 
shardingSphereData.getDatabase(shardingsphereSchemaName).getSchemaData().get(shardingsphereSchemaName);
+        ShardingSphereTableData tableData = 
schemaData.getTable("cluster_information");
+        Collection<ShardingSphereRowData> rows = tableData.getRows();
+        passwordDecorator = new 
AESPasswordDecorator(rows.iterator().next().getUniqueKey());
+    }
+    
+    /**
+     * Decorate.
+     *
+     * @param ruleConfig rule configuration
+     * @return decorated rule configuration
+     */
+    public AuthorityRuleConfiguration decorate(final 
AuthorityRuleConfiguration ruleConfig) {
+        Collection<ShardingSphereUser> users = 
decorateUserPassword(ruleConfig.getUsers());
+        return generateAuthorityRuleConfiguration(users, ruleConfig);
+    }
+    
+    private Collection<ShardingSphereUser> decorateUserPassword(final 
Collection<ShardingSphereUser> users) {
+        Collection<ShardingSphereUser> result = new LinkedList<>();
+        for (ShardingSphereUser each : users) {
+            Grantee grantee = each.getGrantee();
+            result.add(new ShardingSphereUser(grantee.getUsername(),
+                    passwordDecorator.decorate(each.getPassword()), 
grantee.getHostname(), each.getAuthenticationMethodName(), each.isAdmin()));
+        }
+        return result;
+    }
+    
+    /**
+     * Restore.
+     *
+     * @param ruleConfig decorated rule configuration
+     * @return original rule configuration
+     */
+    public AuthorityRuleConfiguration restore(final AuthorityRuleConfiguration 
ruleConfig) {
+        Collection<ShardingSphereUser> users = 
restoreUserPassword(ruleConfig.getUsers());
+        return generateAuthorityRuleConfiguration(users, ruleConfig);
+    }
+    
+    private Collection<ShardingSphereUser> restoreUserPassword(final 
Collection<ShardingSphereUser> users) {
+        Collection<ShardingSphereUser> result = new LinkedList<>();
+        for (ShardingSphereUser each : users) {
+            Grantee grantee = each.getGrantee();
+            result.add(new ShardingSphereUser(grantee.getUsername(),
+                    passwordDecorator.restore(each.getPassword()), 
grantee.getHostname(), each.getAuthenticationMethodName(), each.isAdmin()));
+        }
+        return result;
+    }
+    
+    private AuthorityRuleConfiguration 
generateAuthorityRuleConfiguration(final Collection<ShardingSphereUser> users, 
final AuthorityRuleConfiguration ruleConfig) {
+        return new AuthorityRuleConfiguration(users, 
ruleConfig.getPrivilegeProvider(), ruleConfig.getAuthenticators(), 
ruleConfig.getDefaultAuthenticator());
+    }
+    
+    /**
+     * Can be restored.
+     *
+     * @param ruleConfiguration rule configuration
+     * @return true or false
+     */
+    public boolean canBeRestored(final AuthorityRuleConfiguration 
ruleConfiguration) {
+        for (ShardingSphereUser each : ruleConfiguration.getUsers()) {
+            try {
+                passwordDecorator.restore(each.getPassword());
+                // CHECKSTYLE:OFF
+            } catch (Exception ignored) {
+                // CHECKSTYLE:ON
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git 
a/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/AESPasswordDecorator.java
 
b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/AESPasswordDecorator.java
new file mode 100644
index 00000000000..0b7201360c2
--- /dev/null
+++ 
b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/AESPasswordDecorator.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 com.sphereex.dbplusengine.mode.decorator.password;
+
+import lombok.SneakyThrows;
+import org.apache.commons.codec.digest.DigestUtils;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Base64;
+
+/**
+ * AES password decorator.
+ */
+public final class AESPasswordDecorator implements PasswordDecorator {
+    
+    private static final String ALGORITHM = "AES";
+    
+    private static final int GCM_TAG_LENGTH = 128;
+    
+    private static final int IV_LENGTH = 12;
+    
+    private static final String TRANSFORMATION = "AES/GCM/NoPadding";
+    
+    private final SecretKey secretKey;
+    
+    public AESPasswordDecorator(final String uniqueKey) {
+        secretKey = new SecretKeySpec(DigestUtils.sha256(uniqueKey), 
ALGORITHM);
+    }
+    
+    @SneakyThrows(GeneralSecurityException.class)
+    @Override
+    public String decorate(final String plainText) {
+        if (null == plainText) {
+            return null;
+        }
+        SecureRandom random = new SecureRandom();
+        byte[] iv = new byte[IV_LENGTH];
+        random.nextBytes(iv);
+        Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, iv);
+        byte[] encrypted = 
cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
+        byte[] combined = new byte[iv.length + encrypted.length];
+        System.arraycopy(iv, 0, combined, 0, iv.length);
+        System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
+        return Base64.getEncoder().encodeToString(combined);
+    }
+    
+    @SneakyThrows(GeneralSecurityException.class)
+    @Override
+    public String restore(final String cipherText) {
+        if (null == cipherText) {
+            return null;
+        }
+        byte[] combined = Base64.getDecoder().decode(cipherText);
+        byte[] iv = new byte[IV_LENGTH];
+        System.arraycopy(combined, 0, iv, 0, IV_LENGTH);
+        byte[] encrypted = new byte[combined.length - IV_LENGTH];
+        System.arraycopy(combined, IV_LENGTH, encrypted, 0, combined.length - 
IV_LENGTH);
+        Cipher cipher = getCipher(Cipher.DECRYPT_MODE, iv);
+        byte[] decrypted = cipher.doFinal(encrypted);
+        return new String(decrypted, StandardCharsets.UTF_8);
+    }
+    
+    private Cipher getCipher(final int decryptMode, final byte[] iv) throws 
NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, 
InvalidAlgorithmParameterException {
+        GCMParameterSpec gcmParameterSpec = new 
GCMParameterSpec(GCM_TAG_LENGTH, iv);
+        Cipher result = Cipher.getInstance(TRANSFORMATION);
+        result.init(decryptMode, secretKey, gcmParameterSpec);
+        return result;
+    }
+}
diff --git 
a/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/PasswordDecorator.java
 
b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/PasswordDecorator.java
new file mode 100644
index 00000000000..3e2627eee63
--- /dev/null
+++ 
b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/PasswordDecorator.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 com.sphereex.dbplusengine.mode.decorator.password;
+
+/**
+ * Password decorator.
+ */
+public interface PasswordDecorator {
+    
+    /**
+     * Decorate.
+     *
+     * @param originalValue original value
+     * @return decorated value
+     */
+    String decorate(String originalValue);
+    
+    /**
+     * Restore.
+     *
+     * @param decoratedValue decorated value
+     * @return original value
+     */
+    String restore(String decoratedValue);
+}
diff --git 
a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextsFactory.java
 
b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextsFactory.java
index 1edba228140..79fdc4362c9 100644
--- 
a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextsFactory.java
+++ 
b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextsFactory.java
@@ -19,6 +19,7 @@ package org.apache.shardingsphere.mode.metadata;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
+import 
com.sphereex.dbplusengine.mode.decorator.GlobalRuleConfigurationDecorator;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.config.database.DatabaseConfiguration;
@@ -33,6 +34,7 @@ import 
org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
 import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
 import org.apache.shardingsphere.infra.rule.builder.global.GlobalRulesBuilder;
 import org.apache.shardingsphere.infra.state.datasource.DataSourceState;
 import org.apache.shardingsphere.infra.state.datasource.DataSourceStateManager;
@@ -99,10 +101,17 @@ public final class MetaDataContextsFactory {
         ResourceMetaData globalResourceMetaData = new 
ResourceMetaData(globalDataSources);
         RuleMetaData globalRuleMetaData = new 
RuleMetaData(GlobalRulesBuilder.buildRules(globalRuleConfigs, databases, 
props));
         MetaDataContexts result = new MetaDataContexts(persistService, new 
ShardingSphereMetaData(databases, globalResourceMetaData, globalRuleMetaData, 
props));
+        // SPEX CHANGED: BEGIN
         if (!isDatabaseMetaDataExisted) {
-            persistDatabaseConfigurations(result, param);
+            persistDatabaseConfigurations(instanceContext, result, param);
             persistMetaData(result);
+        } else {
+            Collection<ShardingSphereRule> globalRules = new 
GlobalRuleConfigurationDecorator().restore(
+                    result.getMetaData().getGlobalRuleMetaData().getRules(), 
result.getStatistics(), instanceContext);
+            result.getMetaData().getGlobalRuleMetaData().getRules().clear();
+            
result.getMetaData().getGlobalRuleMetaData().getRules().addAll(globalRules);
         }
+        // SPEX CHANGED: END
         return result;
     }
     
@@ -151,8 +160,12 @@ public final class MetaDataContextsFactory {
         return result;
     }
     
-    private static void persistDatabaseConfigurations(final MetaDataContexts 
metadataContexts, final ContextManagerBuilderParameter param) {
-        
metadataContexts.getPersistService().persistGlobalRuleConfiguration(param.getGlobalRuleConfigs(),
 param.getProps());
+    private static void persistDatabaseConfigurations(final InstanceContext 
instanceContext, final MetaDataContexts metadataContexts, final 
ContextManagerBuilderParameter param) {
+        // SPEX CHANGED: BEGIN
+        Collection<RuleConfiguration> globalRuleConfigs = new 
GlobalRuleConfigurationDecorator().decorate(instanceContext,
+                
metadataContexts.getMetaData().getGlobalRuleMetaData().getConfigurations(), 
metadataContexts.getStatistics());
+        
metadataContexts.getPersistService().persistGlobalRuleConfiguration(globalRuleConfigs,
 param.getProps());
+        // SPEX CHANGED: END
         for (Entry<String, ? extends DatabaseConfiguration> entry : 
param.getDatabaseConfigs().entrySet()) {
             String databaseName = entry.getKey();
             
metadataContexts.getPersistService().persistConfigurations(entry.getKey(), 
entry.getValue(),
diff --git 
a/mode/core/src/test/java/org/apache/shardingsphere/mode/decorator/password/AESPasswordDecoratorTest.java
 
b/mode/core/src/test/java/org/apache/shardingsphere/mode/decorator/password/AESPasswordDecoratorTest.java
new file mode 100644
index 00000000000..85f1ebad212
--- /dev/null
+++ 
b/mode/core/src/test/java/org/apache/shardingsphere/mode/decorator/password/AESPasswordDecoratorTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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.apache.shardingsphere.mode.decorator.password;
+
+import com.sphereex.dbplusengine.mode.decorator.password.AESPasswordDecorator;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.not;
+
+class AESPasswordDecoratorTest {
+    
+    @Test
+    void assertDecorateAndRestore() {
+        String plainText = "password";
+        AESPasswordDecorator decorator = new 
AESPasswordDecorator("0e85e2025a653e7bf27efca5ca243c45");
+        String cipherText0 = decorator.decorate(plainText);
+        String cipherText1 = decorator.decorate(plainText);
+        assertThat(cipherText0, not(cipherText1));
+        assertThat(decorator.restore(cipherText0), is(plainText));
+        assertThat(decorator.restore(cipherText1), is(plainText));
+    }
+}
diff --git 
a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/subscriber/ConfigurationChangedSubscriber.java
 
b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/subscriber/ConfigurationChangedSubscriber.java
index 763d821fc5c..b01e798e91d 100644
--- 
a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/subscriber/ConfigurationChangedSubscriber.java
+++ 
b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/subscriber/ConfigurationChangedSubscriber.java
@@ -18,6 +18,8 @@
 package org.apache.shardingsphere.mode.manager.cluster.coordinator.subscriber;
 
 import com.google.common.eventbus.Subscribe;
+import 
com.sphereex.dbplusengine.mode.decorator.GlobalRuleConfigurationDecorator;
+import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
 import 
org.apache.shardingsphere.mode.event.config.AlterDatabaseRuleConfigurationEvent;
 import 
org.apache.shardingsphere.mode.event.config.DropDatabaseRuleConfigurationEvent;
 import 
org.apache.shardingsphere.mode.event.config.global.AlterGlobalRuleConfigurationEvent;
@@ -27,6 +29,9 @@ import 
org.apache.shardingsphere.mode.event.datasource.unit.RegisterStorageUnitE
 import 
org.apache.shardingsphere.mode.event.datasource.unit.UnregisterStorageUnitEvent;
 import org.apache.shardingsphere.mode.manager.ContextManager;
 
+import java.util.Collection;
+import java.util.Collections;
+
 /**
  * Configuration changed subscriber.
  */
@@ -117,8 +122,12 @@ public final class ConfigurationChangedSubscriber {
         if 
(!event.getActiveVersion().equals(contextManager.getMetaDataContexts().getPersistService().getMetaDataVersionPersistService().getActiveVersionByFullPath(event.getActiveVersionKey())))
 {
             return;
         }
-        contextManager.getConfigurationContextManager()
-                
.alterGlobalRuleConfiguration(contextManager.getMetaDataContexts().getPersistService().getGlobalRuleService().load(event.getRuleSimpleName()));
+        // SPEX CHANGED: BEGIN
+        RuleConfiguration ruleConfig = 
contextManager.getMetaDataContexts().getPersistService().getGlobalRuleService().load(event.getRuleSimpleName());
+        Collection<RuleConfiguration> configs = new 
GlobalRuleConfigurationDecorator()
+                .restore(contextManager.getInstanceContext(), 
Collections.singletonList(ruleConfig), 
contextManager.getMetaDataContexts().getStatistics());
+        
contextManager.getConfigurationContextManager().alterGlobalRuleConfiguration(configs.iterator().next());
+        // SPEX CHANGED: END
     }
     
     /**
diff --git 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/ExportMetaDataExecutor.java
 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/ExportMetaDataExecutor.java
index 1cee2a0bedb..ff83bbad6e9 100644
--- 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/ExportMetaDataExecutor.java
+++ 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/ExportMetaDataExecutor.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.proxy.backend.handler.distsql.ral.queryable;
 
+import 
com.sphereex.dbplusengine.mode.decorator.GlobalRuleConfigurationDecorator;
 import org.apache.commons.codec.binary.Base64;
 import 
org.apache.shardingsphere.distsql.handler.engine.query.DistSQLQueryExecutor;
 import 
org.apache.shardingsphere.distsql.statement.ral.queryable.export.ExportMetaDataStatement;
@@ -75,7 +76,12 @@ public final class ExportMetaDataExecutor implements 
DistSQLQueryExecutor<Export
         ExportedMetaData exportedMetaData = new ExportedMetaData();
         exportedMetaData.setDatabases(getDatabases(proxyContext));
         
exportedMetaData.setProps(generatePropsData(metaData.getProps().getProps()));
-        
exportedMetaData.setRules(generateRulesData(metaData.getGlobalRuleMetaData().getConfigurations()));
+        // SPEX CHANGED: BEGIN
+        ContextManager contextManager = 
ProxyContext.getInstance().getContextManager();
+        Collection<RuleConfiguration> globalRuleConfigs = new 
GlobalRuleConfigurationDecorator().decorate(contextManager.getInstanceContext(),
+                metaData.getGlobalRuleMetaData().getConfigurations(), 
contextManager.getMetaDataContexts().getStatistics());
+        exportedMetaData.setRules(generateRulesData(globalRuleConfigs));
+        // SPEX CHANGED: END
         ExportedClusterInfo exportedClusterInfo = new ExportedClusterInfo();
         exportedClusterInfo.setMetaData(exportedMetaData);
         generateSnapshotInfo(metaData, exportedClusterInfo);
diff --git 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/ImportMetaDataExecutor.java
 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/ImportMetaDataExecutor.java
index d90f79aff93..d5f3e91af2b 100644
--- 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/ImportMetaDataExecutor.java
+++ 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/ImportMetaDataExecutor.java
@@ -17,8 +17,10 @@
 
 package org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable;
 
+import 
com.sphereex.dbplusengine.mode.decorator.authority.AuthorityRuleConfigurationDecorator;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.FileUtils;
+import org.apache.shardingsphere.authority.config.AuthorityRuleConfiguration;
 import 
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
 import 
org.apache.shardingsphere.distsql.statement.ral.updatable.ImportMetaDataStatement;
 import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
@@ -26,8 +28,11 @@ import org.apache.shardingsphere.infra.util.json.JsonUtils;
 import org.apache.shardingsphere.infra.util.yaml.YamlEngine;
 import 
org.apache.shardingsphere.infra.yaml.config.swapper.rule.YamlRuleConfigurationSwapperEngine;
 import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
+import 
org.apache.shardingsphere.mode.repository.standalone.StandalonePersistRepository;
 import 
org.apache.shardingsphere.proxy.backend.config.yaml.YamlProxyDatabaseConfiguration;
 import 
org.apache.shardingsphere.proxy.backend.config.yaml.YamlProxyServerConfiguration;
+import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import 
org.apache.shardingsphere.proxy.backend.distsql.export.ExportedClusterInfo;
 import org.apache.shardingsphere.proxy.backend.distsql.export.ExportedMetaData;
 import org.apache.shardingsphere.infra.exception.generic.FileIOException;
@@ -38,6 +43,7 @@ import java.io.IOException;
 import java.nio.charset.Charset;
 import java.sql.SQLException;
 import java.util.Collection;
+import java.util.Optional;
 
 /**
  * Import meta data executor.
@@ -73,11 +79,38 @@ public final class ImportMetaDataExecutor implements 
DistSQLUpdateExecutor<Impor
             return;
         }
         Collection<RuleConfiguration> rules = 
ruleConfigSwapperEngine.swapToRuleConfigurations(yamlServerConfig.getRules());
+        // SPEX ADDED: BEGIN
+        decorateGlobalRuleConfigurations(rules);
+        // SPEX ADDED: END
         rules.forEach(each -> 
contextManager.getInstanceContext().getModeContextManager().alterGlobalRuleConfiguration(each));
         
contextManager.getInstanceContext().getModeContextManager().alterProperties(yamlServerConfig.getProps());
     }
     
+    private void decorateGlobalRuleConfigurations(final 
Collection<RuleConfiguration> rules) {
+        MetaDataContexts metaDataContexts = 
ProxyContext.getInstance().getContextManager().getMetaDataContexts();
+        if (metaDataContexts.getPersistService().getRepository() instanceof 
StandalonePersistRepository) {
+            return;
+        }
+        if 
(!metaDataContexts.getStatistics().containsDatabase("shardingsphere")) {
+            return;
+        }
+        Optional<AuthorityRuleConfiguration> ruleConfig = rules.stream()
+                .filter(each -> each instanceof 
AuthorityRuleConfiguration).map(each -> (AuthorityRuleConfiguration) 
each).findAny();
+        if (!ruleConfig.isPresent()) {
+            return;
+        }
+        AuthorityRuleConfigurationDecorator 
authorityRuleConfigurationDecorator = new 
AuthorityRuleConfigurationDecorator(metaDataContexts.getStatistics());
+        if 
(!authorityRuleConfigurationDecorator.canBeRestored(ruleConfig.get())) {
+            rules.removeIf(each -> each instanceof AuthorityRuleConfiguration);
+            AuthorityRuleConfiguration decoratedRuleConfig = 
authorityRuleConfigurationDecorator.decorate(ruleConfig.get());
+            rules.add(decoratedRuleConfig);
+        }
+    }
+    
     private void importDatabase(final ExportedMetaData exportedMetaData) {
+        if (null == exportedMetaData.getDatabases() || 
exportedMetaData.getDatabases().isEmpty()) {
+            return;
+        }
         for (String each : exportedMetaData.getDatabases().values()) {
             YamlProxyDatabaseConfiguration yamlDatabaseConfig = 
YamlEngine.unmarshal(each, YamlProxyDatabaseConfiguration.class);
             
databaseConfigImportExecutor.importDatabaseConfiguration(yamlDatabaseConfig);


Reply via email to