Github user twdsilva commented on a diff in the pull request: https://github.com/apache/phoenix/pull/283#discussion_r153685552 --- Diff: phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java --- @@ -4168,4 +4176,124 @@ public MutationState useSchema(UseSchemaStatement useSchemaStatement) throws SQL } return new MutationState(0, 0, connection); } + + public MutationState changePermissions(ChangePermsStatement changePermsStatement) throws SQLException { + + logger.info(changePermsStatement.toString()); + + try(HBaseAdmin admin = connection.getQueryServices().getAdmin()) { + ClusterConnection clusterConnection = (ClusterConnection) admin.getConnection(); + + if (changePermsStatement.getSchemaName() != null) { + // SYSTEM.CATALOG doesn't have any entry for "default" HBase namespace, hence we will bypass the check + if(!changePermsStatement.getSchemaName().equals(QueryConstants.HBASE_DEFAULT_SCHEMA_NAME)) { + FromCompiler.getResolverForSchema(changePermsStatement.getSchemaName(), connection); + } + + changePermsOnSchema(clusterConnection, changePermsStatement); + } else if (changePermsStatement.getTableName() != null) { + PTable inputTable = PhoenixRuntime.getTable(connection, + SchemaUtil.normalizeFullTableName(changePermsStatement.getTableName().toString())); + if (!(PTableType.TABLE.equals(inputTable.getType()) || PTableType.SYSTEM.equals(inputTable.getType()))) { + throw new AccessDeniedException("Cannot GRANT or REVOKE permissions on INDEX TABLES or VIEWS"); + } + + changePermsOnTables(clusterConnection, admin, changePermsStatement, inputTable); + } else { + + changePermsOnUser(clusterConnection, changePermsStatement); + } + + } catch (SQLException e) { + // Bubble up the SQL Exception + throw e; + } catch (Throwable throwable) { + // Wrap around other exceptions to PhoenixIOException (Ex: org.apache.hadoop.hbase.security.AccessDeniedException) + throw ServerUtil.parseServerException(throwable); + } + + return new MutationState(0, 0, connection); + } + + private void changePermsOnSchema(ClusterConnection clusterConnection, ChangePermsStatement changePermsStatement) throws Throwable { + if(changePermsStatement.isGrantStatement()) { + AccessControlClient.grant(clusterConnection, changePermsStatement.getSchemaName(), changePermsStatement.getName(), changePermsStatement.getPermsList()); + } else { + AccessControlClient.revoke(clusterConnection, changePermsStatement.getSchemaName(), changePermsStatement.getName(), Permission.Action.values()); + } + } + + private void changePermsOnTables(ClusterConnection clusterConnection, HBaseAdmin admin, ChangePermsStatement changePermsStatement, PTable inputTable) throws Throwable { + + org.apache.hadoop.hbase.TableName tableName = SchemaUtil.getPhysicalTableName + (inputTable.getPhysicalName().getBytes(), inputTable.isNamespaceMapped()); + + changePermsOnTable(clusterConnection, changePermsStatement, tableName); + + boolean schemaInconsistency = false; + List<PTable> inconsistentTables = null; + + for(PTable indexTable : inputTable.getIndexes()) { + // Local Indexes don't correspond to new physical table, they are just stored in separate CF of base table. + if(indexTable.getIndexType().equals(IndexType.LOCAL)) { + continue; + } + if (inputTable.isNamespaceMapped() != indexTable.isNamespaceMapped()) { + schemaInconsistency = true; + if(inconsistentTables == null) { + inconsistentTables = new ArrayList<>(); + } + inconsistentTables.add(indexTable); + continue; + } + logger.info("Updating permissions for Index Table: " + + indexTable.getName() + " Base Table: " + inputTable.getName()); + tableName = SchemaUtil.getPhysicalTableName(indexTable.getPhysicalName().getBytes(), indexTable.isNamespaceMapped()); + changePermsOnTable(clusterConnection, changePermsStatement, tableName); + } + + if(schemaInconsistency) { + for(PTable table : inconsistentTables) { + logger.error("Fail to propagate permissions to Index Table: " + table.getName()); + } + throw new TablesNotInSyncException(inputTable.getTableName().getString(), + inconsistentTables.get(0).getTableName().getString(), "Namespace properties"); + } + + if(inputTable.isMultiTenant()) { --- End diff -- non multi-tenant tables could also have views which have indexes, so you need to check if the view index table exists for them and then keep the perms in sync if it does.
---