You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by pa...@apache.org on 2021/03/26 04:49:50 UTC

[shardingsphere] branch master updated: Update user privilege in real time (#9796)

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

panjuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new b9feef8  Update user privilege in real time (#9796)
b9feef8 is described below

commit b9feef846dd79ad2841c8287acaf896e2b9ab49c
Author: JingShang Lu <lu...@apache.org>
AuthorDate: Fri Mar 26 12:49:25 2021 +0800

    Update user privilege in real time (#9796)
    
    * Update user privilege in real time
    
    * fix
    
    * fix
    
    * fix
    
    * fix
---
 .../metadata/GovernanceMetaDataContexts.java       | 32 ++++++++++++++++
 .../metadata/GovernanceMetaDataContextsTest.java   |  5 ++-
 .../event/model/auth/PrivilegeChangedEvent.java    | 22 ++++++-----
 .../governance/core/registry/RegistryCenter.java   | 17 +++++++++
 .../core/registry/RegistryCenterNode.java          | 11 ++++++
 .../listener/PrivilegeNodeChangedListener.java     | 44 ++++++++++++++++++++++
 .../registry/listener/RegistryListenerManager.java |  4 ++
 .../GrantEvent.java}                               | 21 ++++++-----
 .../type/GrantStatementAuthRefresher.java          | 15 +++++++-
 9 files changed, 149 insertions(+), 22 deletions(-)

diff --git a/shardingsphere-governance/shardingsphere-governance-context/src/main/java/org/apache/shardingsphere/governance/context/metadata/GovernanceMetaDataContexts.java b/shardingsphere-governance/shardingsphere-governance-context/src/main/java/org/apache/shardingsphere/governance/context/metadata/GovernanceMetaDataContexts.java
index def19de..890af4a 100644
--- a/shardingsphere-governance/shardingsphere-governance-context/src/main/java/org/apache/shardingsphere/governance/context/metadata/GovernanceMetaDataContexts.java
+++ b/shardingsphere-governance/shardingsphere-governance-context/src/main/java/org/apache/shardingsphere/governance/context/metadata/GovernanceMetaDataContexts.java
@@ -19,6 +19,7 @@ package org.apache.shardingsphere.governance.context.metadata;
 
 import com.google.common.collect.Maps;
 import com.google.common.eventbus.Subscribe;
+import org.apache.shardingsphere.governance.core.event.model.auth.PrivilegeChangedEvent;
 import org.apache.shardingsphere.governance.core.event.model.auth.UserRuleChangedEvent;
 import org.apache.shardingsphere.governance.core.event.model.datasource.DataSourceChangeCompletedEvent;
 import org.apache.shardingsphere.governance.core.event.model.datasource.DataSourceChangedEvent;
@@ -46,6 +47,9 @@ import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
 import org.apache.shardingsphere.infra.lock.ShardingSphereLock;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import org.apache.shardingsphere.infra.metadata.auth.Authentication;
+import org.apache.shardingsphere.infra.metadata.auth.builder.PrivilegeBuilder;
+import org.apache.shardingsphere.infra.metadata.auth.builder.loader.PrivilegeLoader;
+import org.apache.shardingsphere.infra.metadata.auth.builder.loader.PrivilegeLoaderEngine;
 import org.apache.shardingsphere.infra.metadata.auth.builtin.DefaultAuthentication;
 import org.apache.shardingsphere.infra.metadata.auth.model.privilege.ShardingSpherePrivilege;
 import org.apache.shardingsphere.infra.metadata.auth.model.user.ShardingSphereUser;
@@ -211,6 +215,18 @@ public final class GovernanceMetaDataContexts implements MetaDataContexts {
         DefaultAuthentication authentication = new DefaultAuthentication(getNewUsers(users));
         authentication.getAuthentication().putAll(getModifiedUsers(users));
         metaDataContexts = new StandardMetaDataContexts(metaDataContexts.getMetaDataMap(), metaDataContexts.getExecutorEngine(), authentication, metaDataContexts.getProps());
+        reloadPrivilege(users);
+    }
+    
+    /**
+     * Renew privilege.
+     *
+     * @param event privilege changed event
+     */
+    @Subscribe
+    public synchronized void renew(final PrivilegeChangedEvent event) {
+        Collection<ShardingSphereUser> users = event.getUsers();
+        reloadPrivilege(users);
     }
     
     /**
@@ -393,4 +409,20 @@ public final class GovernanceMetaDataContexts implements MetaDataContexts {
         }
         return result;
     }
+    
+    private void reloadPrivilege(final Collection<ShardingSphereUser> users) {
+        Optional<PrivilegeLoader> loader = PrivilegeLoaderEngine.findPrivilegeLoader(metaDataContexts.getMetaDataMap().values().iterator().next().getResource().getDatabaseType());
+        if (!loader.isPresent()) {
+            return;
+        }
+        Map<ShardingSphereUser, ShardingSpherePrivilege> result = PrivilegeBuilder.build(metaDataContexts.getMetaDataMap().values(), users, metaDataContexts.getProps());
+        for (Entry<ShardingSphereUser, ShardingSpherePrivilege> each : result.entrySet()) {
+            Optional<ShardingSphereUser> user = metaDataContexts.getAuthentication().getAuthentication().keySet().stream().filter(t -> t.getGrantee().equals(t.getGrantee())).findFirst();
+            if (user.isPresent() && null != result.get(each.getKey())) {
+                metaDataContexts.getAuthentication().getAuthentication().put(user.get(), each.getValue());
+            } else if (!user.isPresent() && null != result.get(each.getKey())) {
+                metaDataContexts.getAuthentication().getAuthentication().put(each.getKey(), each.getValue());
+            }
+        }
+    }
 }
diff --git a/shardingsphere-governance/shardingsphere-governance-context/src/test/java/org/apache/shardingsphere/governance/context/metadata/GovernanceMetaDataContextsTest.java b/shardingsphere-governance/shardingsphere-governance-context/src/test/java/org/apache/shardingsphere/governance/context/metadata/GovernanceMetaDataContextsTest.java
index 810e6aa..00d4eaa 100644
--- a/shardingsphere-governance/shardingsphere-governance-context/src/test/java/org/apache/shardingsphere/governance/context/metadata/GovernanceMetaDataContextsTest.java
+++ b/shardingsphere-governance/shardingsphere-governance-context/src/test/java/org/apache/shardingsphere/governance/context/metadata/GovernanceMetaDataContextsTest.java
@@ -32,6 +32,7 @@ import org.apache.shardingsphere.infra.config.datasource.DataSourceConfiguration
 import org.apache.shardingsphere.infra.config.properties.ConfigurationProperties;
 import org.apache.shardingsphere.infra.config.properties.ConfigurationPropertyKey;
 import org.apache.shardingsphere.infra.context.metadata.impl.StandardMetaDataContexts;
+import org.apache.shardingsphere.infra.database.type.dialect.MySQLDatabaseType;
 import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import org.apache.shardingsphere.infra.metadata.auth.builtin.DefaultAuthentication;
@@ -97,7 +98,9 @@ public final class GovernanceMetaDataContextsTest {
     
     private Map<String, ShardingSphereMetaData> createMetaDataMap() {
         when(metaData.getName()).thenReturn("schema");
-        when(metaData.getResource()).thenReturn(mock(ShardingSphereResource.class));
+        ShardingSphereResource resource = mock(ShardingSphereResource.class);
+        when(resource.getDatabaseType()).thenReturn(new MySQLDatabaseType());
+        when(metaData.getResource()).thenReturn(resource);
         when(metaData.getSchema()).thenReturn(mock(ShardingSphereSchema.class));
         when(metaData.getRuleMetaData().getRules()).thenReturn(Collections.singletonList(readWriteSplittingRule));
         return Collections.singletonMap("schema", metaData);
diff --git a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/event/model/auth/PrivilegeChangedEvent.java
similarity index 55%
copy from shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java
copy to shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/event/model/auth/PrivilegeChangedEvent.java
index 0909dc2..a7133fb 100644
--- a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java
+++ b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/event/model/auth/PrivilegeChangedEvent.java
@@ -15,19 +15,21 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.metadata.auth.refresher.type;
+package org.apache.shardingsphere.governance.core.event.model.auth;
 
-import org.apache.shardingsphere.infra.metadata.auth.Authentication;
-import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
-import org.apache.shardingsphere.infra.metadata.auth.refresher.AuthenticationRefresher;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.governance.core.event.model.GovernanceEvent;
+import org.apache.shardingsphere.infra.metadata.auth.model.user.ShardingSphereUser;
+
+import java.util.Collection;
 
 /**
- * Grant statement auth refresher.
+ * Privilege changed event.
  */
-public final class GrantStatementAuthRefresher implements AuthenticationRefresher {
+@RequiredArgsConstructor
+@Getter
+public final class PrivilegeChangedEvent implements GovernanceEvent {
     
-    @Override
-    public void refresh(final Authentication authentication, final SQLStatement sqlStatement, final ShardingSphereMetaData metaData) {
-    }
+    private final Collection<ShardingSphereUser> users;
 }
diff --git a/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/RegistryCenter.java b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/RegistryCenter.java
index f88fccd..d11d7b1 100644
--- a/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/RegistryCenter.java
+++ b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/RegistryCenter.java
@@ -45,6 +45,7 @@ import org.apache.shardingsphere.infra.eventbus.ShardingSphereEventBus;
 import org.apache.shardingsphere.infra.metadata.auth.builtin.yaml.swapper.UserRuleYamlSwapper;
 import org.apache.shardingsphere.infra.metadata.auth.model.user.ShardingSphereUser;
 import org.apache.shardingsphere.infra.metadata.auth.refresher.event.CreateUserEvent;
+import org.apache.shardingsphere.infra.metadata.auth.refresher.event.GrantEvent;
 import org.apache.shardingsphere.infra.metadata.schema.ShardingSphereSchema;
 import org.apache.shardingsphere.infra.metadata.schema.refresher.event.SchemaAlteredEvent;
 import org.apache.shardingsphere.infra.rule.event.impl.DataSourceDisabledEvent;
@@ -195,6 +196,12 @@ public final class RegistryCenter {
                     YamlEngine.marshal(new UserRuleYamlSwapper().swapToYamlConfiguration(users)));
         }
     }
+    
+    private void persistChangedPrivilege(final Collection<ShardingSphereUser> users) {
+        if (!users.isEmpty()) {
+            repository.persist(node.getPrivilegeNodePath(), YamlEngine.marshal(new UserRuleYamlSwapper().swapToYamlConfiguration(users)));
+        }
+    }
 
     private void persistProperties(final Properties props, final boolean isOverwrite) {
         if (!props.isEmpty() && (isOverwrite || !hasProperties())) {
@@ -459,6 +466,16 @@ public final class RegistryCenter {
     }
     
     /**
+     * User with changed privilege cached event.
+     *
+     * @param event grant event
+     */
+    @Subscribe
+    public synchronized void renew(final GrantEvent event) {
+        persistChangedPrivilege(event.getUsers());
+    }
+    
+    /**
      * Persist instance online.
      */
     public void persistInstanceOnline() {
diff --git a/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/RegistryCenterNode.java b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/RegistryCenterNode.java
index 7b0e340..c5fe9de 100644
--- a/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/RegistryCenterNode.java
+++ b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/RegistryCenterNode.java
@@ -55,6 +55,8 @@ public final class RegistryCenterNode {
     
     private static final String AUTHENTICATION_NODE = "authentication";
     
+    private static final String PRIVILEGE_NODE = "privilegenode";
+    
     private static final String PROPS_NODE = "props";
     
     private static final String COMMA_SEPARATOR = ",";
@@ -253,6 +255,15 @@ public final class RegistryCenterNode {
     }
     
     /**
+     * Get authenticationnodes path.
+     *
+     * @return authenticationnodes path
+     */
+    public String getPrivilegeNodePath() {
+        return Joiner.on(PATH_SEPARATOR).join(ROOT, PRIVILEGE_NODE);
+    }
+    
+    /**
      * Get properties path.
      *
      * @return properties path
diff --git a/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/listener/PrivilegeNodeChangedListener.java b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/listener/PrivilegeNodeChangedListener.java
new file mode 100644
index 0000000..3b7dc8a
--- /dev/null
+++ b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/listener/PrivilegeNodeChangedListener.java
@@ -0,0 +1,44 @@
+/*
+ * 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.governance.core.registry.listener;
+
+import org.apache.shardingsphere.governance.core.event.listener.PostGovernanceRepositoryEventListener;
+import org.apache.shardingsphere.governance.core.event.model.GovernanceEvent;
+import org.apache.shardingsphere.governance.core.event.model.auth.PrivilegeChangedEvent;
+import org.apache.shardingsphere.governance.core.registry.RegistryCenterNode;
+import org.apache.shardingsphere.governance.core.yaml.config.YamlConfigurationConverter;
+import org.apache.shardingsphere.governance.repository.api.RegistryRepository;
+import org.apache.shardingsphere.governance.repository.api.listener.DataChangedEvent;
+
+import java.util.Collections;
+import java.util.Optional;
+
+/**
+ * Authentication changed listener.
+ */
+public final class PrivilegeNodeChangedListener extends PostGovernanceRepositoryEventListener<GovernanceEvent> {
+    
+    public PrivilegeNodeChangedListener(final RegistryRepository registryRepository) {
+        super(registryRepository, Collections.singletonList(new RegistryCenterNode().getPrivilegeNodePath()));
+    }
+    
+    @Override
+    protected Optional<GovernanceEvent> createEvent(final DataChangedEvent event) {
+        return Optional.of(new PrivilegeChangedEvent(YamlConfigurationConverter.convertUserRule(event.getValue())));
+    }
+}
diff --git a/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/listener/RegistryListenerManager.java b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/listener/RegistryListenerManager.java
index 5cabee7..03bceda 100644
--- a/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/listener/RegistryListenerManager.java
+++ b/shardingsphere-governance/shardingsphere-governance-core/src/main/java/org/apache/shardingsphere/governance/core/registry/listener/RegistryListenerManager.java
@@ -40,6 +40,8 @@ public final class RegistryListenerManager {
 
     private final AuthenticationChangedListener authenticationChangedListener;
     
+    private final PrivilegeNodeChangedListener privilegeNodeChangedListener;
+    
     public RegistryListenerManager(final RegistryRepository registryRepository, final Collection<String> schemaNames) {
         terminalStateChangedListener = new TerminalStateChangedListener(registryRepository);
         dataSourceStateChangedListener = new DataSourceStateChangedListener(registryRepository, schemaNames);
@@ -47,6 +49,7 @@ public final class RegistryListenerManager {
         metaDataListener = new MetaDataListener(registryRepository, schemaNames);
         propertiesChangedListener = new PropertiesChangedListener(registryRepository);
         authenticationChangedListener = new AuthenticationChangedListener(registryRepository);
+        privilegeNodeChangedListener = new PrivilegeNodeChangedListener(registryRepository);
     }
     
     /**
@@ -59,5 +62,6 @@ public final class RegistryListenerManager {
         metaDataListener.watch();
         propertiesChangedListener.watch(Type.UPDATED);
         authenticationChangedListener.watch(Type.UPDATED);
+        privilegeNodeChangedListener.watch(Type.UPDATED);
     }
 }
diff --git a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/event/GrantEvent.java
similarity index 60%
copy from shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java
copy to shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/event/GrantEvent.java
index 0909dc2..034a058 100644
--- a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java
+++ b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/event/GrantEvent.java
@@ -15,19 +15,20 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.infra.metadata.auth.refresher.type;
+package org.apache.shardingsphere.infra.metadata.auth.refresher.event;
 
-import org.apache.shardingsphere.infra.metadata.auth.Authentication;
-import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
-import org.apache.shardingsphere.infra.metadata.auth.refresher.AuthenticationRefresher;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.infra.metadata.auth.model.user.ShardingSphereUser;
+
+import java.util.Collection;
 
 /**
- * Grant statement auth refresher.
+ * Grant event.
  */
-public final class GrantStatementAuthRefresher implements AuthenticationRefresher {
+@RequiredArgsConstructor
+@Getter
+public final class GrantEvent {
     
-    @Override
-    public void refresh(final Authentication authentication, final SQLStatement sqlStatement, final ShardingSphereMetaData metaData) {
-    }
+    private final Collection<ShardingSphereUser> users;
 }
diff --git a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java
index 0909dc2..627cecb 100644
--- a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java
+++ b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/auth/refresher/type/GrantStatementAuthRefresher.java
@@ -17,10 +17,17 @@
 
 package org.apache.shardingsphere.infra.metadata.auth.refresher.type;
 
-import org.apache.shardingsphere.infra.metadata.auth.Authentication;
+import org.apache.shardingsphere.infra.eventbus.ShardingSphereEventBus;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import org.apache.shardingsphere.infra.metadata.auth.Authentication;
+import org.apache.shardingsphere.infra.metadata.auth.model.user.ShardingSphereUser;
 import org.apache.shardingsphere.infra.metadata.auth.refresher.AuthenticationRefresher;
+import org.apache.shardingsphere.infra.metadata.auth.refresher.event.GrantEvent;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dcl.MySQLGrantStatement;
+
+import java.util.Collection;
+import java.util.stream.Collectors;
 
 /**
  * Grant statement auth refresher.
@@ -29,5 +36,11 @@ public final class GrantStatementAuthRefresher implements AuthenticationRefreshe
     
     @Override
     public void refresh(final Authentication authentication, final SQLStatement sqlStatement, final ShardingSphereMetaData metaData) {
+        if (sqlStatement instanceof MySQLGrantStatement) {
+            Collection<ShardingSphereUser> users = ((MySQLGrantStatement) sqlStatement).getUsers().stream()
+                    .map(each -> new ShardingSphereUser(each.getUser(), each.getAuth(), each.getHost())).collect(Collectors.toList());
+            ShardingSphereEventBus.getInstance().post(new GrantEvent(users));
+        }
+        // TODO support other db
     }
 }