diff --git a/presto-main-base/src/main/java/com/facebook/presto/security/AccessControlManager.java b/presto-main-base/src/main/java/com/facebook/presto/security/AccessControlManager.java index f0fde936968db..16b7ba6267406 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/security/AccessControlManager.java +++ b/presto-main-base/src/main/java/com/facebook/presto/security/AccessControlManager.java @@ -95,6 +95,7 @@ public AccessControlManager(TransactionManager transactionManager) addSystemAccessControlFactory(new AllowAllSystemAccessControl.Factory()); addSystemAccessControlFactory(new ReadOnlySystemAccessControl.Factory()); addSystemAccessControlFactory(new FileBasedSystemAccessControl.Factory()); + addSystemAccessControlFactory(new DenyQueryIntegrityCheckSystemAccessControl.Factory()); } public void addSystemAccessControlFactory(SystemAccessControlFactory accessControlFactory) diff --git a/presto-main-base/src/main/java/com/facebook/presto/security/DenyQueryIntegrityCheckSystemAccessControl.java b/presto-main-base/src/main/java/com/facebook/presto/security/DenyQueryIntegrityCheckSystemAccessControl.java new file mode 100644 index 0000000000000..c5f019321b4f7 --- /dev/null +++ b/presto-main-base/src/main/java/com/facebook/presto/security/DenyQueryIntegrityCheckSystemAccessControl.java @@ -0,0 +1,101 @@ +/* + * Licensed 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.facebook.presto.security; + +import com.facebook.presto.common.QualifiedObjectName; +import com.facebook.presto.spi.CatalogSchemaTableName; +import com.facebook.presto.spi.MaterializedViewDefinition; +import com.facebook.presto.spi.analyzer.ViewDefinition; +import com.facebook.presto.spi.security.AccessControlContext; +import com.facebook.presto.spi.security.Identity; +import com.facebook.presto.spi.security.SystemAccessControl; +import com.facebook.presto.spi.security.SystemAccessControlFactory; + +import java.security.Principal; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static com.facebook.presto.spi.security.AccessDeniedException.denyQueryIntegrityCheck; +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +public class DenyQueryIntegrityCheckSystemAccessControl + implements SystemAccessControl +{ + public static final String NAME = "deny-query-integrity-check"; + + private static final DenyQueryIntegrityCheckSystemAccessControl INSTANCE = new DenyQueryIntegrityCheckSystemAccessControl(); + + public static class Factory + implements SystemAccessControlFactory + { + @Override + public String getName() + { + return NAME; + } + + @Override + public SystemAccessControl create(Map config) + { + requireNonNull(config, "config is null"); + checkArgument(config.isEmpty(), "This access controller does not support any configuration properties"); + return INSTANCE; + } + } + + @Override + public void checkQueryIntegrity(Identity identity, AccessControlContext context, String query, Map viewDefinitions, Map materializedViewDefinitions) + { + denyQueryIntegrityCheck(); + } + + @Override + public void checkCanSetUser(Identity identity, AccessControlContext context, Optional principal, String userName) + { + } + + @Override + public void checkCanSetSystemSessionProperty(Identity identity, AccessControlContext context, String propertyName) + { + } + + @Override + public void checkCanAccessCatalog(Identity identity, AccessControlContext context, String catalogName) + { + } + + @Override + public Set filterCatalogs(Identity identity, AccessControlContext context, Set catalogs) + { + return catalogs; + } + + @Override + public Set filterSchemas(Identity identity, AccessControlContext context, String catalogName, Set schemaNames) + { + return schemaNames; + } + + @Override + public void checkCanCreateTable(Identity identity, AccessControlContext context, CatalogSchemaTableName table) + { + } + + @Override + public void checkCanShowCreateTable(Identity identity, AccessControlContext context, CatalogSchemaTableName table) + { + } +} diff --git a/presto-main-base/src/main/java/com/facebook/presto/testing/TestingAccessControlManager.java b/presto-main-base/src/main/java/com/facebook/presto/testing/TestingAccessControlManager.java index dd932e971e923..ca16e92866171 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/testing/TestingAccessControlManager.java +++ b/presto-main-base/src/main/java/com/facebook/presto/testing/TestingAccessControlManager.java @@ -101,9 +101,16 @@ public class TestingAccessControlManager @Inject public TestingAccessControlManager(TransactionManager transactionManager) + { + this(transactionManager, true); + } + + public TestingAccessControlManager(TransactionManager transactionManager, boolean loadDefaultSystemAccessControl) { super(transactionManager); - setSystemAccessControl(AllowAllSystemAccessControl.NAME, ImmutableMap.of()); + if (loadDefaultSystemAccessControl) { + setSystemAccessControl(AllowAllSystemAccessControl.NAME, ImmutableMap.of()); + } } public static TestingPrivilege privilege(String entityName, TestingPrivilegeType type) diff --git a/presto-main-base/src/main/java/com/facebook/presto/testing/TestingPrestoServerModule.java b/presto-main-base/src/main/java/com/facebook/presto/testing/TestingPrestoServerModule.java new file mode 100644 index 0000000000000..a0139a22ac673 --- /dev/null +++ b/presto-main-base/src/main/java/com/facebook/presto/testing/TestingPrestoServerModule.java @@ -0,0 +1,63 @@ +/* + * Licensed 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.facebook.presto.testing; + +import com.facebook.presto.eventlistener.EventListenerConfig; +import com.facebook.presto.eventlistener.EventListenerManager; +import com.facebook.presto.security.AccessControlManager; +import com.facebook.presto.server.GracefulShutdownHandler; +import com.facebook.presto.server.security.PrestoAuthenticatorManager; +import com.facebook.presto.spi.security.AccessControl; +import com.facebook.presto.storage.TempStorageManager; +import com.facebook.presto.transaction.TransactionManager; +import com.google.inject.Binder; +import com.google.inject.Module; +import com.google.inject.Provides; +import com.google.inject.Scopes; +import com.google.inject.Singleton; + +import static java.util.Objects.requireNonNull; + +public class TestingPrestoServerModule + implements Module +{ + private final boolean loadDefaultSystemAccessControl; + + public TestingPrestoServerModule(boolean loadDefaultSystemAccessControl) + { + this.loadDefaultSystemAccessControl = loadDefaultSystemAccessControl; + } + + @Override + public void configure(Binder binder) + { + binder.bind(PrestoAuthenticatorManager.class).in(Scopes.SINGLETON); + binder.bind(TestingEventListenerManager.class).in(Scopes.SINGLETON); + binder.bind(TestingTempStorageManager.class).in(Scopes.SINGLETON); + binder.bind(EventListenerManager.class).to(TestingEventListenerManager.class).in(Scopes.SINGLETON); + binder.bind(EventListenerConfig.class).in(Scopes.SINGLETON); + binder.bind(TempStorageManager.class).to(TestingTempStorageManager.class).in(Scopes.SINGLETON); + binder.bind(AccessControl.class).to(AccessControlManager.class).in(Scopes.SINGLETON); + binder.bind(GracefulShutdownHandler.class).in(Scopes.SINGLETON); + binder.bind(ProcedureTester.class).in(Scopes.SINGLETON); + } + + @Provides + @Singleton + public AccessControlManager createAccessControlManager(TransactionManager transactionManager) + { + requireNonNull(transactionManager, "transactionManager is null"); + return new TestingAccessControlManager(transactionManager, loadDefaultSystemAccessControl); + } +} diff --git a/presto-main/src/main/java/com/facebook/presto/server/testing/TestingPrestoServer.java b/presto-main/src/main/java/com/facebook/presto/server/testing/TestingPrestoServer.java index cb0a4850a197c..3f19772431415 100644 --- a/presto-main/src/main/java/com/facebook/presto/server/testing/TestingPrestoServer.java +++ b/presto-main/src/main/java/com/facebook/presto/server/testing/TestingPrestoServer.java @@ -39,7 +39,6 @@ import com.facebook.presto.cost.StatsCalculator; import com.facebook.presto.dispatcher.DispatchManager; import com.facebook.presto.dispatcher.QueryPrerequisitesManagerModule; -import com.facebook.presto.eventlistener.EventListenerConfig; import com.facebook.presto.eventlistener.EventListenerManager; import com.facebook.presto.execution.QueryInfo; import com.facebook.presto.execution.QueryManager; @@ -74,7 +73,6 @@ import com.facebook.presto.spi.eventlistener.EventListener; import com.facebook.presto.spi.function.SqlFunction; import com.facebook.presto.spi.memory.ClusterMemoryPoolManager; -import com.facebook.presto.spi.security.AccessControl; import com.facebook.presto.split.PageSourceManager; import com.facebook.presto.split.SplitManager; import com.facebook.presto.sql.analyzer.FeaturesConfig; @@ -85,11 +83,10 @@ import com.facebook.presto.sql.planner.NodePartitioningManager; import com.facebook.presto.sql.planner.Plan; import com.facebook.presto.sql.planner.sanity.PlanCheckerProviderManager; -import com.facebook.presto.storage.TempStorageManager; import com.facebook.presto.testing.ProcedureTester; import com.facebook.presto.testing.TestingAccessControlManager; import com.facebook.presto.testing.TestingEventListenerManager; -import com.facebook.presto.testing.TestingTempStorageManager; +import com.facebook.presto.testing.TestingPrestoServerModule; import com.facebook.presto.testing.TestingWarningCollectorModule; import com.facebook.presto.transaction.TransactionManager; import com.facebook.presto.ttl.clusterttlprovidermanagers.ClusterTtlProviderManagerModule; @@ -289,6 +286,42 @@ public TestingPrestoServer( List additionalModules, Optional dataDirectory) throws Exception + { + this( + resourceManager, + resourceManagerEnabled, + catalogServer, + catalogServerEnabled, + coordinatorSidecar, + coordinatorSidecarEnabled, + coordinator, + skipLoadingResourceGroupConfigurationManager, + true, + properties, + environment, + discoveryUri, + parserOptions, + additionalModules, + dataDirectory); + } + + public TestingPrestoServer( + boolean resourceManager, + boolean resourceManagerEnabled, + boolean catalogServer, + boolean catalogServerEnabled, + boolean coordinatorSidecar, + boolean coordinatorSidecarEnabled, + boolean coordinator, + boolean skipLoadingResourceGroupConfigurationManager, + boolean loadDefaultSystemAccessControl, + Map properties, + String environment, + URI discoveryUri, + SqlParserOptions parserOptions, + List additionalModules, + Optional dataDirectory) + throws Exception { this.resourceManager = resourceManager; this.catalogServer = catalogServer; @@ -328,18 +361,9 @@ public TestingPrestoServer( .add(new NodeTtlFetcherManagerModule()) .add(new ClusterTtlProviderManagerModule()) .add(new ClientRequestFilterModule()) + .add(new TestingPrestoServerModule(loadDefaultSystemAccessControl)) .add(binder -> { - binder.bind(TestingAccessControlManager.class).in(Scopes.SINGLETON); - binder.bind(TestingEventListenerManager.class).in(Scopes.SINGLETON); - binder.bind(TestingTempStorageManager.class).in(Scopes.SINGLETON); - binder.bind(AccessControlManager.class).to(TestingAccessControlManager.class).in(Scopes.SINGLETON); - binder.bind(EventListenerManager.class).to(TestingEventListenerManager.class).in(Scopes.SINGLETON); - binder.bind(EventListenerConfig.class).in(Scopes.SINGLETON); - binder.bind(TempStorageManager.class).to(TestingTempStorageManager.class).in(Scopes.SINGLETON); - binder.bind(AccessControl.class).to(AccessControlManager.class).in(Scopes.SINGLETON); binder.bind(ShutdownAction.class).to(TestShutdownAction.class).in(Scopes.SINGLETON); - binder.bind(GracefulShutdownHandler.class).in(Scopes.SINGLETON); - binder.bind(ProcedureTester.class).in(Scopes.SINGLETON); binder.bind(RequestBlocker.class).in(Scopes.SINGLETON); newSetBinder(binder, Filter.class, TheServlet.class).addBinding() .to(RequestBlocker.class).in(Scopes.SINGLETON); @@ -385,7 +409,7 @@ public TestingPrestoServer( transactionManager = injector.getInstance(TransactionManager.class); sqlParser = injector.getInstance(SqlParser.class); metadata = injector.getInstance(Metadata.class); - accessControl = injector.getInstance(TestingAccessControlManager.class); + accessControl = (TestingAccessControlManager) injector.getInstance(AccessControlManager.class); procedureTester = injector.getInstance(ProcedureTester.class); splitManager = injector.getInstance(SplitManager.class); pageSourceManager = injector.getInstance(PageSourceManager.class); diff --git a/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java b/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java index 793247eb7a3c9..b9f88018332f8 100644 --- a/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java +++ b/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java @@ -31,6 +31,7 @@ import com.facebook.presto.metadata.InternalNode; import com.facebook.presto.metadata.Metadata; import com.facebook.presto.metadata.SessionPropertyManager; +import com.facebook.presto.security.AllowAllSystemAccessControl; import com.facebook.presto.server.BasicQueryInfo; import com.facebook.presto.server.testing.TestingPrestoServer; import com.facebook.presto.spi.ConnectorId; @@ -134,6 +135,8 @@ public class DistributedQueryRunner private final int resourceManagerCount; private final AtomicReference testFunctionNamespacesHandle = new AtomicReference<>(); + private final Map accessControlProperties; + @Deprecated public DistributedQueryRunner(Session defaultSession, int nodeCount) throws Exception @@ -163,7 +166,8 @@ public DistributedQueryRunner(Session defaultSession, int nodeCount, Map dataDirectory, Optional> externalWorkerLauncher, - List extraModules) + List extraModules, + Map accessControlProperties) throws Exception { requireNonNull(defaultSession, "defaultSession is null"); this.extraModules = requireNonNull(extraModules, "extraModules is null"); + this.accessControlProperties = requireNonNull(accessControlProperties, "accessControlProperties is null"); try { long start = nanoTime(); @@ -243,6 +249,7 @@ private DistributedQueryRunner( coordinatorSidecarEnabled, false, skipLoadingResourceGroupConfigurationManager, + false, workerProperties, parserOptions, environment, @@ -273,6 +280,7 @@ private DistributedQueryRunner( false, false, skipLoadingResourceGroupConfigurationManager, + false, rmProperties, parserOptions, environment, @@ -294,6 +302,7 @@ private DistributedQueryRunner( false, false, skipLoadingResourceGroupConfigurationManager, + false, catalogServerProperties, parserOptions, environment, @@ -313,6 +322,7 @@ private DistributedQueryRunner( true, false, skipLoadingResourceGroupConfigurationManager, + false, coordinatorSidecarProperties, parserOptions, environment, @@ -321,6 +331,8 @@ private DistributedQueryRunner( servers.add(coordinatorSidecar.get()); } + final boolean loadDefaultSystemAccessControl = !accessControlProperties.containsKey("access-control.name") || + accessControlProperties.get("access-control.name").equals("allow-all"); for (int i = 0; i < coordinatorCount; i++) { TestingPrestoServer coordinator = closer.register(createTestingPrestoServer( discoveryUrl, @@ -332,6 +344,7 @@ private DistributedQueryRunner( false, true, skipLoadingResourceGroupConfigurationManager, + loadDefaultSystemAccessControl, extraCoordinatorProperties, parserOptions, environment, @@ -464,6 +477,7 @@ private static TestingPrestoServer createTestingPrestoServer( boolean coordinatorSidecarEnabled, boolean coordinator, boolean skipLoadingResourceGroupConfigurationManager, + boolean loadDefaultSystemAccessControl, Map extraProperties, SqlParserOptions parserOptions, String environment, @@ -495,6 +509,7 @@ private static TestingPrestoServer createTestingPrestoServer( coordinatorSidecarEnabled, coordinator, skipLoadingResourceGroupConfigurationManager, + loadDefaultSystemAccessControl, properties, environment, discoveryUri, @@ -798,6 +813,15 @@ public void createTestFunctionNamespace(String catalogName, String schemaName) testFunctionNamespacesHandle.get().execute("INSERT INTO function_namespaces SELECT ?, ?", catalogName, schemaName); } + public void loadSystemAccessControl() + { + for (TestingPrestoServer server : servers) { + if (server.isCoordinator()) { + server.getAccessControl().loadSystemAccessControl(accessControlProperties); + } + } + } + private boolean isConnectorVisibleToAllNodes(ConnectorId connectorId) { if (!externalWorkers.isEmpty()) { @@ -1097,6 +1121,7 @@ public static class Builder private boolean skipLoadingResourceGroupConfigurationManager; private List extraModules = ImmutableList.of(); private int resourceManagerCount = 1; + private Map accessControlProperties = ImmutableMap.of("access-control.name", AllowAllSystemAccessControl.NAME); protected Builder(Session defaultSession) { @@ -1232,6 +1257,12 @@ public Builder setSkipLoadingResourceGroupConfigurationManager(boolean skipLoadi return this; } + public Builder setAccessControlProperties(Map accessControlProperties) + { + this.accessControlProperties = accessControlProperties; + return this; + } + public DistributedQueryRunner build() throws Exception { @@ -1253,7 +1284,8 @@ public DistributedQueryRunner build() environment, dataDirectory, externalWorkerLauncher, - extraModules); + extraModules, + accessControlProperties); } } } diff --git a/presto-tests/src/test/java/com/facebook/presto/tests/TestCheckAccessPermissionsForQueryTypes.java b/presto-tests/src/test/java/com/facebook/presto/tests/TestCheckAccessPermissionsForQueryTypes.java new file mode 100644 index 0000000000000..d1e16f45e90ab --- /dev/null +++ b/presto-tests/src/test/java/com/facebook/presto/tests/TestCheckAccessPermissionsForQueryTypes.java @@ -0,0 +1,57 @@ +/* + * Licensed 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.facebook.presto.tests; + +import com.facebook.presto.security.DenyQueryIntegrityCheckSystemAccessControl; +import com.facebook.presto.testing.QueryRunner; +import com.facebook.presto.tests.tpch.TpchQueryRunnerBuilder; +import com.google.common.collect.ImmutableMap; +import org.testng.annotations.Test; + +public class TestCheckAccessPermissionsForQueryTypes + extends AbstractTestQueryFramework +{ + @Override + protected QueryRunner createQueryRunner() + throws Exception + { + DistributedQueryRunner queryRunner = TpchQueryRunnerBuilder.builder() + .setAccessControlProperties(ImmutableMap.of("access-control.name", DenyQueryIntegrityCheckSystemAccessControl.NAME)).build(); + + queryRunner.loadSystemAccessControl(); + + return queryRunner; + } + + @Override + protected QueryRunner createExpectedQueryRunner() + throws Exception + { + QueryRunner queryRunner = TpchQueryRunnerBuilder.builder().build(); + return queryRunner; + } + + @Test + public void testCheckQueryIntegrityCalls() + { + assertAccessDenied("select * from orders", ".*Query integrity check failed.*"); + assertAccessDenied("analyze orders", ".*Query integrity check failed.*"); + assertAccessDenied("explain analyze orders", ".*Query integrity check failed.*"); + assertAccessDenied("explain select * from orders", ".*Query integrity check failed.*"); + assertAccessDenied("explain (type validate) select * from orders", ".*Query integrity check failed.*"); + assertQueryFails("CREATE TABLE test_empty (a BIGINT)", ".*This connector does not support creating tables.*"); + assertQuerySucceeds("use tpch.tiny"); + } +}