You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by ct...@apache.org on 2013/12/05 00:58:52 UTC

[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 <ta...@gmail.com>
Authored: Fri Aug 2 13:32:42 2013 -0400
Committer: Christopher Tubbs <ct...@apache.org>
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<Entry<String,String>> set = namespace.getSettings().entrySet();
+    Set<Entry<String,String>> set = namespace.settings.entrySet();
     Iterator<Entry<String,String>> entries = set.iterator();
     while (entries.hasNext()) {
       Entry<String,String> 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<String,String> getSettings() {
-    return settings;
-  }
-  
   public List<String> getTables(MockAccumulo acu) {
     List<String> l = new LinkedList<String>();
     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<String,String> 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<String,String> 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<String,String> 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<String,String> 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<String,String> 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<IteratorScope> scope = new HashSet<IteratorScope>();
+    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<String,String> 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<String,String> 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<String,Set<TableNamespacePermission>> tableNamespacePerms = new HashMap<String,Set<TableNamespacePermission>>();
+    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<String,Set<TablePermission>> entry : tablePerms.entrySet())
         createTablePerm(rootuser, entry.getKey(), entry.getValue());
+      for (Entry<String,Set<TableNamespacePermission>> 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<TableNamespacePermission> 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<Master>(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<Master>(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<Master>(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<String,String> propertiesToSet = new HashMap<String,String>();
           Set<String> propertiesToExclude = new HashSet<String>();

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<Master> 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<Master> 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<Entry<Key,Value>> 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 {