Return-Path: X-Original-To: apmail-accumulo-commits-archive@www.apache.org Delivered-To: apmail-accumulo-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id E9373109DE for ; Wed, 4 Dec 2013 23:58:43 +0000 (UTC) Received: (qmail 46381 invoked by uid 500); 4 Dec 2013 23:58:43 -0000 Delivered-To: apmail-accumulo-commits-archive@accumulo.apache.org Received: (qmail 46214 invoked by uid 500); 4 Dec 2013 23:58:43 -0000 Mailing-List: contact commits-help@accumulo.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@accumulo.apache.org Delivered-To: mailing list commits@accumulo.apache.org Received: (qmail 46069 invoked by uid 99); 4 Dec 2013 23:58:43 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 04 Dec 2013 23:58:43 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id CCFDA320356; Wed, 4 Dec 2013 23:58:42 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: ctubbsii@apache.org To: commits@accumulo.apache.org Date: Wed, 04 Dec 2013 23:58:52 -0000 Message-Id: <7a3e2e196cff48a694c08340abda63c5@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [11/50] [abbrv] git commit: ACCUMULO-1479 finished initial implementation of table namespace permissions, including tests ACCUMULO-1479 finished initial implementation of table namespace permissions, including tests Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/14fb2571 Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/14fb2571 Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/14fb2571 Branch: refs/heads/master Commit: 14fb257126810965c637ae234b1ba9623c2b5855 Parents: ad9abf4 Author: Sean Hickey Authored: Fri Aug 2 13:32:42 2013 -0400 Committer: Christopher Tubbs Committed: Wed Dec 4 18:46:10 2013 -0500 ---------------------------------------------------------------------- .../accumulo/core/client/mock/MockTable.java | 2 +- .../core/client/mock/MockTableNamespace.java | 4 - .../core/security/TableNamespacePermission.java | 5 +- .../apache/accumulo/core/util/shell/Shell.java | 3 +- .../commands/NamespacePermissionsCommand.java | 44 +++++ .../shell/commands/UserPermissionsCommand.java | 22 +-- .../client/mock/MockTableNamespacesTest.java | 180 ++++++++++++------- .../server/conf/TableParentConfiguration.java | 41 +++++ .../security/AuditedSecurityOperation.java | 2 +- .../server/security/SecurityOperation.java | 48 ++++- .../server/security/handler/ZKPermHandler.java | 19 ++ .../java/org/apache/accumulo/master/Master.java | 30 +++- .../master/tableOps/CloneTableNamespace.java | 25 ++- .../master/tableOps/CreateTableNamespace.java | 24 ++- .../master/tableOps/DeleteTableNamespace.java | 14 +- .../server/conf/TableParentConfiguration.java | 41 ----- .../org/apache/accumulo/test/ShellServerIT.java | 5 + .../apache/accumulo/test/TableNamespacesIT.java | 144 ++++++++++++--- 18 files changed, 466 insertions(+), 187 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java b/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java index 0e71414..5c4cb36 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java +++ b/core/src/main/java/org/apache/accumulo/core/client/mock/MockTable.java @@ -105,7 +105,7 @@ public class MockTable { MockTable(MockTableNamespace namespace, boolean limitVersion, TimeType timeType) { this(limitVersion, timeType); - Set> set = namespace.getSettings().entrySet(); + Set> set = namespace.settings.entrySet(); Iterator> entries = set.iterator(); while (entries.hasNext()) { Entry entry = entries.next(); http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableNamespace.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableNamespace.java b/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableNamespace.java index beec4db..1798dd1 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableNamespace.java +++ b/core/src/main/java/org/apache/accumulo/core/client/mock/MockTableNamespace.java @@ -43,10 +43,6 @@ public class MockTableNamespace { } } - public Map getSettings() { - return settings; - } - public List getTables(MockAccumulo acu) { List l = new LinkedList(); for (String t : acu.tables.keySet()) { http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/core/src/main/java/org/apache/accumulo/core/security/TableNamespacePermission.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/security/TableNamespacePermission.java b/core/src/main/java/org/apache/accumulo/core/security/TableNamespacePermission.java index 565a81a..9354b02 100644 --- a/core/src/main/java/org/apache/accumulo/core/security/TableNamespacePermission.java +++ b/core/src/main/java/org/apache/accumulo/core/security/TableNamespacePermission.java @@ -23,12 +23,11 @@ public enum TableNamespacePermission { // One can add new permissions, with new numbers, but please don't change or use numbers previously assigned READ((byte) 0), WRITE((byte) 1), - ALTER_TABLE_NAMESPACE((byte) 2), + ALTER_NAMESPACE((byte) 2), GRANT((byte) 3), ALTER_TABLE((byte) 4), CREATE_TABLE((byte) 5), - DROP_TABLE((byte) 6), - BULK_IMPORT((byte) 7); + DROP_TABLE((byte) 6); final private byte permID; http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java b/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java index debca0b..c19e84a 100644 --- a/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java +++ b/core/src/main/java/org/apache/accumulo/core/util/shell/Shell.java @@ -122,6 +122,7 @@ import org.apache.accumulo.core.util.shell.commands.ListScansCommand; import org.apache.accumulo.core.util.shell.commands.ListShellIterCommand; import org.apache.accumulo.core.util.shell.commands.MaxRowCommand; import org.apache.accumulo.core.util.shell.commands.MergeCommand; +import org.apache.accumulo.core.util.shell.commands.NamespacePermissionsCommand; import org.apache.accumulo.core.util.shell.commands.NamespacesCommand; import org.apache.accumulo.core.util.shell.commands.NoTableCommand; import org.apache.accumulo.core.util.shell.commands.OfflineCommand; @@ -354,7 +355,7 @@ public class Shell extends ShellOptions { new SetShellIterCommand(), new ListShellIterCommand(), new DeleteShellIterCommand()}; Command[] otherCommands = {new HiddenCommand()}; Command[] permissionsCommands = {new GrantCommand(), new RevokeCommand(), new SystemPermissionsCommand(), new TablePermissionsCommand(), - new UserPermissionsCommand()}; + new UserPermissionsCommand(), new NamespacePermissionsCommand()}; Command[] stateCommands = {new AuthenticateCommand(), new ClsCommand(), new ClearCommand(), new FateCommand(), new NoTableCommand(), new SleepCommand(), new TableCommand(), new UserCommand(), new WhoAmICommand()}; Command[] tableCommands = {new CloneTableCommand(), new ConfigCommand(), new CreateTableCommand(), new DeleteTableCommand(), new DropTableCommand(), http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/core/src/main/java/org/apache/accumulo/core/util/shell/commands/NamespacePermissionsCommand.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/NamespacePermissionsCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/NamespacePermissionsCommand.java new file mode 100644 index 0000000..822522e --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/NamespacePermissionsCommand.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.accumulo.core.util.shell.commands; + +import java.io.IOException; + +import org.apache.accumulo.core.security.TableNamespacePermission; +import org.apache.accumulo.core.util.shell.Shell; +import org.apache.accumulo.core.util.shell.Shell.Command; +import org.apache.commons.cli.CommandLine; + +public class NamespacePermissionsCommand extends Command { + @Override + public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws IOException { + for (String p : TableNamespacePermission.printableValues()) { + shellState.getReader().println(p); + } + return 0; + } + + @Override + public String description() { + return "displays a list of valid table namespace permissions"; + } + + @Override + public int numArgs() { + return 0; + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/core/src/main/java/org/apache/accumulo/core/util/shell/commands/UserPermissionsCommand.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/UserPermissionsCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/UserPermissionsCommand.java index 25d9d54..1b6377a 100644 --- a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/UserPermissionsCommand.java +++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/UserPermissionsCommand.java @@ -47,34 +47,34 @@ public class UserPermissionsCommand extends Command { } shellState.getReader().println(); - for (String t : shellState.getConnector().tableOperations().list()) { + for (String n : shellState.getConnector().tableNamespaceOperations().list()) { delim = ""; - for (TablePermission p : TablePermission.values()) { - if (shellState.getConnector().securityOperations().hasTablePermission(user, t, p) && p != null) { + for (TableNamespacePermission p : TableNamespacePermission.values()) { + if (p != null && shellState.getConnector().securityOperations().hasTableNamespacePermission(user, n, p)) { if (runOnce == 0) { - shellState.getReader().print("\nTable permissions (" + t + "): "); + shellState.getReader().print("\nTable Namespace permissions (" + n + "): "); runOnce++; } - shellState.getReader().print(delim + "Table." + p.name()); + shellState.getReader().print(delim + "Namespace." + p.name()); delim = ", "; } - } runOnce = 0; } shellState.getReader().println(); - for (String n : shellState.getConnector().tableNamespaceOperations().list()) { + for (String t : shellState.getConnector().tableOperations().list()) { delim = ""; - for (TableNamespacePermission p : TableNamespacePermission.values()) { - if (p != null && shellState.getConnector().securityOperations().hasTableNamespacePermission(user, n, p)) { + for (TablePermission p : TablePermission.values()) { + if (shellState.getConnector().securityOperations().hasTablePermission(user, t, p) && p != null) { if (runOnce == 0) { - shellState.getReader().print("\nTable Namespace permissions (" + n + "): "); + shellState.getReader().print("\nTable permissions (" + t + "): "); runOnce++; } - shellState.getReader().print(delim + "Namespace." + p.name()); + shellState.getReader().print(delim + "Table." + p.name()); delim = ", "; } + } runOnce = 0; } http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/core/src/test/java/org/apache/accumulo/core/client/mock/MockTableNamespacesTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/client/mock/MockTableNamespacesTest.java b/core/src/test/java/org/apache/accumulo/core/client/mock/MockTableNamespacesTest.java index d15b3e5..2ba1006 100644 --- a/core/src/test/java/org/apache/accumulo/core/client/mock/MockTableNamespacesTest.java +++ b/core/src/test/java/org/apache/accumulo/core/client/mock/MockTableNamespacesTest.java @@ -21,14 +21,29 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Map.Entry; +import java.util.EnumSet; +import java.util.HashSet; import java.util.Random; import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.AccumuloException; +import org.apache.accumulo.core.client.BatchWriter; +import org.apache.accumulo.core.client.BatchWriterConfig; import org.apache.accumulo.core.client.Connector; import org.apache.accumulo.core.client.Instance; +import org.apache.accumulo.core.client.IteratorSetting; +import org.apache.accumulo.core.client.Scanner; import org.apache.accumulo.core.client.TableNamespaceNotEmptyException; +import org.apache.accumulo.core.client.TableNamespaceNotFoundException; +import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.client.security.tokens.PasswordToken; import org.apache.accumulo.core.conf.Property; +import org.apache.accumulo.core.data.Key; +import org.apache.accumulo.core.data.Mutation; +import org.apache.accumulo.core.data.Value; +import org.apache.accumulo.core.iterators.Filter; +import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; +import org.apache.accumulo.core.security.Authorizations; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -54,9 +69,9 @@ public class MockTableNamespacesTest { } /** - * This test creates a new namespace "testing" and a table "testing.table1" which puts "table1" into the "testing" namespace. - * Then we create "testing.table2" which creates "table2" and puts it into "testing" as well. - * Then we make sure that you can't delete a namespace with tables in it, and then we delete the tables and delete the namespace. + * This test creates a new namespace "testing" and a table "testing.table1" which puts "table1" into the "testing" namespace. Then we create "testing.table2" + * which creates "table2" and puts it into "testing" as well. Then we make sure that you can't delete a namespace with tables in it, and then we delete the + * tables and delete the namespace. * * @throws Exception */ @@ -93,7 +108,7 @@ public class MockTableNamespacesTest { c.tableOperations().delete(tableName2); assertTrue(!c.tableOperations().exists(tableName2)); assertTrue(c.tableNamespaceOperations().exists(namespace)); - + c.tableOperations().delete(tableName1); assertTrue(!c.tableOperations().exists(tableName1)); c.tableNamespaceOperations().delete(namespace); @@ -128,37 +143,15 @@ public class MockTableNamespacesTest { c.tableNamespaceOperations().setProperty(namespace, propKey, propVal); // check the namespace has the property - boolean itWorked = false; - for (Entry prop : c.tableNamespaceOperations().getProperties(namespace)) { - if (prop.getKey().equals(propKey) && prop.getValue().equals(propVal)) { - itWorked = true; - break; - } - } - - assertTrue(itWorked); + assertTrue(checkTableNamespaceHasProp(c, namespace, propKey, propVal)); // check that the table gets it from the namespace - itWorked = false; - for (Entry prop : c.tableOperations().getProperties(tableName1)) { - if (prop.getKey().equals(propKey) && prop.getValue().equals(propVal)) { - itWorked = true; - break; - } - } - assertTrue(itWorked); + assertTrue(checkTableHasProp(c, tableName1, propKey, propVal)); // test a second table to be sure the first wasn't magical - // (also, changed the order, the namespace already exists with the property) - itWorked = false; + // (also, changed the order, the namespace has the property already) c.tableOperations().create(tableName2); - for (Entry prop : c.tableOperations().getProperties(tableName2)) { - if (prop.getKey().equals(propKey) && prop.getValue().equals(propVal)) { - itWorked = true; - break; - } - } - assertTrue(itWorked); + assertTrue(checkTableHasProp(c, tableName2, propKey, propVal)); // test that table properties override namespace properties String propKey2 = Property.TABLE_FILE_MAX.getKey(); @@ -168,47 +161,38 @@ public class MockTableNamespacesTest { c.tableOperations().setProperty(tableName2, propKey2, tablePropVal); c.tableNamespaceOperations().setProperty("propchange", propKey2, propVal2); - itWorked = false; - for (Entry prop : c.tableOperations().getProperties(tableName2)) { - if (prop.getKey().equals(propKey2) && prop.getValue().equals(tablePropVal)) { - itWorked = true; - break; - } - } - assertTrue(itWorked); + assertTrue(checkTableHasProp(c, tableName2, propKey2, tablePropVal)); // now check that you can change the default namespace's properties propVal = "13K"; - propVal2 = "44"; String tableName = "some_table"; c.tableOperations().create(tableName); c.tableNamespaceOperations().setProperty(Constants.DEFAULT_TABLE_NAMESPACE, propKey, propVal); - itWorked = false; - for (Entry prop : c.tableOperations().getProperties(tableName)) { - if (prop.getKey().equals(propKey) && prop.getValue().equals(propVal)) { - itWorked = true; - break; - } - } - assertTrue(itWorked); - } - - /** - * This test creates a new user and a namespace. It checks to make sure the user can't modify anything in the namespace at first, then it grants the user - * permissions and makes sure that they can modify the namespace. Then it also checks if the user has the correct permissions on tables both already existing - * in the namespace and ones they create. - * - * @throws Exception - */ - @Test - public void testNamespacePermissions() throws Exception { - // TODO make the test once namespace-level permissions are implemented. (ACCUMULO-1479) + assertTrue(checkTableHasProp(c, tableName, propKey, propVal)); + + // test the properties server-side by configuring an iterator. + // should not show anything with column-family = 'a' + String tableName3 = namespace + ".table3"; + c.tableOperations().create(tableName3); + + IteratorSetting setting = new IteratorSetting(250, "thing", SimpleFilter.class.getName()); + c.tableNamespaceOperations().attachIterator(namespace, setting); + + BatchWriter bw = c.createBatchWriter(tableName3, new BatchWriterConfig()); + Mutation m = new Mutation("r"); + m.put("a", "b", new Value("abcde".getBytes())); + bw.addMutation(m); + bw.flush(); + bw.close(); + + // Scanner s = c.createScanner(tableName3, Authorizations.EMPTY); + // do scanners work correctly in mock? + // assertTrue(!s.iterator().hasNext()); } /** - * This test renames and clones two separate table into different namespaces. - * different namespace. + * This test renames and clones two separate table into different namespaces. different namespace. * * @throws Exception */ @@ -218,11 +202,11 @@ public class MockTableNamespacesTest { String namespace2 = "cloned"; String tableName = "table"; String tableName1 = "renamed.table1"; - //String tableName2 = "cloned.table2"; + // String tableName2 = "cloned.table2"; Instance instance = new MockInstance("renameclone"); Connector c = instance.getConnector("user", new PasswordToken("pass")); - + c.tableOperations().create(tableName); c.tableNamespaceOperations().create(namespace1); c.tableNamespaceOperations().create(namespace2); @@ -233,10 +217,11 @@ public class MockTableNamespacesTest { assertTrue(!c.tableOperations().exists(tableName)); // TODO implement clone in mock - /*c.tableOperations().clone(tableName1, tableName2, false, null, null); - - assertTrue(c.tableOperations().exists(tableName1)); - assertTrue(c.tableOperations().exists(tableName2));*/ + /* + * c.tableOperations().clone(tableName1, tableName2, false, null, null); + * + * assertTrue(c.tableOperations().exists(tableName1)); assertTrue(c.tableOperations().exists(tableName2)); + */ return; } @@ -262,4 +247,65 @@ public class MockTableNamespacesTest { assertTrue(!c.tableOperations().exists(namespace1 + "." + table)); assertTrue(c.tableOperations().exists(namespace2 + "." + table)); } + + /** + * This tests adding iterators to a namespace, listing them, and removing them + */ + @Test + public void testNamespaceIterators() throws Exception { + Instance instance = new MockInstance("Iterators"); + Connector c = instance.getConnector("user", new PasswordToken("pass")); + + String namespace = "iterator"; + String tableName = namespace + ".table"; + String iter = "thing"; + + c.tableNamespaceOperations().create(namespace); + c.tableOperations().create(tableName); + + IteratorSetting setting = new IteratorSetting(250, iter, SimpleFilter.class.getName()); + HashSet scope = new HashSet(); + scope.add(IteratorScope.scan); + c.tableNamespaceOperations().attachIterator(namespace, setting, EnumSet.copyOf(scope)); + + BatchWriter bw = c.createBatchWriter(tableName, new BatchWriterConfig()); + Mutation m = new Mutation("r"); + m.put("a", "b", new Value("abcde".getBytes(Constants.UTF8))); + bw.addMutation(m); + bw.flush(); + + Scanner s = c.createScanner(tableName, Authorizations.EMPTY); + System.out.println(s.iterator().next()); + // do scanners work correctly in mock? + // assertTrue(!s.iterator().hasNext()); + + assertTrue(c.tableNamespaceOperations().listIterators(namespace).containsKey(iter)); + c.tableNamespaceOperations().removeIterator(namespace, iter, EnumSet.copyOf(scope)); + } + + private boolean checkTableHasProp(Connector c, String t, String propKey, String propVal) throws AccumuloException, TableNotFoundException { + for (Entry e : c.tableOperations().getProperties(t)) { + if (e.getKey().equals(propKey) && e.getValue().equals(propVal)) { + return true; + } + } + return false; + } + + private boolean checkTableNamespaceHasProp(Connector c, String n, String propKey, String propVal) throws AccumuloException, TableNamespaceNotFoundException { + for (Entry e : c.tableNamespaceOperations().getProperties(n)) { + if (e.getKey().equals(propKey) && e.getValue().equals(propVal)) { + return true; + } + } + return false; + } + + public static class SimpleFilter extends Filter { + public boolean accept(Key k, Value v) { + if (k.getColumnFamily().toString().equals("a")) + return false; + return true; + } + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/server/base/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java b/server/base/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java new file mode 100644 index 0000000..7590d76 --- /dev/null +++ b/server/base/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java @@ -0,0 +1,41 @@ +/* + * 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.accumulo.server.conf; + +import org.apache.accumulo.core.client.impl.Tables; +import org.apache.accumulo.core.conf.AccumuloConfiguration; + + +/** + * Used by TableConfiguration to dynamically get the TableNamespaceConfiguration if the namespace changes + */ +public class TableParentConfiguration extends TableNamespaceConfiguration { + + private String tableId; + + public TableParentConfiguration(String tableId, AccumuloConfiguration parent) { + super(null, parent); + this.tableId = tableId; + this.namespaceId = getNamespaceId(); + } + + @Override + protected String getNamespaceId() { + this.namespaceId = Tables.getNamespace(inst, tableId); + return this.namespaceId; + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/server/base/src/main/java/org/apache/accumulo/server/security/AuditedSecurityOperation.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/AuditedSecurityOperation.java b/server/base/src/main/java/org/apache/accumulo/server/security/AuditedSecurityOperation.java index 7148556..7ec9fd2 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/security/AuditedSecurityOperation.java +++ b/server/base/src/main/java/org/apache/accumulo/server/security/AuditedSecurityOperation.java @@ -235,7 +235,7 @@ public class AuditedSecurityOperation extends SecurityOperation { @Override public boolean canCreateTable(TCredentials c, String tableName) throws ThriftSecurityException { try { - boolean result = super.canCreateTable(c); + boolean result = super.canCreateTable(c, tableName); audit(c, result, CAN_CREATE_TABLE_AUDIT_TEMPLATE, tableName); return result; } catch (ThriftSecurityException ex) { http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/server/base/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java b/server/base/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java index 6dcaf9d..7e7dde9 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java +++ b/server/base/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java @@ -343,7 +343,7 @@ public class SecurityOperation { String namespace = TableNamespaces.getNamespaceId(HdfsZooInstance.getInstance(), tableNamespace); return hasTableNamespacePermission(credentials, namespace, permission, useCached); } catch (TableNamespaceNotFoundException e) { - return false; + throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.TABLE_NAMESPACE_DOESNT_EXIST); } } @@ -451,7 +451,8 @@ public class SecurityOperation { } public boolean canCreateTable(TCredentials c, String tableName) throws ThriftSecurityException { - return canCreateTable(c) || hasTableNamespacePermissionForTableName(c, tableName, TableNamespacePermission.CREATE_TABLE, false); + authenticate(c); + return hasTableNamespacePermissionForTableName(c, tableName, TableNamespacePermission.CREATE_TABLE, false) || canCreateTable(c); } public boolean canCreateTable(TCredentials c) throws ThriftSecurityException { @@ -469,7 +470,8 @@ public class SecurityOperation { authenticate(c); return (hasSystemPermission(c, SystemPermission.CREATE_TABLE, false) || hasTableNamespacePermissionForTableName(c, tableName, TableNamespacePermission.CREATE_TABLE, false)) - && (hasTablePermission(c, tableId, TablePermission.READ, false) || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.READ, false)); + && (hasTablePermission(c, tableId, TablePermission.READ, false) || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.READ, + false)); } public boolean canDeleteTable(TCredentials c, String tableId) throws ThriftSecurityException { @@ -504,8 +506,7 @@ public class SecurityOperation { public boolean canBulkImport(TCredentials c, String tableId) throws ThriftSecurityException { authenticate(c); - return hasTablePermission(c, tableId, TablePermission.BULK_IMPORT, false) - || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.BULK_IMPORT, false); + return hasTablePermission(c, tableId, TablePermission.BULK_IMPORT, false); } public boolean canCompact(TCredentials c, String tableId) throws ThriftSecurityException { @@ -579,7 +580,7 @@ public class SecurityOperation { public boolean canRevokeTableNamespace(TCredentials c, String user, String tableNamespace) throws ThriftSecurityException { authenticate(c); - return hasSystemPermission(c, SystemPermission.ALTER_NAMESPACE, false) || hasTablePermission(c, tableNamespace, TablePermission.GRANT, false); + return hasSystemPermission(c, SystemPermission.ALTER_NAMESPACE, false) || hasTableNamespacePermission(c, tableNamespace, TableNamespacePermission.GRANT, false); } public void changeAuthorizations(TCredentials credentials, String user, Authorizations authorizations) throws ThriftSecurityException { @@ -778,7 +779,7 @@ public class SecurityOperation { } public void deleteTableNamespace(TCredentials credentials, String tableNamespace) throws ThriftSecurityException { - if (!canDeleteTable(credentials, tableNamespace)) + if (!canDeleteNamespace(credentials, tableNamespace)) throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED); try { permHandle.cleanTableNamespacePermissions(tableNamespace); @@ -801,4 +802,37 @@ public class SecurityOperation { return hasSystemPermission(credentials, SystemPermission.CREATE_TABLE, false) || hasTableNamespacePermissionForTableName(credentials, tableName, TableNamespacePermission.CREATE_TABLE, false); } + + public boolean canAlterNamespace(TCredentials credentials, String namespaceId) throws ThriftSecurityException { + authenticate(credentials); + return hasTableNamespacePermission(credentials, namespaceId, TableNamespacePermission.ALTER_NAMESPACE, false) + || hasSystemPermission(credentials, SystemPermission.ALTER_NAMESPACE, false); + } + + public boolean canCreateNamespace(TCredentials credentials, String namespace) throws ThriftSecurityException { + authenticate(credentials); + return canCreateNamespace(credentials); + } + + public boolean canCreateNamespace(TCredentials credentials) throws ThriftSecurityException { + authenticate(credentials); + return hasSystemPermission(credentials, SystemPermission.CREATE_NAMESPACE, false); + } + + public boolean canDeleteNamespace(TCredentials credentials, String namespaceId) throws ThriftSecurityException { + authenticate(credentials); + return hasSystemPermission(credentials, SystemPermission.DROP_NAMESPACE, false); + } + + public boolean canRenameNamespace(TCredentials credentials, String namespaceId, String oldName, String newName) throws ThriftSecurityException { + authenticate(credentials); + return hasTableNamespacePermission(credentials, namespaceId, TableNamespacePermission.ALTER_NAMESPACE, false) + || hasSystemPermission(credentials, SystemPermission.ALTER_NAMESPACE, false); + } + + public boolean canCloneNamespace(TCredentials credentials, String namespaceId, String namespace) throws ThriftSecurityException { + authenticate(credentials); + return hasTableNamespacePermission(credentials, namespaceId, TableNamespacePermission.READ, false) + && hasSystemPermission(credentials, SystemPermission.CREATE_NAMESPACE, false); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java index 78b79a1..6f6304a 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java +++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java @@ -23,6 +23,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; +import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.TableNamespaceNotFoundException; import org.apache.accumulo.core.client.TableNotFoundException; @@ -382,6 +383,10 @@ public class ZKPermHandler implements PermissionHandler { // Allow the root user to flush the system tables tablePerms.put(RootTable.ID, Collections.singleton(TablePermission.ALTER_TABLE)); tablePerms.put(MetadataTable.ID, Collections.singleton(TablePermission.ALTER_TABLE)); + // essentially the same but on the system namespace, the ALTER_TABLE permission is now redundant + Map> tableNamespacePerms = new HashMap>(); + tableNamespacePerms.put(Constants.SYSTEM_TABLE_NAMESPACE_ID, Collections.singleton(TableNamespacePermission.ALTER_NAMESPACE)); + tableNamespacePerms.put(Constants.SYSTEM_TABLE_NAMESPACE_ID, Collections.singleton(TableNamespacePermission.ALTER_TABLE)); try { // prep parent node of users with root username @@ -392,6 +397,8 @@ public class ZKPermHandler implements PermissionHandler { zoo.putPersistentData(ZKUserPath + "/" + rootuser + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(rootPerms), NodeExistsPolicy.FAIL); for (Entry> entry : tablePerms.entrySet()) createTablePerm(rootuser, entry.getKey(), entry.getValue()); + for (Entry> entry : tableNamespacePerms.entrySet()) + createTableNamespacePerm(rootuser, entry.getKey(), entry.getValue()); } catch (KeeperException e) { log.error(e, e); throw new RuntimeException(e); @@ -432,6 +439,17 @@ public class ZKPermHandler implements PermissionHandler { } } + /** + * Sets up a new table namespace configuration for the provided user/table. No checking for existence is done here, it should be done before calling. + */ + private void createTableNamespacePerm(String user, String namespace, Set perms) throws KeeperException, InterruptedException { + synchronized (zooCache) { + zooCache.clear(); + ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, + ZKSecurityTool.convertTableNamespacePermissions(perms), NodeExistsPolicy.FAIL); + } + } + @Override public void cleanUser(String user) throws AccumuloSecurityException { try { @@ -439,6 +457,7 @@ public class ZKPermHandler implements PermissionHandler { IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance(); zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserSysPerms, NodeMissingPolicy.SKIP); zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms, NodeMissingPolicy.SKIP); + zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms, NodeMissingPolicy.SKIP); zooCache.clear(ZKUserPath + "/" + user); } } catch (InterruptedException e) { http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/server/master/src/main/java/org/apache/accumulo/master/Master.java ---------------------------------------------------------------------- diff --git a/server/master/src/main/java/org/apache/accumulo/master/Master.java b/server/master/src/main/java/org/apache/accumulo/master/Master.java index d3f22e6..293dbc9 100644 --- a/server/master/src/main/java/org/apache/accumulo/master/Master.java +++ b/server/master/src/main/java/org/apache/accumulo/master/Master.java @@ -43,9 +43,9 @@ import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.RowIterator; import org.apache.accumulo.core.client.Scanner; import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.admin.TableOperationsImpl; import org.apache.accumulo.core.client.admin.TimeType; import org.apache.accumulo.core.client.impl.TableNamespaces; -import org.apache.accumulo.core.client.admin.TableOperationsImpl; import org.apache.accumulo.core.client.impl.Tables; import org.apache.accumulo.core.client.impl.ThriftTransportPool; import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode; @@ -743,14 +743,22 @@ public class Master implements LiveTServerSet.Listener, TableObserver, CurrentSt throws ThriftSecurityException, ThriftTableOperationException { String namespaceId = null; + namespaceId = checkNamespaceId(namespace, op); + + if (!security.canAlterNamespace(c, namespaceId)) + throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED); + try { - namespaceId = TableNamespaces.getNamespaceId(instance, namespace); - // TODO insert a permission check here once namespace-level permissions exist. (ACCUMULO-1479) if (value == null) { NamespacePropUtil.removeNamespaceProperty(namespaceId, property); } else { NamespacePropUtil.setNamespaceProperty(namespaceId, property, value); } + } catch (KeeperException.NoNodeException e) { + // race condition... table namespace no longer exists? This call will throw an exception if the table namespace was deleted: + checkNamespaceId(namespaceId, op); + log.info("Error altering table namespace property", e); + throw new ThriftTableOperationException(namespaceId, namespace, op, TableOperationExceptionType.OTHER, "Problem altering table namespaceproperty"); } catch (Exception e) { log.error("Problem altering table namespace property", e); throw new ThriftTableOperationException(namespaceId, namespace, op, TableOperationExceptionType.OTHER, "Problem altering table namespace property"); @@ -1125,7 +1133,9 @@ public class Master implements LiveTServerSet.Listener, TableObserver, CurrentSt switch (op) { case CREATE: { String namespace = ByteBufferUtil.toString(arguments.get(0)); - // TODO security check once namespace permissions exist (ACCUMULO-1479) + if (!security.canCreateNamespace(c, namespace)) + throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED); + checkNotSystemNamespace(namespace, TableOperation.CREATE); checkTableNamespaceName(namespace, TableOperation.CREATE); fate.seedTransaction(opid, new TraceRepo(new CreateTableNamespace(c.getPrincipal(), namespace, options)), autoCleanup); @@ -1135,11 +1145,14 @@ public class Master implements LiveTServerSet.Listener, TableObserver, CurrentSt String oldName = ByteBufferUtil.toString(arguments.get(0)); String newName = ByteBufferUtil.toString(arguments.get(1)); - // TODO security check (ACCUMULO-1479) String namespaceId = checkNamespaceId(oldName, TableOperation.RENAME); + checkNotSystemNamespace(oldName, TableOperation.RENAME); checkNotSystemNamespace(newName, TableOperation.RENAME); checkTableNamespaceName(newName, TableOperation.RENAME); + if (!security.canRenameNamespace(c, namespaceId, oldName, newName)) + throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED); + fate.seedTransaction(opid, new TraceRepo(new RenameTableNamespace(namespaceId, oldName, newName)), autoCleanup); break; } @@ -1147,7 +1160,9 @@ public class Master implements LiveTServerSet.Listener, TableObserver, CurrentSt String namespace = ByteBufferUtil.toString(arguments.get(0)); checkNotSystemNamespace(namespace, TableOperation.DELETE); String namespaceId = checkNamespaceId(namespace, TableOperation.DELETE); - // TODO security check (ACCUMULO-1479) + if (!security.canDeleteNamespace(c, namespaceId)) + throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED); + fate.seedTransaction(opid, new TraceRepo(new DeleteTableNamespace(namespaceId)), autoCleanup); break; } @@ -1156,7 +1171,8 @@ public class Master implements LiveTServerSet.Listener, TableObserver, CurrentSt String namespace = ByteBufferUtil.toString(arguments.get(1)); checkNotSystemNamespace(namespace, TableOperation.CLONE); checkTableNamespaceName(namespace, TableOperation.CLONE); - // TODO security check (ACCUMULO-1479) + if (!security.canCloneNamespace(c, namespaceId, namespace)) + throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED); Map propertiesToSet = new HashMap(); Set propertiesToExclude = new HashSet(); http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneTableNamespace.java ---------------------------------------------------------------------- diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneTableNamespace.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneTableNamespace.java index 9b661f2..ffa1448 100644 --- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneTableNamespace.java +++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CloneTableNamespace.java @@ -23,10 +23,14 @@ import java.util.Set; import org.apache.accumulo.core.client.Instance; import org.apache.accumulo.core.client.impl.Tables; import org.apache.accumulo.core.client.impl.thrift.TableOperation; +import org.apache.accumulo.core.client.impl.thrift.ThriftSecurityException; +import org.apache.accumulo.core.security.TableNamespacePermission; import org.apache.accumulo.fate.Repo; import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy; import org.apache.accumulo.master.Master; import org.apache.accumulo.server.client.HdfsZooInstance; +import org.apache.accumulo.server.security.AuditedSecurityOperation; +import org.apache.accumulo.server.security.SystemCredentials; import org.apache.accumulo.server.tables.TableManager; import org.apache.log4j.Logger; @@ -134,15 +138,18 @@ class CloneNamespacePermissions extends MasterRepo { @Override public Repo call(long tid, Master environment) throws Exception { - // TODO add table namespace permissions (ACCUMULO-1479) - // give all table permissions to the creator - /* - * for (TablePermission permission : TablePermission.values()) { try { - * AuditedSecurityOperation.getInstance().grantTablePermission(SecurityConstants.getSystemCredentials(), cloneInfo.user, cloneInfo.newId, permission); } - * catch (ThriftSecurityException e) { Logger.getLogger(FinishCloneTableNamespace.class).error(e.getMessage(), e); throw e; } } - */ - - // setup permissions in zookeeper before table info in zookeeper + // give all table namespace permissions to the creator + for (TableNamespacePermission permission : TableNamespacePermission.values()) { + try { + AuditedSecurityOperation.getInstance().grantTableNamespacePermission(SystemCredentials.get().toThrift(environment.getInstance()), cloneInfo.user, + cloneInfo.newId, permission); + } catch (ThriftSecurityException e) { + Logger.getLogger(FinishCloneTableNamespace.class).error(e.getMessage(), e); + throw e; + } + } + + // setup permissions in zookeeper before table namespace info in zookeeper // this way concurrent users will not get a spurious pemission denied // error return new CloneNamespaceZookeeper(cloneInfo); http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/server/master/src/main/java/org/apache/accumulo/master/tableOps/CreateTableNamespace.java ---------------------------------------------------------------------- diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CreateTableNamespace.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CreateTableNamespace.java index d6c6fc4..247ae56 100644 --- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CreateTableNamespace.java +++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CreateTableNamespace.java @@ -23,9 +23,14 @@ import java.util.Map.Entry; import org.apache.accumulo.core.client.Instance; import org.apache.accumulo.core.client.impl.Tables; import org.apache.accumulo.core.client.impl.thrift.TableOperation; +import org.apache.accumulo.core.client.impl.thrift.ThriftSecurityException; +import org.apache.accumulo.core.security.TableNamespacePermission; import org.apache.accumulo.fate.Repo; import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy; import org.apache.accumulo.master.Master; +import org.apache.accumulo.server.security.AuditedSecurityOperation; +import org.apache.accumulo.server.security.SecurityOperation; +import org.apache.accumulo.server.security.SystemCredentials; import org.apache.accumulo.server.tables.TableManager; import org.apache.accumulo.server.util.NamespacePropUtil; import org.apache.log4j.Logger; @@ -135,14 +140,17 @@ class SetupNamespacePermissions extends MasterRepo { @Override public Repo call(long tid, Master env) throws Exception { - // TODO implement once namespace permissions exist (ACCUMULO-1479) - - // give all table permissions to the creator - /* - * SecurityOperation security = AuditedSecurityOperation.getInstance(); for (TableNamespacePermission permission : TableNamespacePermission.values()) { try - * { security.grantTableNamespacePermission(SecurityConstants.getSystemCredentials(), tableNamespaceInfo.user, tableNamespaceInfo.tableId, permission); } - * catch (ThriftSecurityException e) { Logger.getLogger(FinishCreateTableNamespace.class).error(e.getMessage(), e); throw e; } } - */ + // give all table namespace permissions to the creator + SecurityOperation security = AuditedSecurityOperation.getInstance(); + for (TableNamespacePermission permission : TableNamespacePermission.values()) { + try { + security.grantTableNamespacePermission(SystemCredentials.get().toThrift(env.getInstance()), tableNamespaceInfo.user, tableNamespaceInfo.namespaceId, + permission); + } catch (ThriftSecurityException e) { + Logger.getLogger(FinishCreateTableNamespace.class).error(e.getMessage(), e); + throw e; + } + } // setup permissions in zookeeper before table info in zookeeper // this way concurrent users will not get a spurious permission denied http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/server/master/src/main/java/org/apache/accumulo/master/tableOps/DeleteTableNamespace.java ---------------------------------------------------------------------- diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/DeleteTableNamespace.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/DeleteTableNamespace.java index 5013a2f..bd8e5c3 100644 --- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/DeleteTableNamespace.java +++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/DeleteTableNamespace.java @@ -18,8 +18,11 @@ package org.apache.accumulo.master.tableOps; import org.apache.accumulo.core.client.impl.Tables; import org.apache.accumulo.core.client.impl.thrift.TableOperation; +import org.apache.accumulo.core.client.impl.thrift.ThriftSecurityException; import org.apache.accumulo.fate.Repo; import org.apache.accumulo.master.Master; +import org.apache.accumulo.server.security.AuditedSecurityOperation; +import org.apache.accumulo.server.security.SystemCredentials; import org.apache.accumulo.server.tables.TableManager; import org.apache.log4j.Logger; @@ -51,11 +54,12 @@ class NamespaceCleanUp extends MasterRepo { } Tables.clearCache(master.getInstance()); - // TODO remove any permissions associated with this once they exist (ACCUMULO-1479) - /* - * try { AuditedSecurityOperation.getInstance().deleteTable(SecurityConstants.getSystemCredentials(), namespaceName); } catch (ThriftSecurityException e) { - * log.error(e.getMessage(), e); } - */ + // remove any permissions associated with this table namespace + try { + AuditedSecurityOperation.getInstance().deleteTableNamespace(SystemCredentials.get().toThrift(master.getInstance()), namespaceId); + } catch (ThriftSecurityException e) { + log.error(e.getMessage(), e); + } Utils.unreserveTableNamespace(namespaceId, id, true); http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/server/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java ---------------------------------------------------------------------- diff --git a/server/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java b/server/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java deleted file mode 100644 index 7590d76..0000000 --- a/server/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.accumulo.server.conf; - -import org.apache.accumulo.core.client.impl.Tables; -import org.apache.accumulo.core.conf.AccumuloConfiguration; - - -/** - * Used by TableConfiguration to dynamically get the TableNamespaceConfiguration if the namespace changes - */ -public class TableParentConfiguration extends TableNamespaceConfiguration { - - private String tableId; - - public TableParentConfiguration(String tableId, AccumuloConfiguration parent) { - super(null, parent); - this.tableId = tableId; - this.namespaceId = getNamespaceId(); - } - - @Override - protected String getNamespaceId() { - this.namespaceId = Tables.getNamespace(inst, tableId); - return this.namespaceId; - } -} http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java ---------------------------------------------------------------------- diff --git a/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java b/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java index 663fa44..792ba3e 100644 --- a/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java +++ b/test/src/test/java/org/apache/accumulo/test/ShellServerIT.java @@ -873,6 +873,11 @@ public class ShellServerIT extends SimpleMacIT { exec("setiter -tn thing2 -scan -class org.apache.accumulo.core.iterators.user.SummingCombiner -p 10 -n name", true); exec("listiter -tn thing2 -scan", true, "Summing", true); exec("deleteiter -tn thing2 -n name -scan", true); + exec("createuser dude"); + exec("pass"); + exec("pass"); + exec("grant Namespace.CREATE_TABLE -tn thing2 -u dude", true); + exec("revoke Namespace.CREATE_TABLE -tn thing2 -u dude", true); // properties override and such exec("config -tn thing2 -s table.file.max=44444", true); http://git-wip-us.apache.org/repos/asf/accumulo/blob/14fb2571/test/src/test/java/org/apache/accumulo/test/TableNamespacesIT.java ---------------------------------------------------------------------- diff --git a/test/src/test/java/org/apache/accumulo/test/TableNamespacesIT.java b/test/src/test/java/org/apache/accumulo/test/TableNamespacesIT.java index b779152..1a52f72 100644 --- a/test/src/test/java/org/apache/accumulo/test/TableNamespacesIT.java +++ b/test/src/test/java/org/apache/accumulo/test/TableNamespacesIT.java @@ -23,6 +23,7 @@ import static org.junit.Assert.fail; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Random; @@ -51,6 +52,7 @@ import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.iterators.Filter; import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; import org.apache.accumulo.core.security.Authorizations; +import org.apache.accumulo.core.security.SystemPermission; import org.apache.accumulo.core.security.TableNamespacePermission; import org.apache.accumulo.core.util.UtilWaitThread; import org.apache.accumulo.examples.simple.constraints.NumericValueConstraint; @@ -82,8 +84,6 @@ public class TableNamespacesIT { /** * This test creates a table without specifying a namespace. In this case, it puts the table into the default namespace. - * - * @throws Exception */ @Test public void testDefaultNamespace() throws Exception { @@ -99,8 +99,6 @@ public class TableNamespacesIT { * This test creates a new namespace "testing" and a table "testing.table1" which puts "table1" into the "testing" namespace. Then we create "testing.table2" * which creates "table2" and puts it into "testing" as well. Then we make sure that you can't delete a namespace with tables in it, and then we delete the * tables and delete the namespace. - * - * @throws Exception */ @Test public void testCreateAndDeleteNamespace() throws Exception { @@ -148,8 +146,6 @@ public class TableNamespacesIT { * Checks to make sure namespace-level properties are overridden by table-level properties. * * Checks to see if the default namespace's properties work as well. - * - * @throws Exception */ @Test @@ -216,21 +212,8 @@ public class TableNamespacesIT { } /** - * This test creates a new user and a namespace. It checks to make sure the user can't modify anything in the namespace at first, then it grants the user - * permissions and makes sure that they can modify the namespace. Then it also checks if the user has the correct permissions on tables both already existing - * in the namespace and ones they create. - * - * @throws Exception - */ - @Test - public void testNamespacePermissions() throws Exception { - // TODO make the test once namespace-level permissions are implemented. (ACCUMULO-1479) - } - - /** * This test renames and clones two separate table into different namespaces. different namespace. * - * @throws Exception */ @Test public void testRenameAndCloneTableToNewNamespace() throws Exception { @@ -413,6 +396,7 @@ public class TableNamespacesIT { /** <<<<<<< HEAD +<<<<<<< HEAD * Tests that when a table moves to a new namespace that it's properties inherit from the new namespace and not the old one */ @Test @@ -452,6 +436,10 @@ public class TableNamespacesIT { } /** * Tests new Namespace permissions as well as modifications to Table permissions because of namespaces +======= + * Tests new Namespace permissions as well as modifications to Table permissions because of namespaces. Checks each permission to first make sure the user + * doesn't have permission to perform the action, then root grants them the permission and we check to make sure they could perform the action. +>>>>>>> ACCUMULO-1479 finished initial implementation of table namespace permissions, including tests */ @Test public void testPermissions() throws Exception { @@ -460,9 +448,9 @@ public class TableNamespacesIT { PasswordToken pass = new PasswordToken(secret); String n1 = "namespace1"; - + String user1 = "dude"; - + c.tableNamespaceOperations().create(n1); c.tableOperations().create(n1 + ".table1"); @@ -478,9 +466,121 @@ public class TableNamespacesIT { } c.securityOperations().grantTableNamespacePermission(user1, n1, TableNamespacePermission.CREATE_TABLE); - user1Con.tableOperations().create(n1 + ".table2"); assertTrue(c.tableOperations().list().contains(n1 + ".table2")); + c.securityOperations().revokeTableNamespacePermission(user1, n1, TableNamespacePermission.CREATE_TABLE); + + try { + user1Con.tableOperations().delete(n1 + ".table1"); + fail(); + } catch (AccumuloSecurityException e) { + // should happen + } + + c.securityOperations().grantTableNamespacePermission(user1, n1, TableNamespacePermission.DROP_TABLE); + user1Con.tableOperations().delete(n1 + ".table1"); + assertTrue(!c.tableOperations().list().contains(n1 + ".table1")); + c.securityOperations().revokeTableNamespacePermission(user1, n1, TableNamespacePermission.DROP_TABLE); + + c.tableOperations().create(n1 + ".t"); + BatchWriter bw = c.createBatchWriter(n1 + ".t", null); + Mutation m = new Mutation("row"); + m.put("cf", "cq", "value"); + bw.addMutation(m); + bw.close(); + + Iterator> i = user1Con.createScanner(n1 + ".t", new Authorizations()).iterator(); + try { + i.next(); + fail(); + } catch (RuntimeException e) { + // yup + } + + m = new Mutation("user1"); + m.put("cf", "cq", "turtles"); + bw = user1Con.createBatchWriter(n1 + ".t", null); + try { + bw.addMutation(m); + bw.close(); + fail(); + } catch (MutationsRejectedException e) { + // good + } + + c.securityOperations().grantTableNamespacePermission(user1, n1, TableNamespacePermission.READ); + i = user1Con.createScanner(n1 + ".t", new Authorizations()).iterator(); + assertTrue(i.hasNext()); + c.securityOperations().revokeTableNamespacePermission(user1, n1, TableNamespacePermission.READ); + + c.securityOperations().grantTableNamespacePermission(user1, n1, TableNamespacePermission.WRITE); + m = new Mutation("user1"); + m.put("cf", "cq", "turtles"); + bw = user1Con.createBatchWriter(n1 + ".t", null); + bw.addMutation(m); + bw.close(); + c.securityOperations().revokeTableNamespacePermission(user1, n1, TableNamespacePermission.WRITE); + + try { + user1Con.tableOperations().setProperty(n1 + ".t", Property.TABLE_FILE_MAX.getKey(), "42"); + fail(); + } catch (AccumuloSecurityException e) {} + + c.securityOperations().grantTableNamespacePermission(user1, n1, TableNamespacePermission.ALTER_TABLE); + user1Con.tableOperations().setProperty(n1 + ".t", Property.TABLE_FILE_MAX.getKey(), "42"); + user1Con.tableOperations().removeProperty(n1 + ".t", Property.TABLE_FILE_MAX.getKey()); + c.securityOperations().revokeTableNamespacePermission(user1, n1, TableNamespacePermission.ALTER_TABLE); + + try { + user1Con.tableNamespaceOperations().setProperty(n1, Property.TABLE_FILE_MAX.getKey(), "55"); + fail(); + } catch (AccumuloSecurityException e) {} + + c.securityOperations().grantTableNamespacePermission(user1, n1, TableNamespacePermission.ALTER_NAMESPACE); + user1Con.tableNamespaceOperations().setProperty(n1, Property.TABLE_FILE_MAX.getKey(), "42"); + user1Con.tableNamespaceOperations().removeProperty(n1, Property.TABLE_FILE_MAX.getKey()); + c.securityOperations().revokeTableNamespacePermission(user1, n1, TableNamespacePermission.ALTER_NAMESPACE); + + String user2 = "guy"; + c.securityOperations().createLocalUser(user2, pass); + try { + user1Con.securityOperations().grantTableNamespacePermission(user2, n1, TableNamespacePermission.ALTER_NAMESPACE); + fail(); + } catch (AccumuloSecurityException e) {} + + c.securityOperations().grantTableNamespacePermission(user1, n1, TableNamespacePermission.GRANT); + user1Con.securityOperations().grantTableNamespacePermission(user2, n1, TableNamespacePermission.ALTER_NAMESPACE); + user1Con.securityOperations().revokeTableNamespacePermission(user2, n1, TableNamespacePermission.ALTER_NAMESPACE); + c.securityOperations().revokeTableNamespacePermission(user1, n1, TableNamespacePermission.GRANT); + + String n2 = "namespace2"; + try { + user1Con.tableNamespaceOperations().create(n2); + fail(); + } catch (AccumuloSecurityException e) {} + + c.securityOperations().grantSystemPermission(user1, SystemPermission.CREATE_NAMESPACE); + user1Con.tableNamespaceOperations().create(n2); + c.securityOperations().revokeSystemPermission(user1, SystemPermission.CREATE_NAMESPACE); + + try { + user1Con.tableNamespaceOperations().delete(n2); + fail(); + } catch (AccumuloSecurityException e) {} + + c.securityOperations().grantSystemPermission(user1, SystemPermission.DROP_NAMESPACE); + user1Con.tableNamespaceOperations().delete(n2); + c.securityOperations().revokeSystemPermission(user1, SystemPermission.DROP_NAMESPACE); + + try { + user1Con.tableNamespaceOperations().setProperty(n1, Property.TABLE_FILE_MAX.getKey(), "33"); + fail(); + } catch (AccumuloSecurityException e) {} + + c.securityOperations().grantSystemPermission(user1, SystemPermission.ALTER_NAMESPACE); + user1Con.tableNamespaceOperations().setProperty(n1, Property.TABLE_FILE_MAX.getKey(), "33"); + user1Con.tableNamespaceOperations().removeProperty(n1, Property.TABLE_FILE_MAX.getKey()); + c.securityOperations().revokeSystemPermission(user1, SystemPermission.ALTER_NAMESPACE); } private boolean checkTableHasProp(Connector c, String t, String propKey, String propVal) throws AccumuloException, TableNotFoundException {