/* * 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.connector.ConnectorId; import com.facebook.presto.connector.informationSchema.InformationSchemaConnector; import com.facebook.presto.connector.system.SystemConnector; import com.facebook.presto.metadata.Catalog; import com.facebook.presto.metadata.CatalogManager; import com.facebook.presto.metadata.InMemoryNodeManager; import com.facebook.presto.metadata.MetadataManager; import com.facebook.presto.metadata.QualifiedObjectName; import com.facebook.presto.spi.CatalogSchemaName; import com.facebook.presto.spi.CatalogSchemaTableName; import com.facebook.presto.spi.PrestoException; import com.facebook.presto.spi.SchemaTableName; import com.facebook.presto.spi.connector.Connector; import com.facebook.presto.spi.connector.ConnectorAccessControl; import com.facebook.presto.spi.connector.ConnectorTransactionHandle; import com.facebook.presto.spi.security.AccessDeniedException; import com.facebook.presto.spi.security.Identity; import com.facebook.presto.spi.security.Privilege; import com.facebook.presto.spi.security.SystemAccessControl; import com.facebook.presto.spi.security.SystemAccessControlFactory; import com.facebook.presto.testing.TestingConnectorContext; import com.facebook.presto.tpch.TpchConnectorFactory; import com.facebook.presto.transaction.TransactionManager; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.testng.annotations.Test; import java.security.Principal; import java.util.Map; import java.util.Optional; import java.util.Set; import static com.facebook.presto.connector.ConnectorId.createInformationSchemaConnectorId; import static com.facebook.presto.connector.ConnectorId.createSystemTablesConnectorId; import static com.facebook.presto.spi.security.AccessDeniedException.denySelectTable; import static com.facebook.presto.transaction.TransactionBuilder.transaction; import static com.facebook.presto.transaction.TransactionManager.createTestTransactionManager; import static java.util.Objects.requireNonNull; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; public class TestAccessControlManager { private static final Principal PRINCIPAL = new TestingPrincipal("principal"); private static final String USER_NAME = "user_name"; @Test(expectedExceptions = PrestoException.class, expectedExceptionsMessageRegExp = "Presto server is still initializing") public void testInitializing() throws Exception { AccessControlManager accessControlManager = new AccessControlManager(createTestTransactionManager()); accessControlManager.checkCanSetUser(null, "foo"); } @Test public void testNoneSystemAccessControl() throws Exception { AccessControlManager accessControlManager = new AccessControlManager(createTestTransactionManager()); accessControlManager.setSystemAccessControl(AllowAllSystemAccessControl.NAME, ImmutableMap.of()); accessControlManager.checkCanSetUser(null, USER_NAME); } @Test public void testReadOnlySystemAccessControl() throws Exception { Identity identity = new Identity(USER_NAME, Optional.of(PRINCIPAL)); QualifiedObjectName tableName = new QualifiedObjectName("catalog", "schema", "table"); TransactionManager transactionManager = createTestTransactionManager(); AccessControlManager accessControlManager = new AccessControlManager(transactionManager); accessControlManager.setSystemAccessControl(ReadOnlySystemAccessControl.NAME, ImmutableMap.of()); accessControlManager.checkCanSetUser(PRINCIPAL, USER_NAME); accessControlManager.checkCanSetSystemSessionProperty(identity, "property"); transaction(transactionManager, accessControlManager) .execute(transactionId -> { accessControlManager.checkCanSetCatalogSessionProperty(transactionId, identity, "catalog", "property"); accessControlManager.checkCanSelectFromTable(transactionId, identity, tableName); accessControlManager.checkCanSelectFromView(transactionId, identity, tableName); accessControlManager.checkCanCreateViewWithSelectFromTable(transactionId, identity, tableName); accessControlManager.checkCanCreateViewWithSelectFromView(transactionId, identity, tableName); accessControlManager.checkCanShowSchemas(transactionId, identity, "catalog"); accessControlManager.checkCanShowTablesMetadata(transactionId, identity, new CatalogSchemaName("catalog", "schema")); Set<String> catalogs = ImmutableSet.of("catalog"); assertEquals(accessControlManager.filterCatalogs(identity, catalogs), catalogs); Set<String> schemas = ImmutableSet.of("schema"); assertEquals(accessControlManager.filterSchemas(transactionId, identity, "catalog", schemas), schemas); Set<SchemaTableName> tableNames = ImmutableSet.of(new SchemaTableName("schema", "table")); assertEquals(accessControlManager.filterTables(transactionId, identity, "catalog", tableNames), tableNames); }); try { transaction(transactionManager, accessControlManager) .execute(transactionId -> { accessControlManager.checkCanInsertIntoTable(transactionId, identity, tableName); }); fail(); } catch (AccessDeniedException expected) { } } @Test public void testSetAccessControl() throws Exception { AccessControlManager accessControlManager = new AccessControlManager(createTestTransactionManager()); TestSystemAccessControlFactory accessControlFactory = new TestSystemAccessControlFactory("test"); accessControlManager.addSystemAccessControlFactory(accessControlFactory); accessControlManager.setSystemAccessControl("test", ImmutableMap.of()); accessControlManager.checkCanSetUser(PRINCIPAL, USER_NAME); assertEquals(accessControlFactory.getCheckedUserName(), USER_NAME); assertEquals(accessControlFactory.getCheckedPrincipal(), PRINCIPAL); } @Test public void testNoCatalogAccessControl() throws Exception { TransactionManager transactionManager = createTestTransactionManager(); AccessControlManager accessControlManager = new AccessControlManager(transactionManager); TestSystemAccessControlFactory accessControlFactory = new TestSystemAccessControlFactory("test"); accessControlManager.addSystemAccessControlFactory(accessControlFactory); accessControlManager.setSystemAccessControl("test", ImmutableMap.of()); transaction(transactionManager, accessControlManager) .execute(transactionId -> { accessControlManager.checkCanSelectFromTable(transactionId, new Identity(USER_NAME, Optional.of(PRINCIPAL)), new QualifiedObjectName("catalog", "schema", "table")); }); } @Test(expectedExceptions = PrestoException.class, expectedExceptionsMessageRegExp = "Access Denied: Cannot select from table schema.table") public void testDenyCatalogAccessControl() throws Exception { CatalogManager catalogManager = new CatalogManager(); TransactionManager transactionManager = createTestTransactionManager(catalogManager); AccessControlManager accessControlManager = new AccessControlManager(transactionManager); TestSystemAccessControlFactory accessControlFactory = new TestSystemAccessControlFactory("test"); accessControlManager.addSystemAccessControlFactory(accessControlFactory); accessControlManager.setSystemAccessControl("test", ImmutableMap.of()); ConnectorId connectorId = registerBogusConnector(catalogManager, transactionManager, accessControlManager, "catalog"); accessControlManager.addCatalogAccessControl(connectorId, new DenyConnectorAccessControl()); transaction(transactionManager, accessControlManager) .execute(transactionId -> { accessControlManager.checkCanSelectFromTable(transactionId, new Identity(USER_NAME, Optional.of(PRINCIPAL)), new QualifiedObjectName("catalog", "schema", "table")); }); } @Test(expectedExceptions = PrestoException.class, expectedExceptionsMessageRegExp = "Access Denied: Cannot select from table secured_catalog.schema.table") public void testDenySystemAccessControl() throws Exception { CatalogManager catalogManager = new CatalogManager(); TransactionManager transactionManager = createTestTransactionManager(catalogManager); AccessControlManager accessControlManager = new AccessControlManager(transactionManager); TestSystemAccessControlFactory accessControlFactory = new TestSystemAccessControlFactory("test"); accessControlManager.addSystemAccessControlFactory(accessControlFactory); accessControlManager.setSystemAccessControl("test", ImmutableMap.of()); registerBogusConnector(catalogManager, transactionManager, accessControlManager, "connector"); accessControlManager.addCatalogAccessControl(new ConnectorId("connector"), new DenyConnectorAccessControl()); transaction(transactionManager, accessControlManager) .execute(transactionId -> { accessControlManager.checkCanSelectFromTable(transactionId, new Identity(USER_NAME, Optional.of(PRINCIPAL)), new QualifiedObjectName("secured_catalog", "schema", "table")); }); } private static ConnectorId registerBogusConnector(CatalogManager catalogManager, TransactionManager transactionManager, AccessControl accessControl, String catalogName) { ConnectorId connectorId = new ConnectorId(catalogName); Connector connector = new TpchConnectorFactory().create(catalogName, ImmutableMap.of(), new TestingConnectorContext()); InMemoryNodeManager nodeManager = new InMemoryNodeManager(); MetadataManager metadata = MetadataManager.createTestMetadataManager(catalogManager); ConnectorId systemId = createSystemTablesConnectorId(connectorId); catalogManager.registerCatalog(new Catalog( catalogName, connectorId, connector, createInformationSchemaConnectorId(connectorId), new InformationSchemaConnector(catalogName, nodeManager, metadata, accessControl), systemId, new SystemConnector( systemId, nodeManager, connector.getSystemTables(), transactionId -> transactionManager.getConnectorTransaction(transactionId, connectorId)))); return connectorId; } private static class TestSystemAccessControlFactory implements SystemAccessControlFactory { private final String name; private Map<String, String> config; private Principal checkedPrincipal; private String checkedUserName; public TestSystemAccessControlFactory(String name) { this.name = requireNonNull(name, "name is null"); } public Map<String, String> getConfig() { return config; } public Principal getCheckedPrincipal() { return checkedPrincipal; } public String getCheckedUserName() { return checkedUserName; } @Override public String getName() { return name; } @Override public SystemAccessControl create(Map<String, String> config) { this.config = config; return new SystemAccessControl() { @Override public void checkCanSetUser(Principal principal, String userName) { checkedPrincipal = principal; checkedUserName = userName; } @Override public void checkCanSetSystemSessionProperty(Identity identity, String propertyName) { throw new UnsupportedOperationException(); } @Override public void checkCanSelectFromTable(Identity identity, CatalogSchemaTableName table) { if (table.getCatalogName().equals("secured_catalog")) { denySelectTable(table.toString()); } } }; } } private static class DenyConnectorAccessControl implements ConnectorAccessControl { @Override public void checkCanSelectFromTable(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName tableName) { denySelectTable(tableName.toString()); } @Override public void checkCanCreateSchema(ConnectorTransactionHandle transactionHandle, Identity identity, String schemaName) { throw new UnsupportedOperationException(); } @Override public void checkCanDropSchema(ConnectorTransactionHandle transactionHandle, Identity identity, String schemaName) { throw new UnsupportedOperationException(); } @Override public void checkCanRenameSchema(ConnectorTransactionHandle transactionHandle, Identity identity, String schemaName, String newSchemaName) { throw new UnsupportedOperationException(); } @Override public void checkCanCreateTable(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName tableName) { throw new UnsupportedOperationException(); } @Override public void checkCanDropTable(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName tableName) { throw new UnsupportedOperationException(); } @Override public void checkCanRenameTable(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName tableName, SchemaTableName newTableName) { throw new UnsupportedOperationException(); } @Override public void checkCanAddColumn(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName tableName) { throw new UnsupportedOperationException(); } @Override public void checkCanRenameColumn(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName tableName) { throw new UnsupportedOperationException(); } @Override public void checkCanInsertIntoTable(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName tableName) { throw new UnsupportedOperationException(); } @Override public void checkCanDeleteFromTable(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName tableName) { throw new UnsupportedOperationException(); } @Override public void checkCanCreateView(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName viewName) { throw new UnsupportedOperationException(); } @Override public void checkCanDropView(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName viewName) { throw new UnsupportedOperationException(); } @Override public void checkCanSelectFromView(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName viewName) { throw new UnsupportedOperationException(); } @Override public void checkCanCreateViewWithSelectFromTable(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName tableName) { throw new UnsupportedOperationException(); } @Override public void checkCanCreateViewWithSelectFromView(ConnectorTransactionHandle transactionHandle, Identity identity, SchemaTableName viewName) { throw new UnsupportedOperationException(); } @Override public void checkCanSetCatalogSessionProperty(Identity identity, String propertyName) { throw new UnsupportedOperationException(); } @Override public void checkCanGrantTablePrivilege(ConnectorTransactionHandle transactionHandle, Identity identity, Privilege privilege, SchemaTableName tableName) { throw new UnsupportedOperationException(); } @Override public void checkCanRevokeTablePrivilege(ConnectorTransactionHandle transactionHandle, Identity identity, Privilege privilege, SchemaTableName tableName) { throw new UnsupportedOperationException(); } } }