From 502086107ce39d112f06faa2dddbc51fdbbcbd2e Mon Sep 17 00:00:00 2001 From: panjuan Date: Sun, 21 Apr 2019 17:50:14 +0800 Subject: [PATCH] ShardingProxy supports multiple users and authorizedSchemas (#2237) * rename to UserChangedListenerTest * use AuthenticationChangedListenerTest * use UserYamlSwapperTest * modify authentication * Authentication changed event * Authentication changed listener * modify AUTHENTICATION_YAML * check style * check style * modify swap() * add AuthenticationYamlSwapperTest.java * use Authentication() * modify AUTHENTICATION_YAML * Authentication engine for MySQL. * login() * Authentication engine * modify unit cases in MySQLAuthenticationHandlerTest.java * setAuthentication() * use Authentication * modify javadoc * modify javadoc * modify loadServerConfiguration() * use authentication in loadServerConfiguration * modify unit cases * add user * add UserYamlSwapper * modify YamlAuthentication * use YamlUser * delete new YamlAuthentication() * add YamlUser.java * modify AUTHENTICATION_YAML content * use Collections * use Collections * modify config * use Collections * modify unit cases * prefer to use Collections * modify swap() * add isAuthorizedSchema() * isAuthorizedSchema() * add userName * modify assertMarshal() * getSchemaNames() * mock(BackendConnection.class) * new ShowDatabasesBackendHandler(backendConnection) * modify setUp() * modify setUp() * !authorizedSchemas.isEmpty() * trimResults() * isAuthorizedSchema() * modify isAuthorizedSchema() * isAuthorizedSchema(final String schema) * rename to ProxyUser * rename to ProxyUserYamlSwapperTest * modify examples * use ProxyUserYamlSwapperTest * use ProxyUser * use ProxyUser * Proxy user YAML swapper * rename to ProxyUserYamlSwapper * use ProxyUserYamlSwapper * ProxyUserYamlSwapperTest * USE YamlProxyUser * rename to YamlProxyUser * use YamlProxyUser * use YamlProxyUser * rename to YamlAuthenticationConfiguration * rename to YamlAuthenticationConfiguration * use YamlAuthenticationConfiguration * use YamlAuthenticationConfiguration * rename to YamlProxyUserConfiguration * use YamlProxyUserConfiguration * use YamlProxyUserConfiguration --- .../core/rule/Authentication.java | 7 +-- .../shardingsphere/core/rule/ProxyUser.java | 37 +++++++++++++ .../YamlAuthenticationConfiguration.java | 37 +++++++++++++ ...n.java => YamlProxyUserConfiguration.java} | 8 +-- .../impl/AuthenticationYamlSwapper.java | 38 ++++++++++---- .../swapper/impl/ProxyUserYamlSwapper.java | 52 +++++++++++++++++++ .../core/yaml/engine/YamlEngineTest.java | 20 +++---- .../core/yaml/swapper/AllSwapperTests.java | 4 +- ...est.java => ProxyUserYamlSwapperTest.java} | 27 +++++----- .../AuthenticationChangedListener.java | 4 +- .../config/service/ConfigurationService.java | 4 +- .../ShardingOrchestrationFacadeTest.java | 5 +- .../AuthenticationChangedListenerTest.java | 7 +-- .../service/ConfigurationServiceTest.java | 25 +++++---- .../jdbc/connection/BackendConnection.java | 3 ++ .../TextProtocolBackendHandlerFactory.java | 2 +- .../admin/ShowDatabasesBackendHandler.java | 21 +++++++- .../text/admin/UseDatabaseBackendHandler.java | 17 ++++-- .../ShowDatabasesBackendHandlerTest.java | 21 +++++++- .../admin/UseDatabaseBackendHandlerTest.java | 18 ++++++- .../shardingproxy/Bootstrap.java | 17 +++--- .../src/main/resources/conf/server.yaml | 13 +++-- .../config/ShardingConfigurationLoader.java | 3 +- .../yaml/YamlProxyServerConfiguration.java | 4 +- .../context/ShardingProxyContextTest.java | 23 +++++--- .../src/test/resources/conf/server.yaml | 8 +-- .../mysql/auth/MySQLAuthenticationEngine.java | 1 + .../admin/initdb/MySQLComInitDbExecutor.java | 10 +++- .../mysql/MySQLFrontendEngineTest.java | 16 +++--- .../handshake/MySQLAuthenticationHandler.java | 18 +++++-- .../MySQLAuthenticationHandlerTest.java | 10 ++-- 31 files changed, 371 insertions(+), 109 deletions(-) create mode 100644 sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/rule/ProxyUser.java create mode 100644 sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlAuthenticationConfiguration.java rename sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/{YamlAuthentication.java => YamlProxyUserConfiguration.java} (88%) create mode 100644 sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/swapper/impl/ProxyUserYamlSwapper.java rename sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/impl/{AuthenticationYamlSwapperTest.java => ProxyUserYamlSwapperTest.java} (58%) diff --git a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/rule/Authentication.java b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/rule/Authentication.java index fcce15c425833..d485f967cd8bd 100644 --- a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/rule/Authentication.java +++ b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/rule/Authentication.java @@ -20,6 +20,9 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; +import java.util.HashMap; +import java.util.Map; + /** * Authentication. * @@ -29,7 +32,5 @@ @Getter public final class Authentication { - private final String username; - - private final String password; + private Map users = new HashMap<>(); } diff --git a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/rule/ProxyUser.java b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/rule/ProxyUser.java new file mode 100644 index 0000000000000..d4e5b1dc07839 --- /dev/null +++ b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/rule/ProxyUser.java @@ -0,0 +1,37 @@ +/* + * 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.core.rule; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Collection; + +/** + * Proxy user. + * + * @author panjuan + */ +@RequiredArgsConstructor +@Getter +public final class ProxyUser { + + private final String password; + + private final Collection authorizedSchemas; +} diff --git a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlAuthenticationConfiguration.java b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlAuthenticationConfiguration.java new file mode 100644 index 0000000000000..adeaeef27f56d --- /dev/null +++ b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlAuthenticationConfiguration.java @@ -0,0 +1,37 @@ +/* + * 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.core.yaml.config.common; + +import lombok.Getter; +import lombok.Setter; +import org.apache.shardingsphere.core.yaml.config.YamlConfiguration; + +import java.util.HashMap; +import java.util.Map; + +/** + * Authentication configuration for YAML. + * + * @author panjuan + */ +@Getter +@Setter +public final class YamlAuthenticationConfiguration implements YamlConfiguration { + + private Map users = new HashMap<>(); +} diff --git a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlAuthentication.java b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlProxyUserConfiguration.java similarity index 88% rename from sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlAuthentication.java rename to sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlProxyUserConfiguration.java index ab0551fa850f2..299272b558a65 100644 --- a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlAuthentication.java +++ b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/config/common/YamlProxyUserConfiguration.java @@ -22,15 +22,15 @@ import org.apache.shardingsphere.core.yaml.config.YamlConfiguration; /** - * Authentication for YAML. + * Proxy user for YAML. * * @author zhangliang */ @Getter @Setter -public final class YamlAuthentication implements YamlConfiguration { - - private String username; +public final class YamlProxyUserConfiguration implements YamlConfiguration { private String password; + + private String authorizedSchemas; } diff --git a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/swapper/impl/AuthenticationYamlSwapper.java b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/swapper/impl/AuthenticationYamlSwapper.java index 31438a2f39202..fa06a1a0bdf13 100644 --- a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/swapper/impl/AuthenticationYamlSwapper.java +++ b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/swapper/impl/AuthenticationYamlSwapper.java @@ -17,10 +17,12 @@ package org.apache.shardingsphere.core.yaml.swapper.impl; -import com.google.common.base.Preconditions; -import com.google.common.base.Strings; +import com.google.common.base.Function; +import com.google.common.collect.Maps; import org.apache.shardingsphere.core.rule.Authentication; -import org.apache.shardingsphere.core.yaml.config.common.YamlAuthentication; +import org.apache.shardingsphere.core.rule.ProxyUser; +import org.apache.shardingsphere.core.yaml.config.common.YamlAuthenticationConfiguration; +import org.apache.shardingsphere.core.yaml.config.common.YamlProxyUserConfiguration; import org.apache.shardingsphere.core.yaml.swapper.YamlSwapper; /** @@ -28,19 +30,33 @@ * * @author zhangliang */ -public final class AuthenticationYamlSwapper implements YamlSwapper { +public final class AuthenticationYamlSwapper implements YamlSwapper { + + private final ProxyUserYamlSwapper proxyUserYamlSwapper = new ProxyUserYamlSwapper(); @Override - public YamlAuthentication swap(final Authentication data) { - YamlAuthentication result = new YamlAuthentication(); - result.setUsername(data.getUsername()); - result.setPassword(data.getPassword()); + public YamlAuthenticationConfiguration swap(final Authentication data) { + YamlAuthenticationConfiguration result = new YamlAuthenticationConfiguration(); + result.getUsers().putAll(Maps.transformValues(data.getUsers(), new Function() { + + @Override + public YamlProxyUserConfiguration apply(final ProxyUser input) { + return proxyUserYamlSwapper.swap(input); + } + })); return result; } @Override - public Authentication swap(final YamlAuthentication yamlConfiguration) { - Preconditions.checkArgument(!Strings.isNullOrEmpty(yamlConfiguration.getUsername()), "Username is required."); - return new Authentication(yamlConfiguration.getUsername(), yamlConfiguration.getPassword()); + public Authentication swap(final YamlAuthenticationConfiguration yamlConfiguration) { + Authentication result = new Authentication(); + result.getUsers().putAll(Maps.transformValues(yamlConfiguration.getUsers(), new Function() { + + @Override + public ProxyUser apply(final YamlProxyUserConfiguration input) { + return proxyUserYamlSwapper.swap(input); + } + })); + return result; } } diff --git a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/swapper/impl/ProxyUserYamlSwapper.java b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/swapper/impl/ProxyUserYamlSwapper.java new file mode 100644 index 0000000000000..52329f1f75e41 --- /dev/null +++ b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/yaml/swapper/impl/ProxyUserYamlSwapper.java @@ -0,0 +1,52 @@ +/* + * 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.core.yaml.swapper.impl; + +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import org.apache.shardingsphere.core.rule.ProxyUser; +import org.apache.shardingsphere.core.yaml.config.common.YamlProxyUserConfiguration; +import org.apache.shardingsphere.core.yaml.swapper.YamlSwapper; + +import java.util.Collections; + +/** + * Proxy user YAML swapper. + * + * @author zhangliang + */ +public final class ProxyUserYamlSwapper implements YamlSwapper { + + @Override + public YamlProxyUserConfiguration swap(final ProxyUser data) { + YamlProxyUserConfiguration result = new YamlProxyUserConfiguration(); + result.setPassword(data.getPassword()); + String authorizedSchemas = null == data.getAuthorizedSchemas() ? "" : Joiner.on(',').join(data.getAuthorizedSchemas()); + result.setAuthorizedSchemas(authorizedSchemas); + return result; + } + + @Override + public ProxyUser swap(final YamlProxyUserConfiguration yamlConfiguration) { + if (Strings.isNullOrEmpty(yamlConfiguration.getAuthorizedSchemas())) { + return new ProxyUser(yamlConfiguration.getPassword(), Collections.emptyList()); + } + return new ProxyUser(yamlConfiguration.getPassword(), Splitter.on(',').trimResults().splitToList(yamlConfiguration.getAuthorizedSchemas())); + } +} diff --git a/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/engine/YamlEngineTest.java b/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/engine/YamlEngineTest.java index 4fd8d3cc0eaf2..f041090e954c1 100644 --- a/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/engine/YamlEngineTest.java +++ b/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/engine/YamlEngineTest.java @@ -17,7 +17,7 @@ package org.apache.shardingsphere.core.yaml.engine; -import org.apache.shardingsphere.core.yaml.config.common.YamlAuthentication; +import org.apache.shardingsphere.core.yaml.config.common.YamlProxyUserConfiguration; import org.junit.Test; import java.util.Map; @@ -30,32 +30,32 @@ public final class YamlEngineTest { @Test public void assertUnmarshal() { - YamlAuthentication actual = YamlEngine.unmarshal("username: root\npassword: pwd", YamlAuthentication.class); - assertThat(actual.getUsername(), is("root")); + YamlProxyUserConfiguration actual = YamlEngine.unmarshal("password: pwd\nauthorizedSchemas: db1", YamlProxyUserConfiguration.class); assertThat(actual.getPassword(), is("pwd")); + assertThat(actual.getAuthorizedSchemas(), is("db1")); } @SuppressWarnings("unchecked") @Test public void assertUnmarshalMap() { - Map actual = (Map) YamlEngine.unmarshal("username: root\npassword: pwd"); - assertThat(actual.get("username").toString(), is("root")); + Map actual = (Map) YamlEngine.unmarshal("password: pwd\nauthorizedSchemas: db1"); assertThat(actual.get("password").toString(), is("pwd")); + assertThat(actual.get("authorizedSchemas").toString(), is("db1")); } @SuppressWarnings("unchecked") @Test public void assertUnmarshalProperties() { - Properties actual = YamlEngine.unmarshalProperties("username: root\npassword: pwd"); - assertThat(actual.getProperty("username"), is("root")); + Properties actual = YamlEngine.unmarshalProperties("password: pwd\nauthorizedSchemas: db1"); + assertThat(actual.getProperty("authorizedSchemas"), is("db1")); assertThat(actual.getProperty("password"), is("pwd")); } @Test public void assertMarshal() { - YamlAuthentication actual = new YamlAuthentication(); - actual.setUsername("root"); + YamlProxyUserConfiguration actual = new YamlProxyUserConfiguration(); actual.setPassword("pwd"); - assertThat(YamlEngine.marshal(actual), is("password: pwd\nusername: root\n")); + actual.setAuthorizedSchemas("db1"); + assertThat(YamlEngine.marshal(actual), is("authorizedSchemas: db1\npassword: pwd\n")); } } diff --git a/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/AllSwapperTests.java b/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/AllSwapperTests.java index 6129829633450..5a80c90d10200 100644 --- a/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/AllSwapperTests.java +++ b/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/AllSwapperTests.java @@ -17,10 +17,10 @@ package org.apache.shardingsphere.core.yaml.swapper; -import org.apache.shardingsphere.core.yaml.swapper.impl.AuthenticationYamlSwapperTest; import org.apache.shardingsphere.core.yaml.swapper.impl.EncryptorRuleConfigurationYamlSwapperTest; import org.apache.shardingsphere.core.yaml.swapper.impl.KeyGeneratorConfigurationYamlSwapperTest; import org.apache.shardingsphere.core.yaml.swapper.impl.MasterSlaveRuleConfigurationYamlSwapperTest; +import org.apache.shardingsphere.core.yaml.swapper.impl.ProxyUserYamlSwapperTest; import org.apache.shardingsphere.core.yaml.swapper.impl.ShardingRuleConfigurationYamlSwapperTest; import org.apache.shardingsphere.core.yaml.swapper.impl.ShardingStrategyConfigurationYamlSwapperTest; import org.apache.shardingsphere.core.yaml.swapper.impl.TableRuleConfigurationYamlSwapperTest; @@ -36,7 +36,7 @@ ShardingStrategyConfigurationYamlSwapperTest.class, KeyGeneratorConfigurationYamlSwapperTest.class, EncryptorRuleConfigurationYamlSwapperTest.class, - AuthenticationYamlSwapperTest.class + ProxyUserYamlSwapperTest.class }) public final class AllSwapperTests { } diff --git a/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/impl/AuthenticationYamlSwapperTest.java b/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/impl/ProxyUserYamlSwapperTest.java similarity index 58% rename from sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/impl/AuthenticationYamlSwapperTest.java rename to sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/impl/ProxyUserYamlSwapperTest.java index 03a7b8e085230..5c19020b28721 100644 --- a/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/impl/AuthenticationYamlSwapperTest.java +++ b/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/yaml/swapper/impl/ProxyUserYamlSwapperTest.java @@ -17,34 +17,31 @@ package org.apache.shardingsphere.core.yaml.swapper.impl; -import org.apache.shardingsphere.core.rule.Authentication; -import org.apache.shardingsphere.core.yaml.config.common.YamlAuthentication; +import org.apache.shardingsphere.core.rule.ProxyUser; +import org.apache.shardingsphere.core.yaml.config.common.YamlProxyUserConfiguration; import org.junit.Test; +import java.util.Collections; + import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; -public final class AuthenticationYamlSwapperTest { +public final class ProxyUserYamlSwapperTest { @Test public void assertSwapToYaml() { - YamlAuthentication actual = new AuthenticationYamlSwapper().swap(new Authentication("root", "pwd")); - assertThat(actual.getUsername(), is("root")); + YamlProxyUserConfiguration actual = new ProxyUserYamlSwapper().swap(new ProxyUser("pwd", Collections.singleton("db1"))); + assertThat(actual.getAuthorizedSchemas(), is("db1")); assertThat(actual.getPassword(), is("pwd")); } @Test public void assertSwapToObject() { - YamlAuthentication yamlAuthentication = new YamlAuthentication(); - yamlAuthentication.setUsername("root"); - yamlAuthentication.setPassword("pwd"); - Authentication actual = new AuthenticationYamlSwapper().swap(yamlAuthentication); - assertThat(actual.getUsername(), is("root")); + YamlProxyUserConfiguration yamlProxyUserConfiguration = new YamlProxyUserConfiguration(); + yamlProxyUserConfiguration.setAuthorizedSchemas("db1"); + yamlProxyUserConfiguration.setPassword("pwd"); + ProxyUser actual = new ProxyUserYamlSwapper().swap(yamlProxyUserConfiguration); + assertThat(actual.getAuthorizedSchemas().iterator().next(), is("db1")); assertThat(actual.getPassword(), is("pwd")); } - - @Test(expected = IllegalArgumentException.class) - public void assertSwapToObjectWithoutUsername() { - new AuthenticationYamlSwapper().swap(new YamlAuthentication()); - } } diff --git a/sharding-orchestration/sharding-orchestration-core/src/main/java/org/apache/shardingsphere/orchestration/internal/registry/config/listener/AuthenticationChangedListener.java b/sharding-orchestration/sharding-orchestration-core/src/main/java/org/apache/shardingsphere/orchestration/internal/registry/config/listener/AuthenticationChangedListener.java index 5d3422462faa2..9f02927013471 100644 --- a/sharding-orchestration/sharding-orchestration-core/src/main/java/org/apache/shardingsphere/orchestration/internal/registry/config/listener/AuthenticationChangedListener.java +++ b/sharding-orchestration/sharding-orchestration-core/src/main/java/org/apache/shardingsphere/orchestration/internal/registry/config/listener/AuthenticationChangedListener.java @@ -17,7 +17,7 @@ package org.apache.shardingsphere.orchestration.internal.registry.config.listener; -import org.apache.shardingsphere.core.yaml.config.common.YamlAuthentication; +import org.apache.shardingsphere.core.yaml.config.common.YamlAuthenticationConfiguration; import org.apache.shardingsphere.core.yaml.engine.YamlEngine; import org.apache.shardingsphere.core.yaml.swapper.impl.AuthenticationYamlSwapper; import org.apache.shardingsphere.orchestration.internal.registry.config.event.AuthenticationChangedEvent; @@ -39,6 +39,6 @@ public AuthenticationChangedListener(final String name, final RegistryCenter reg @Override protected AuthenticationChangedEvent createShardingOrchestrationEvent(final DataChangedEvent event) { - return new AuthenticationChangedEvent(new AuthenticationYamlSwapper().swap(YamlEngine.unmarshal(event.getValue(), YamlAuthentication.class))); + return new AuthenticationChangedEvent(new AuthenticationYamlSwapper().swap(YamlEngine.unmarshal(event.getValue(), YamlAuthenticationConfiguration.class))); } } diff --git a/sharding-orchestration/sharding-orchestration-core/src/main/java/org/apache/shardingsphere/orchestration/internal/registry/config/service/ConfigurationService.java b/sharding-orchestration/sharding-orchestration-core/src/main/java/org/apache/shardingsphere/orchestration/internal/registry/config/service/ConfigurationService.java index df04f9c087b96..3710a5aba0486 100644 --- a/sharding-orchestration/sharding-orchestration-core/src/main/java/org/apache/shardingsphere/orchestration/internal/registry/config/service/ConfigurationService.java +++ b/sharding-orchestration/sharding-orchestration-core/src/main/java/org/apache/shardingsphere/orchestration/internal/registry/config/service/ConfigurationService.java @@ -26,7 +26,7 @@ import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration; import org.apache.shardingsphere.core.config.DataSourceConfiguration; import org.apache.shardingsphere.core.rule.Authentication; -import org.apache.shardingsphere.core.yaml.config.common.YamlAuthentication; +import org.apache.shardingsphere.core.yaml.config.common.YamlAuthenticationConfiguration; import org.apache.shardingsphere.core.yaml.config.masterslave.YamlMasterSlaveRuleConfiguration; import org.apache.shardingsphere.core.yaml.config.sharding.YamlShardingRuleConfiguration; import org.apache.shardingsphere.core.yaml.engine.YamlEngine; @@ -211,7 +211,7 @@ public MasterSlaveRuleConfiguration loadMasterSlaveRuleConfiguration(final Strin * @return authentication */ public Authentication loadAuthentication() { - return new AuthenticationYamlSwapper().swap(YamlEngine.unmarshal(regCenter.getDirectly(configNode.getAuthenticationPath()), YamlAuthentication.class)); + return new AuthenticationYamlSwapper().swap(YamlEngine.unmarshal(regCenter.getDirectly(configNode.getAuthenticationPath()), YamlAuthenticationConfiguration.class)); } /** diff --git a/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/ShardingOrchestrationFacadeTest.java b/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/ShardingOrchestrationFacadeTest.java index a0907ca0eb710..592f62d8be311 100644 --- a/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/ShardingOrchestrationFacadeTest.java +++ b/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/ShardingOrchestrationFacadeTest.java @@ -20,6 +20,7 @@ import org.apache.shardingsphere.api.config.RuleConfiguration; import org.apache.shardingsphere.core.config.DataSourceConfiguration; import org.apache.shardingsphere.core.rule.Authentication; +import org.apache.shardingsphere.core.rule.ProxyUser; import org.apache.shardingsphere.orchestration.config.OrchestrationConfiguration; import org.apache.shardingsphere.orchestration.internal.registry.config.service.ConfigurationService; import org.apache.shardingsphere.orchestration.internal.registry.listener.ShardingOrchestrationListenerManager; @@ -73,7 +74,9 @@ public void setUp() { public void assertInitWithParameters() { Map dataSourceConfigurationMap = Collections.singletonMap("test_ds", mock(DataSourceConfiguration.class)); Map ruleConfigurationMap = Collections.singletonMap("sharding_db", mock(RuleConfiguration.class)); - Authentication authentication = new Authentication("root", "root"); + ProxyUser proxyUser = new ProxyUser("root", Collections.singleton("db1")); + Authentication authentication = new Authentication(); + authentication.getUsers().put("root", proxyUser); Properties props = new Properties(); shardingOrchestrationFacade.init(Collections.singletonMap("sharding_db", dataSourceConfigurationMap), ruleConfigurationMap, authentication, props); verify(configService).persistConfiguration("sharding_db", dataSourceConfigurationMap, ruleConfigurationMap.get("sharding_db"), authentication, props, true); diff --git a/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/config/listener/AuthenticationChangedListenerTest.java b/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/config/listener/AuthenticationChangedListenerTest.java index 75472c8a02b5d..47dd2dc20162a 100644 --- a/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/config/listener/AuthenticationChangedListenerTest.java +++ b/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/config/listener/AuthenticationChangedListenerTest.java @@ -32,7 +32,8 @@ @RunWith(MockitoJUnitRunner.class) public final class AuthenticationChangedListenerTest { - private static final String AUTHENTICATION_YAML = "password: root\nusername: root\n"; + private static final String AUTHENTICATION_YAML = " users:\n" + " root1:\n password: root1\n" + + " authorizedSchemas: sharding_db\n" + " root2:\n" + " password: root2\n" + " authorizedSchemas: sharding_db,ms_db"; private AuthenticationChangedListener authenticationChangedListener; @@ -46,7 +47,7 @@ public void setUp() { @Test public void assertCreateShardingOrchestrationEvent() { - assertThat( - authenticationChangedListener.createShardingOrchestrationEvent(new DataChangedEvent("test", AUTHENTICATION_YAML, ChangedType.UPDATED)).getAuthentication().getUsername(), is("root")); + assertThat(authenticationChangedListener.createShardingOrchestrationEvent( + new DataChangedEvent("test", AUTHENTICATION_YAML, ChangedType.UPDATED)).getAuthentication().getUsers().get("root1").getPassword(), is("root1")); } } diff --git a/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/config/service/ConfigurationServiceTest.java b/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/config/service/ConfigurationServiceTest.java index c70667536bbb5..18796559da9d0 100644 --- a/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/config/service/ConfigurationServiceTest.java +++ b/sharding-orchestration/sharding-orchestration-core/src/test/java/org/apache/shardingsphere/orchestration/internal/registry/config/service/ConfigurationServiceTest.java @@ -25,9 +25,11 @@ import org.apache.shardingsphere.core.config.DataSourceConfiguration; import org.apache.shardingsphere.core.constant.properties.ShardingPropertiesConstant; import org.apache.shardingsphere.core.rule.Authentication; +import org.apache.shardingsphere.core.yaml.config.common.YamlAuthenticationConfiguration; import org.apache.shardingsphere.core.yaml.config.masterslave.YamlMasterSlaveRuleConfiguration; import org.apache.shardingsphere.core.yaml.config.sharding.YamlShardingRuleConfiguration; import org.apache.shardingsphere.core.yaml.engine.YamlEngine; +import org.apache.shardingsphere.core.yaml.swapper.impl.AuthenticationYamlSwapper; import org.apache.shardingsphere.core.yaml.swapper.impl.MasterSlaveRuleConfigurationYamlSwapper; import org.apache.shardingsphere.core.yaml.swapper.impl.ShardingRuleConfigurationYamlSwapper; import org.apache.shardingsphere.orchestration.reg.api.RegistryCenter; @@ -77,7 +79,8 @@ public final class ConfigurationServiceTest { private static final String MASTER_SLAVE_RULE_YAML = "masterDataSourceName: master_ds\n" + "name: ms_ds\n" + "slaveDataSourceNames:\n" + "- slave_ds_0\n" + "- slave_ds_1\n"; - private static final String AUTHENTICATION_YAML = "password: root\n" + "username: root\n"; + private static final String AUTHENTICATION_YAML = "users:\n" + " root1:\n" + " authorizedSchemas: sharding_db\n" + " password: root1\n" + + " root2:\n" + " authorizedSchemas: sharding_db,ms_db\n" + " password: root2\n"; private static final String PROPS_YAML = "sql.show: false\n"; @@ -151,7 +154,7 @@ public void assertPersistConfigurationForShardingRuleWithAuthenticationAndIsNotO when(regCenter.get("/test/config/authentication")).thenReturn(AUTHENTICATION_YAML); when(regCenter.get("/test/config/props")).thenReturn(PROPS_YAML); ConfigurationService configurationService = new ConfigurationService("test", regCenter); - configurationService.persistConfiguration("sharding_db", createDataSourceConfigurations(), createShardingRuleConfiguration(), new Authentication("root", "root"), createProperties(), false); + configurationService.persistConfiguration("sharding_db", createDataSourceConfigurations(), createShardingRuleConfiguration(), createAuthentication(), createProperties(), false); verify(regCenter, times(0)).persist(eq("/test/config/schema/sharding_db/datasource"), ArgumentMatchers.any()); verify(regCenter, times(0)).persist("/test/config/schema/sharding_db/rule", SHARDING_RULE_YAML); verify(regCenter, times(0)).persist("/test/config/authentication", AUTHENTICATION_YAML); @@ -161,7 +164,7 @@ public void assertPersistConfigurationForShardingRuleWithAuthenticationAndIsNotO @Test public void assertPersistConfigurationForShardingRuleWithAuthenticationAndIsNotOverwriteAndConfigurationIsNotExisted() { ConfigurationService configurationService = new ConfigurationService("test", regCenter); - configurationService.persistConfiguration("sharding_db", createDataSourceConfigurations(), createShardingRuleConfiguration(), new Authentication("root", "root"), createProperties(), false); + configurationService.persistConfiguration("sharding_db", createDataSourceConfigurations(), createShardingRuleConfiguration(), createAuthentication(), createProperties(), false); verify(regCenter).persist(eq("/test/config/schema/sharding_db/datasource"), ArgumentMatchers.any()); verify(regCenter).persist("/test/config/schema/sharding_db/rule", SHARDING_RULE_YAML); verify(regCenter).persist("/test/config/authentication", AUTHENTICATION_YAML); @@ -171,7 +174,7 @@ public void assertPersistConfigurationForShardingRuleWithAuthenticationAndIsNotO @Test public void assertPersistConfigurationForShardingRuleWithAuthenticationAndIsOverwrite() { ConfigurationService configurationService = new ConfigurationService("test", regCenter); - configurationService.persistConfiguration("sharding_db", createDataSourceConfigurations(), createShardingRuleConfiguration(), new Authentication("root", "root"), createProperties(), true); + configurationService.persistConfiguration("sharding_db", createDataSourceConfigurations(), createShardingRuleConfiguration(), createAuthentication(), createProperties(), true); verify(regCenter).persist(eq("/test/config/schema/sharding_db/datasource"), ArgumentMatchers.any()); verify(regCenter).persist("/test/config/schema/sharding_db/rule", SHARDING_RULE_YAML); verify(regCenter).persist("/test/config/authentication", AUTHENTICATION_YAML); @@ -186,7 +189,7 @@ public void assertPersistConfigurationForMasterSlaveRuleWithAuthenticationAndIsN when(regCenter.get("/test/config/props")).thenReturn(PROPS_YAML); ConfigurationService configurationService = new ConfigurationService("test", regCenter); configurationService.persistConfiguration("sharding_db", - createDataSourceConfigurations(), createMasterSlaveRuleConfiguration(), new Authentication("root", "root"), createProperties(), false); + createDataSourceConfigurations(), createMasterSlaveRuleConfiguration(), createAuthentication(), createProperties(), false); verify(regCenter, times(0)).persist(eq("/test/config/schema/sharding_db/datasource"), ArgumentMatchers.any()); verify(regCenter, times(0)).persist("/test/config/schema/sharding_db/rule", MASTER_SLAVE_RULE_YAML); verify(regCenter, times(0)).persist("/test/config/authentication", AUTHENTICATION_YAML); @@ -197,7 +200,7 @@ public void assertPersistConfigurationForMasterSlaveRuleWithAuthenticationAndIsN public void assertPersistConfigurationForMasterSlaveRuleWithAuthenticationAndIsNotOverwriteAndConfigurationIsNotExisted() { ConfigurationService configurationService = new ConfigurationService("test", regCenter); configurationService.persistConfiguration("sharding_db", - createDataSourceConfigurations(), createMasterSlaveRuleConfiguration(), new Authentication("root", "root"), createProperties(), false); + createDataSourceConfigurations(), createMasterSlaveRuleConfiguration(), createAuthentication(), createProperties(), false); verify(regCenter).persist(eq("/test/config/schema/sharding_db/datasource"), ArgumentMatchers.any()); verify(regCenter).persist("/test/config/schema/sharding_db/rule", MASTER_SLAVE_RULE_YAML); verify(regCenter).persist("/test/config/authentication", AUTHENTICATION_YAML); @@ -208,7 +211,7 @@ public void assertPersistConfigurationForMasterSlaveRuleWithAuthenticationAndIsN public void assertPersistConfigurationForMasterSlaveRuleWithAuthenticationAndIsOverwrite() { ConfigurationService configurationService = new ConfigurationService("test", regCenter); configurationService.persistConfiguration("sharding_db", - createDataSourceConfigurations(), createMasterSlaveRuleConfiguration(), new Authentication("root", "root"), createProperties(), true); + createDataSourceConfigurations(), createMasterSlaveRuleConfiguration(), createAuthentication(), createProperties(), true); verify(regCenter).persist(eq("/test/config/schema/sharding_db/datasource"), ArgumentMatchers.any()); verify(regCenter).persist("/test/config/schema/sharding_db/rule", MASTER_SLAVE_RULE_YAML); verify(regCenter).persist("/test/config/authentication", AUTHENTICATION_YAML); @@ -253,6 +256,10 @@ private MasterSlaveRuleConfiguration createMasterSlaveRuleConfiguration() { return new MasterSlaveRuleConfigurationYamlSwapper().swap(YamlEngine.unmarshal(MASTER_SLAVE_RULE_YAML, YamlMasterSlaveRuleConfiguration.class)); } + private Authentication createAuthentication() { + return new AuthenticationYamlSwapper().swap(YamlEngine.unmarshal(AUTHENTICATION_YAML, YamlAuthenticationConfiguration.class)); + } + private Properties createProperties() { Properties result = new Properties(); result.put(ShardingPropertiesConstant.SQL_SHOW.getKey(), Boolean.FALSE); @@ -312,8 +319,8 @@ public void assertLoadAuthentication() { when(regCenter.getDirectly("/test/config/authentication")).thenReturn(AUTHENTICATION_YAML); ConfigurationService configurationService = new ConfigurationService("test", regCenter); Authentication actual = configurationService.loadAuthentication(); - assertThat(actual.getUsername(), is("root")); - assertThat(actual.getPassword(), is("root")); + assertThat(actual.getUsers().size(), is(2)); + assertThat(actual.getUsers().get("root1").getPassword(), is("root1")); } @Test diff --git a/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/communication/jdbc/connection/BackendConnection.java b/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/communication/jdbc/connection/BackendConnection.java index d77dbbcad2899..47b75895bce1f 100644 --- a/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/communication/jdbc/connection/BackendConnection.java +++ b/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/communication/jdbc/connection/BackendConnection.java @@ -62,6 +62,9 @@ public final class BackendConnection implements AutoCloseable { @Setter private int connectionId; + @Setter + private String userName; + private final Multimap cachedConnections = LinkedHashMultimap.create(); private final Collection cachedStatements = new CopyOnWriteArrayList<>(); diff --git a/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/TextProtocolBackendHandlerFactory.java b/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/TextProtocolBackendHandlerFactory.java index 98485cf40e885..af62e8b4b3997 100644 --- a/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/TextProtocolBackendHandlerFactory.java +++ b/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/TextProtocolBackendHandlerFactory.java @@ -85,7 +85,7 @@ private static TextProtocolBackendHandler createDALBackendHandler(final SQLState return new UseDatabaseBackendHandler((UseStatement) sqlStatement, backendConnection); } if (sqlStatement instanceof ShowDatabasesStatement) { - return new ShowDatabasesBackendHandler(); + return new ShowDatabasesBackendHandler(backendConnection); } return new UnicastBackendHandler(sql, backendConnection); } diff --git a/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/ShowDatabasesBackendHandler.java b/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/ShowDatabasesBackendHandler.java index 7f1a3b10bacc0..d1db13b65395a 100644 --- a/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/ShowDatabasesBackendHandler.java +++ b/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/ShowDatabasesBackendHandler.java @@ -17,35 +17,54 @@ package org.apache.shardingsphere.shardingproxy.backend.text.admin; +import lombok.RequiredArgsConstructor; import org.apache.shardingsphere.core.merge.MergedResult; import org.apache.shardingsphere.core.merge.dal.show.ShowDatabasesMergedResult; +import org.apache.shardingsphere.shardingproxy.backend.communication.jdbc.connection.BackendConnection; import org.apache.shardingsphere.shardingproxy.backend.response.BackendResponse; import org.apache.shardingsphere.shardingproxy.backend.response.query.QueryData; import org.apache.shardingsphere.shardingproxy.backend.response.query.QueryHeader; import org.apache.shardingsphere.shardingproxy.backend.response.query.QueryResponse; import org.apache.shardingsphere.shardingproxy.backend.schema.LogicSchemas; import org.apache.shardingsphere.shardingproxy.backend.text.TextProtocolBackendHandler; +import org.apache.shardingsphere.shardingproxy.context.ShardingProxyContext; import java.sql.SQLException; import java.sql.Types; +import java.util.Collection; import java.util.Collections; +import java.util.LinkedList; +import java.util.List; /** * Show databases backend handler. * * @author chenqingyang * @author zhaojun + * @author panjuan */ +@RequiredArgsConstructor public final class ShowDatabasesBackendHandler implements TextProtocolBackendHandler { + private final BackendConnection backendConnection; + private MergedResult mergedResult; @Override public BackendResponse execute() { - mergedResult = new ShowDatabasesMergedResult(LogicSchemas.getInstance().getSchemaNames()); + mergedResult = new ShowDatabasesMergedResult(getSchemaNames()); return new QueryResponse(Collections.singletonList(new QueryHeader("information_schema", "SCHEMATA", "Database", "SCHEMA_NAME", 100, Types.VARCHAR, 0))); } + private List getSchemaNames() { + List result = new LinkedList<>(LogicSchemas.getInstance().getSchemaNames()); + Collection authorizedSchemas = ShardingProxyContext.getInstance().getAuthentication().getUsers().get(backendConnection.getUserName()).getAuthorizedSchemas(); + if (!authorizedSchemas.isEmpty()) { + result.retainAll(authorizedSchemas); + } + return result; + } + @Override public boolean next() throws SQLException { return null != mergedResult && mergedResult.next(); diff --git a/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/UseDatabaseBackendHandler.java b/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/UseDatabaseBackendHandler.java index b8bb0a72ccb11..9ba60fcc06b78 100644 --- a/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/UseDatabaseBackendHandler.java +++ b/sharding-proxy/sharding-proxy-backend/src/main/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/UseDatabaseBackendHandler.java @@ -28,6 +28,9 @@ import org.apache.shardingsphere.shardingproxy.backend.response.update.UpdateResponse; import org.apache.shardingsphere.shardingproxy.backend.schema.LogicSchemas; import org.apache.shardingsphere.shardingproxy.backend.text.TextProtocolBackendHandler; +import org.apache.shardingsphere.shardingproxy.context.ShardingProxyContext; + +import java.util.Collection; /** * Use database backend handler. @@ -45,11 +48,17 @@ public final class UseDatabaseBackendHandler implements TextProtocolBackendHandl @Override public BackendResponse execute() { String schema = SQLUtil.getExactlyValue(useStatement.getSchema()); - if (!LogicSchemas.getInstance().schemaExists(schema)) { - return new ErrorResponse(new UnknownDatabaseException(schema)); + if (LogicSchemas.getInstance().schemaExists(schema) && isAuthorizedSchema(schema)) { + backendConnection.setCurrentSchema(schema); + return new UpdateResponse(); } - backendConnection.setCurrentSchema(schema); - return new UpdateResponse(); + return new ErrorResponse(new UnknownDatabaseException(schema)); + + } + + private boolean isAuthorizedSchema(final String schema) { + Collection authorizedSchemas = ShardingProxyContext.getInstance().getAuthentication().getUsers().get(backendConnection.getUserName()).getAuthorizedSchemas(); + return authorizedSchemas.isEmpty() || authorizedSchemas.contains(schema); } @Override diff --git a/sharding-proxy/sharding-proxy-backend/src/test/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/ShowDatabasesBackendHandlerTest.java b/sharding-proxy/sharding-proxy-backend/src/test/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/ShowDatabasesBackendHandlerTest.java index 02d58a249323d..df691ee8e1cd3 100644 --- a/sharding-proxy/sharding-proxy-backend/src/test/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/ShowDatabasesBackendHandlerTest.java +++ b/sharding-proxy/sharding-proxy-backend/src/test/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/ShowDatabasesBackendHandlerTest.java @@ -17,9 +17,13 @@ package org.apache.shardingsphere.shardingproxy.backend.text.admin; +import org.apache.shardingsphere.core.rule.Authentication; +import org.apache.shardingsphere.core.rule.ProxyUser; import org.apache.shardingsphere.shardingproxy.backend.MockLogicSchemasUtil; +import org.apache.shardingsphere.shardingproxy.backend.communication.jdbc.connection.BackendConnection; import org.apache.shardingsphere.shardingproxy.backend.response.query.QueryData; import org.apache.shardingsphere.shardingproxy.backend.response.query.QueryResponse; +import org.apache.shardingsphere.shardingproxy.context.ShardingProxyContext; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -27,19 +31,34 @@ import java.sql.SQLException; import java.sql.Types; +import java.util.Arrays; +import java.util.Properties; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public final class ShowDatabasesBackendHandlerTest { - private ShowDatabasesBackendHandler showDatabasesBackendHandler = new ShowDatabasesBackendHandler(); + private ShowDatabasesBackendHandler showDatabasesBackendHandler; @Before public void setUp() { MockLogicSchemasUtil.setLogicSchemas("schema", 5); + BackendConnection backendConnection = mock(BackendConnection.class); + when(backendConnection.getUserName()).thenReturn("root"); + ShardingProxyContext.getInstance().init(getAuthentication(), new Properties()); + showDatabasesBackendHandler = new ShowDatabasesBackendHandler(backendConnection); + } + + private Authentication getAuthentication() { + ProxyUser proxyUser = new ProxyUser("root", Arrays.asList("schema_0", "schema_1")); + Authentication result = new Authentication(); + result.getUsers().put("root", proxyUser); + return result; } @Test diff --git a/sharding-proxy/sharding-proxy-backend/src/test/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/UseDatabaseBackendHandlerTest.java b/sharding-proxy/sharding-proxy-backend/src/test/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/UseDatabaseBackendHandlerTest.java index fb5ed7d310b37..78ad6c50e1bdc 100644 --- a/sharding-proxy/sharding-proxy-backend/src/test/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/UseDatabaseBackendHandlerTest.java +++ b/sharding-proxy/sharding-proxy-backend/src/test/java/org/apache/shardingsphere/shardingproxy/backend/text/admin/UseDatabaseBackendHandlerTest.java @@ -18,17 +18,22 @@ package org.apache.shardingsphere.shardingproxy.backend.text.admin; import org.apache.shardingsphere.core.parse.old.parser.dialect.mysql.statement.UseStatement; +import org.apache.shardingsphere.core.rule.Authentication; +import org.apache.shardingsphere.core.rule.ProxyUser; import org.apache.shardingsphere.shardingproxy.backend.MockLogicSchemasUtil; import org.apache.shardingsphere.shardingproxy.backend.communication.jdbc.connection.BackendConnection; import org.apache.shardingsphere.shardingproxy.backend.response.BackendResponse; import org.apache.shardingsphere.shardingproxy.backend.response.error.ErrorResponse; import org.apache.shardingsphere.shardingproxy.backend.response.update.UpdateResponse; +import org.apache.shardingsphere.shardingproxy.context.ShardingProxyContext; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import java.util.Arrays; +import java.util.Properties; + import static org.hamcrest.CoreMatchers.instanceOf; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.anyString; @@ -40,12 +45,21 @@ @RunWith(MockitoJUnitRunner.class) public final class UseDatabaseBackendHandlerTest { - @Mock private BackendConnection backendConnection; @Before public void setUp() { MockLogicSchemasUtil.setLogicSchemas("schema", 10); + backendConnection = mock(BackendConnection.class); + when(backendConnection.getUserName()).thenReturn("root"); + ShardingProxyContext.getInstance().init(getAuthentication(), new Properties()); + } + + private Authentication getAuthentication() { + ProxyUser proxyUser = new ProxyUser("root", Arrays.asList("schema_0", "schema_1")); + Authentication result = new Authentication(); + result.getUsers().put("root", proxyUser); + return result; } @Test diff --git a/sharding-proxy/sharding-proxy-bootstrap/src/main/java/org/apache/shardingsphere/shardingproxy/Bootstrap.java b/sharding-proxy/sharding-proxy-bootstrap/src/main/java/org/apache/shardingsphere/shardingproxy/Bootstrap.java index 41bc8e444ed85..468ca55cf3737 100644 --- a/sharding-proxy/sharding-proxy-bootstrap/src/main/java/org/apache/shardingsphere/shardingproxy/Bootstrap.java +++ b/sharding-proxy/sharding-proxy-bootstrap/src/main/java/org/apache/shardingsphere/shardingproxy/Bootstrap.java @@ -23,6 +23,8 @@ import org.apache.shardingsphere.core.config.DataSourceConfiguration; import org.apache.shardingsphere.core.constant.properties.ShardingPropertiesConstant; import org.apache.shardingsphere.core.rule.Authentication; +import org.apache.shardingsphere.core.yaml.config.common.YamlAuthenticationConfiguration; +import org.apache.shardingsphere.core.yaml.swapper.impl.AuthenticationYamlSwapper; import org.apache.shardingsphere.core.yaml.swapper.impl.MasterSlaveRuleConfigurationYamlSwapper; import org.apache.shardingsphere.core.yaml.swapper.impl.ShardingRuleConfigurationYamlSwapper; import org.apache.shardingsphere.opentracing.ShardingTracer; @@ -68,9 +70,7 @@ public static void main(final String[] args) throws IOException { ShardingConfiguration shardingConfig = new ShardingConfigurationLoader().load(); int port = getPort(args); if (null == shardingConfig.getServerConfiguration().getOrchestration()) { - startWithoutRegistryCenter(shardingConfig.getRuleConfigurationMap(), - new Authentication(shardingConfig.getServerConfiguration().getAuthentication().getUsername(), shardingConfig.getServerConfiguration().getAuthentication().getPassword()), - shardingConfig.getServerConfiguration().getProps(), port); + startWithoutRegistryCenter(shardingConfig.getRuleConfigurationMap(), shardingConfig.getServerConfiguration().getAuthentication(), shardingConfig.getServerConfiguration().getProps(), port); } else { startWithRegistryCenter(shardingConfig.getServerConfiguration(), shardingConfig.getRuleConfigurationMap().keySet(), shardingConfig.getRuleConfigurationMap(), port); } @@ -87,8 +87,9 @@ private static int getPort(final String[] args) { } } - private static void startWithoutRegistryCenter(final Map ruleConfigs, final Authentication authentication, final Properties prop, final int port) { - ShardingProxyContext.getInstance().init(authentication, prop); + private static void startWithoutRegistryCenter(final Map ruleConfigs, + final YamlAuthenticationConfiguration authentication, final Properties prop, final int port) { + ShardingProxyContext.getInstance().init(getAuthentication(authentication), prop); LogicSchemas.getInstance().init(getDataSourceParameterMap(ruleConfigs), getRuleConfiguration(ruleConfigs)); initOpenTracing(); ShardingProxy.getInstance().start(port); @@ -132,7 +133,7 @@ private static void initShardingOrchestrationFacade( shardingOrchestrationFacade.init(); } else { shardingOrchestrationFacade.init(getDataSourceConfigurationMap(ruleConfigs), - getRuleConfiguration(ruleConfigs), new Authentication(serverConfig.getAuthentication().getUsername(), serverConfig.getAuthentication().getPassword()), serverConfig.getProps()); + getRuleConfiguration(ruleConfigs), getAuthentication(serverConfig.getAuthentication()), serverConfig.getProps()); } } @@ -169,4 +170,8 @@ private static Map getRuleConfiguration(final Map execute() { - if (LogicSchemas.getInstance().schemaExists(packet.getSchema())) { + String schema = SQLUtil.getExactlyValue(packet.getSchema()); + if (LogicSchemas.getInstance().schemaExists(schema) && isAuthorizedSchema(schema)) { backendConnection.setCurrentSchema(packet.getSchema()); return Collections.singletonList(new MySQLOKPacket(1)); } return Collections.singletonList(new MySQLErrPacket(1, MySQLServerErrorCode.ER_BAD_DB_ERROR, packet.getSchema())); } + + private boolean isAuthorizedSchema(final String schema) { + Collection authorizedSchemas = ShardingProxyContext.getInstance().getAuthentication().getUsers().get(backendConnection.getUserName()).getAuthorizedSchemas(); + return authorizedSchemas.isEmpty() || authorizedSchemas.contains(schema); + } } diff --git a/sharding-proxy/sharding-proxy-frontend/sharding-proxy-frontend-mysql/src/test/java/org/apache/shardingsphere/shardingproxy/frontend/mysql/MySQLFrontendEngineTest.java b/sharding-proxy/sharding-proxy-frontend/sharding-proxy-frontend-mysql/src/test/java/org/apache/shardingsphere/shardingproxy/frontend/mysql/MySQLFrontendEngineTest.java index e41bd2ff6fd7d..6f908dcf672d3 100644 --- a/sharding-proxy/sharding-proxy-frontend/sharding-proxy-frontend-mysql/src/test/java/org/apache/shardingsphere/shardingproxy/frontend/mysql/MySQLFrontendEngineTest.java +++ b/sharding-proxy/sharding-proxy-frontend/sharding-proxy-frontend-mysql/src/test/java/org/apache/shardingsphere/shardingproxy/frontend/mysql/MySQLFrontendEngineTest.java @@ -20,6 +20,7 @@ import io.netty.channel.ChannelHandlerContext; import lombok.SneakyThrows; import org.apache.shardingsphere.core.rule.Authentication; +import org.apache.shardingsphere.core.rule.ProxyUser; import org.apache.shardingsphere.shardingproxy.backend.communication.jdbc.connection.BackendConnection; import org.apache.shardingsphere.shardingproxy.context.ShardingProxyContext; import org.apache.shardingsphere.shardingproxy.frontend.ConnectionIdGenerator; @@ -34,6 +35,7 @@ import org.mockito.junit.MockitoJUnitRunner; import java.lang.reflect.Field; +import java.util.Collections; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.isA; @@ -69,8 +71,8 @@ public void assertHandshake() { @Test public void assertAuthWhenLoginSuccess() { - Authentication authentication = new Authentication("root", ""); - setAuthentication(authentication); + ProxyUser proxyUser = new ProxyUser("", Collections.singleton("db1")); + setAuthentication(proxyUser); when(payload.readStringNul()).thenReturn("root"); assertTrue(mysqlFrontendEngine.getAuthEngine().auth(context, payload, mock(BackendConnection.class))); verify(context).writeAndFlush(isA(MySQLOKPacket.class)); @@ -78,8 +80,8 @@ public void assertAuthWhenLoginSuccess() { @Test public void assertAuthWhenLoginFailure() { - Authentication authentication = new Authentication("root", "error"); - setAuthentication(authentication); + ProxyUser proxyUser = new ProxyUser("error", Collections.singleton("db1")); + setAuthentication(proxyUser); when(payload.readStringNul()).thenReturn("root"); when(payload.readStringNulByBytes()).thenReturn("root".getBytes()); assertTrue(mysqlFrontendEngine.getAuthEngine().auth(context, payload, mock(BackendConnection.class))); @@ -87,9 +89,11 @@ public void assertAuthWhenLoginFailure() { } @SneakyThrows - private void setAuthentication(final Object value) { + private void setAuthentication(final ProxyUser proxyUser) { + Authentication authentication = new Authentication(); + authentication.getUsers().put("root", proxyUser); Field field = ShardingProxyContext.class.getDeclaredField("authentication"); field.setAccessible(true); - field.set(ShardingProxyContext.getInstance(), value); + field.set(ShardingProxyContext.getInstance(), authentication); } } diff --git a/sharding-proxy/sharding-proxy-transport/sharding-proxy-transport-mysql/src/main/java/org/apache/shardingsphere/shardingproxy/transport/mysql/packet/handshake/MySQLAuthenticationHandler.java b/sharding-proxy/sharding-proxy-transport/sharding-proxy-transport-mysql/src/main/java/org/apache/shardingsphere/shardingproxy/transport/mysql/packet/handshake/MySQLAuthenticationHandler.java index f87cc74b900fa..b6584ca97bdb4 100644 --- a/sharding-proxy/sharding-proxy-transport/sharding-proxy-transport-mysql/src/main/java/org/apache/shardingsphere/shardingproxy/transport/mysql/packet/handshake/MySQLAuthenticationHandler.java +++ b/sharding-proxy/sharding-proxy-transport/sharding-proxy-transport-mysql/src/main/java/org/apache/shardingsphere/shardingproxy/transport/mysql/packet/handshake/MySQLAuthenticationHandler.java @@ -17,13 +17,15 @@ package org.apache.shardingsphere.shardingproxy.transport.mysql.packet.handshake; +import com.google.common.base.Optional; import com.google.common.base.Strings; import lombok.Getter; import org.apache.commons.codec.digest.DigestUtils; -import org.apache.shardingsphere.core.rule.Authentication; +import org.apache.shardingsphere.core.rule.ProxyUser; import org.apache.shardingsphere.shardingproxy.context.ShardingProxyContext; import java.util.Arrays; +import java.util.Map.Entry; /** * Authentication handler for MySQL. @@ -45,11 +47,17 @@ public final class MySQLAuthenticationHandler { * @return login success or failure */ public boolean login(final String username, final byte[] authResponse) { - Authentication authentication = SHARDING_PROXY_CONTEXT.getAuthentication(); - if (Strings.isNullOrEmpty(authentication.getPassword())) { - return authentication.getUsername().equals(username); + Optional user = getUser(username); + return user.isPresent() && (Strings.isNullOrEmpty(user.get().getPassword()) || Arrays.equals(getAuthCipherBytes(user.get().getPassword()), authResponse)); + } + + private Optional getUser(final String username) { + for (Entry entry : SHARDING_PROXY_CONTEXT.getAuthentication().getUsers().entrySet()) { + if (entry.getKey().equals(username)) { + return Optional.of(entry.getValue()); + } } - return authentication.getUsername().equals(username) && Arrays.equals(getAuthCipherBytes(authentication.getPassword()), authResponse); + return Optional.absent(); } private byte[] getAuthCipherBytes(final String password) { diff --git a/sharding-proxy/sharding-proxy-transport/sharding-proxy-transport-mysql/src/test/java/org/apache/shardingsphere/shardingproxy/transport/mysql/packet/handshake/MySQLAuthenticationHandlerTest.java b/sharding-proxy/sharding-proxy-transport/sharding-proxy-transport-mysql/src/test/java/org/apache/shardingsphere/shardingproxy/transport/mysql/packet/handshake/MySQLAuthenticationHandlerTest.java index e3fcfa03cb81f..d41eb8a37bf3f 100644 --- a/sharding-proxy/sharding-proxy-transport/sharding-proxy-transport-mysql/src/test/java/org/apache/shardingsphere/shardingproxy/transport/mysql/packet/handshake/MySQLAuthenticationHandlerTest.java +++ b/sharding-proxy/sharding-proxy-transport/sharding-proxy-transport-mysql/src/test/java/org/apache/shardingsphere/shardingproxy/transport/mysql/packet/handshake/MySQLAuthenticationHandlerTest.java @@ -20,11 +20,13 @@ import com.google.common.primitives.Bytes; import lombok.SneakyThrows; import org.apache.shardingsphere.core.rule.Authentication; +import org.apache.shardingsphere.core.rule.ProxyUser; import org.apache.shardingsphere.shardingproxy.context.ShardingProxyContext; import org.junit.Before; import org.junit.Test; import java.lang.reflect.Field; +import java.util.Collections; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @@ -53,20 +55,22 @@ private void initAuthPluginDataForAuthenticationHandler() { @Test public void assertLoginWithPassword() { - setAuthentication(new Authentication("root", "root")); + setAuthentication(new ProxyUser("root", Collections.singleton("db1"))); byte[] authResponse = {-27, 89, -20, -27, 65, -120, -64, -101, 86, -100, -108, -100, 6, -125, -37, 117, 14, -43, 95, -113}; assertTrue(authenticationHandler.login("root", authResponse)); } @Test public void assertLoginWithoutPassword() { - setAuthentication(new Authentication("root", null)); + setAuthentication(new ProxyUser(null, null)); byte[] authResponse = {-27, 89, -20, -27, 65, -120, -64, -101, 86, -100, -108, -100, 6, -125, -37, 117, 14, -43, 95, -113}; assertTrue(authenticationHandler.login("root", authResponse)); } @SneakyThrows - private void setAuthentication(final Authentication authentication) { + private void setAuthentication(final ProxyUser proxyUser) { + Authentication authentication = new Authentication(); + authentication.getUsers().put("root", proxyUser); Field field = ShardingProxyContext.class.getDeclaredField("authentication"); field.setAccessible(true); field.set(ShardingProxyContext.getInstance(), authentication);