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:03 UTC

[11/50] [abbrv] ACCUMULO-1479 implemented most of Table Namespace Permissions, doesnt entirely work, not well tested

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/core/src/main/java/org/apache/accumulo/core/client/impl/thrift/SecurityErrorCode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/client/impl/thrift/SecurityErrorCode.java b/core/src/main/java/org/apache/accumulo/core/client/impl/thrift/SecurityErrorCode.java
index b706ce8..9bf554f 100644
--- a/core/src/main/java/org/apache/accumulo/core/client/impl/thrift/SecurityErrorCode.java
+++ b/core/src/main/java/org/apache/accumulo/core/client/impl/thrift/SecurityErrorCode.java
@@ -45,7 +45,8 @@ import org.apache.thrift.TEnum;
   PERMISSIONHANDLER_FAILED(14),
   TOKEN_EXPIRED(15),
   SERIALIZATION_ERROR(16),
-  INSUFFICIENT_PROPERTIES(17);
+  INSUFFICIENT_PROPERTIES(17),
+  TABLE_NAMESPACE_DOESNT_EXIST(18);
 
   private final int value;
 
@@ -102,6 +103,8 @@ import org.apache.thrift.TEnum;
         return SERIALIZATION_ERROR;
       case 17:
         return INSUFFICIENT_PROPERTIES;
+      case 18:
+        return TABLE_NAMESPACE_DOESNT_EXIST;
       default:
         return null;
     }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java b/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java
index 37e8379..f96abad 100644
--- a/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java
+++ b/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java
@@ -32,6 +32,7 @@ import org.apache.accumulo.core.metadata.MetadataTable;
 import org.apache.accumulo.core.metadata.RootTable;
 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.security.TablePermission;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.io.Text;
@@ -100,7 +101,7 @@ public class MockAccumulo {
   public void createNamespace(String username, String namespace) {
     if (!namespaceExists(namespace)) {
       MockTableNamespace n = new MockTableNamespace();
-      n.userPermissions.put(username, EnumSet.allOf(TablePermission.class));
+      n.userPermissions.put(username, EnumSet.allOf(TableNamespacePermission.class));
       namespaces.put(namespace, n);
     }
   }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/core/src/main/java/org/apache/accumulo/core/client/mock/MockSecurityOperations.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/client/mock/MockSecurityOperations.java b/core/src/main/java/org/apache/accumulo/core/client/mock/MockSecurityOperations.java
index 765cda9..dd48b52 100644
--- a/core/src/main/java/org/apache/accumulo/core/client/mock/MockSecurityOperations.java
+++ b/core/src/main/java/org/apache/accumulo/core/client/mock/MockSecurityOperations.java
@@ -27,6 +27,7 @@ import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
 import org.apache.accumulo.core.client.security.tokens.PasswordToken;
 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.security.TablePermission;
 
 public class MockSecurityOperations implements SecurityOperations {
@@ -128,6 +129,17 @@ public class MockSecurityOperations implements SecurityOperations {
   }
   
   @Override
+  public boolean hasTableNamespacePermission(String principal, String tableNamespace, TableNamespacePermission perm) throws AccumuloException, AccumuloSecurityException {
+    MockTableNamespace namespace = acu.namespaces.get(tableNamespace);
+    if (namespace == null)
+      throw new AccumuloSecurityException(tableNamespace, SecurityErrorCode.TABLE_DOESNT_EXIST);
+    EnumSet<TableNamespacePermission> perms = namespace.userPermissions.get(principal);
+    if (perms == null)
+      return false;
+    return perms.contains(perm);
+  }
+  
+  @Override
   public void grantSystemPermission(String principal, SystemPermission permission) throws AccumuloException, AccumuloSecurityException {
     MockUser user = acu.users.get(principal);
     if (user != null)
@@ -151,6 +163,20 @@ public class MockSecurityOperations implements SecurityOperations {
   }
   
   @Override
+  public void grantTableNamespacePermission(String principal, String tableNamespace, TableNamespacePermission permission) throws AccumuloException, AccumuloSecurityException {
+    if (acu.users.get(principal) == null)
+      throw new AccumuloSecurityException(principal, SecurityErrorCode.USER_DOESNT_EXIST);
+    MockTableNamespace namespace = acu.namespaces.get(tableNamespace);
+    if (namespace == null)
+      throw new AccumuloSecurityException(tableNamespace, SecurityErrorCode.TABLE_DOESNT_EXIST);
+    EnumSet<TableNamespacePermission> perms = namespace.userPermissions.get(principal);
+    if (perms == null)
+      namespace.userPermissions.put(principal, EnumSet.of(permission));
+    else
+      perms.add(permission);
+  }
+  
+  @Override
   public void revokeSystemPermission(String principal, SystemPermission permission) throws AccumuloException, AccumuloSecurityException {
     MockUser user = acu.users.get(principal);
     if (user != null)
@@ -172,6 +198,19 @@ public class MockSecurityOperations implements SecurityOperations {
     
   }
   
+  @Override
+  public void revokeTableNamespacePermission(String principal, String tableNamespace, TableNamespacePermission permission) throws AccumuloException, AccumuloSecurityException {
+    if (acu.users.get(principal) == null)
+      throw new AccumuloSecurityException(principal, SecurityErrorCode.USER_DOESNT_EXIST);
+    MockTableNamespace namespace = acu.namespaces.get(tableNamespace);
+    if (namespace == null)
+      throw new AccumuloSecurityException(tableNamespace, SecurityErrorCode.TABLE_DOESNT_EXIST);
+    EnumSet<TableNamespacePermission> perms = namespace.userPermissions.get(principal);
+    if (perms != null)
+      perms.remove(permission);
+    
+  }
+  
   @Deprecated
   @Override
   public Set<String> listUsers() throws AccumuloException, AccumuloSecurityException {

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/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 2a32165..beec4db 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
@@ -25,13 +25,13 @@ import java.util.Map.Entry;
 
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.Property;
-import org.apache.accumulo.core.security.TablePermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 
 
 public class MockTableNamespace {
   
   final Map<String,String> settings;
-  Map<String,EnumSet<TablePermission>> userPermissions = new HashMap<String,EnumSet<TablePermission>>();
+  Map<String,EnumSet<TableNamespacePermission>> userPermissions = new HashMap<String,EnumSet<TableNamespacePermission>>();
   
   public MockTableNamespace() {
     settings = new HashMap<String,String>();

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/core/src/main/java/org/apache/accumulo/core/client/security/SecurityErrorCode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/client/security/SecurityErrorCode.java b/core/src/main/java/org/apache/accumulo/core/client/security/SecurityErrorCode.java
index fb51387..f1ea539 100644
--- a/core/src/main/java/org/apache/accumulo/core/client/security/SecurityErrorCode.java
+++ b/core/src/main/java/org/apache/accumulo/core/client/security/SecurityErrorCode.java
@@ -37,5 +37,6 @@ public enum SecurityErrorCode {
   PERMISSIONHANDLER_FAILED,
   TOKEN_EXPIRED,
   SERIALIZATION_ERROR,
-  INSUFFICIENT_PROPERTIES;
+  INSUFFICIENT_PROPERTIES,
+  TABLE_NAMESPACE_DOESNT_EXIST;
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/core/src/main/java/org/apache/accumulo/core/security/SystemPermission.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/security/SystemPermission.java b/core/src/main/java/org/apache/accumulo/core/security/SystemPermission.java
index 699396e..6bdb8e6 100644
--- a/core/src/main/java/org/apache/accumulo/core/security/SystemPermission.java
+++ b/core/src/main/java/org/apache/accumulo/core/security/SystemPermission.java
@@ -29,7 +29,10 @@ public enum SystemPermission {
   CREATE_USER((byte) 4),
   DROP_USER((byte) 5),
   ALTER_USER((byte) 6),
-  SYSTEM((byte) 7);
+  SYSTEM((byte) 7),
+  CREATE_NAMESPACE((byte) 8),
+  DROP_NAMESPACE((byte) 9),
+  ALTER_NAMESPACE((byte) 10);
   
   private byte permID;
   

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/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
new file mode 100644
index 0000000..565a81a
--- /dev/null
+++ b/core/src/main/java/org/apache/accumulo/core/security/TableNamespacePermission.java
@@ -0,0 +1,67 @@
+/*
+ * 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.security;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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),
+  GRANT((byte) 3),
+  ALTER_TABLE((byte) 4),
+  CREATE_TABLE((byte) 5),
+  DROP_TABLE((byte) 6),
+  BULK_IMPORT((byte) 7);
+  
+  final private byte permID;
+  
+  final private static TableNamespacePermission mapping[] = new TableNamespacePermission[8];
+  static {
+    for (TableNamespacePermission perm : TableNamespacePermission.values())
+      mapping[perm.permID] = perm;
+  }
+  
+  private TableNamespacePermission(byte id) {
+    this.permID = id;
+  }
+  
+  public byte getId() {
+    return this.permID;
+  }
+  
+  public static List<String> printableValues() {
+    TableNamespacePermission[] a = TableNamespacePermission.values();
+    
+    List<String> list = new ArrayList<String>(a.length);
+    
+    for (TableNamespacePermission p : a)
+      list.add("Namespace." + p);
+    
+    return list;
+  }
+  
+  public static TableNamespacePermission getPermissionById(byte id) {
+    TableNamespacePermission result = mapping[id];
+    if (result != null)
+      return result;
+    throw new IndexOutOfBoundsException("No such permission");
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GrantCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GrantCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GrantCommand.java
index f3e7200..9f6e7e4 100644
--- a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GrantCommand.java
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GrantCommand.java
@@ -21,6 +21,7 @@ import java.util.Set;
 
 import org.apache.accumulo.core.security.SystemPermission;
 import org.apache.accumulo.core.security.TablePermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 import org.apache.accumulo.core.util.BadArgumentException;
 import org.apache.accumulo.core.util.shell.Shell;
 import org.apache.accumulo.core.util.shell.Shell.Command;
@@ -53,6 +54,17 @@ public class GrantCommand extends TableOperation {
       }
     } else if (permission[0].equalsIgnoreCase("Table")) {
       super.execute(fullCommand, cl, shellState);
+    } else if (permission[0].equalsIgnoreCase("Namespace")) {
+      if (cl.hasOption(optTableNamespace.getOpt())) {
+        try {
+          shellState.getConnector().securityOperations()
+              .grantTableNamespacePermission(user, cl.getOptionValue(optTableNamespace.getOpt()), TableNamespacePermission.valueOf(permission[1]));
+        } catch (IllegalArgumentException e) {
+          throw new BadArgumentException("No such table namespace permission", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
+        }
+      } else {
+        throw new BadArgumentException("No Table Namespace specified to apply permission to", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
+      }
     } else {
       throw new BadArgumentException("Unrecognized permission", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
     }
@@ -71,7 +83,7 @@ public class GrantCommand extends TableOperation {
   
   @Override
   public String description() {
-    return "grants system or table permissions for a user";
+    return "grants system, table, or table namespace permissions for a user";
   }
   
   @Override
@@ -84,6 +96,7 @@ public class GrantCommand extends TableOperation {
     final Token cmd = new Token(getName());
     cmd.addSubcommand(new Token(TablePermission.printableValues()));
     cmd.addSubcommand(new Token(SystemPermission.printableValues()));
+    cmd.addSubcommand(new Token(TableNamespacePermission.printableValues()));
     root.addSubcommand(cmd);
   }
   
@@ -96,9 +109,13 @@ public class GrantCommand extends TableOperation {
     
     systemOpt = new Option("s", "system", false, "grant a system permission");
     
+    optTableNamespace = new Option(Shell.tableNamespaceOption, "table-namespace", true, "name of a table namespace to operate on");
+    optTableNamespace.setArgName("tableNamespace");
+    
     group.addOption(systemOpt);
     group.addOption(optTableName);
     group.addOption(optTablePattern);
+    group.addOption(optTableNamespace);
     
     o.addOptionGroup(group);
     userOpt = new Option(Shell.userOption, "user", true, "user to operate on");

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RevokeCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RevokeCommand.java b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RevokeCommand.java
index 676284a..cc9cd93 100644
--- a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RevokeCommand.java
+++ b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/RevokeCommand.java
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.util.BadArgumentException;
 import org.apache.accumulo.core.util.shell.Shell;
@@ -53,7 +54,18 @@ public class RevokeCommand extends TableOperation {
       }
     } else if (permission[0].equalsIgnoreCase("Table")) {
       super.execute(fullCommand, cl, shellState);
-    } else {
+    } else if (permission[0].equalsIgnoreCase("Namespace")) {
+      if (cl.hasOption(optTableNamespace.getOpt())) {
+        try {
+          shellState.getConnector().securityOperations()
+              .revokeTableNamespacePermission(user, cl.getOptionValue(optTableNamespace.getOpt()), TableNamespacePermission.valueOf(permission[1]));
+        } catch (IllegalArgumentException e) {
+          throw new BadArgumentException("No such table namespace permission", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
+        }
+      } else {
+        throw new BadArgumentException("No Table Namespace specified to apply permission to", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
+      } 
+    }else {
       throw new BadArgumentException("Unrecognized permission", fullCommand, fullCommand.indexOf(cl.getArgs()[0]));
     }
     return 0;
@@ -84,6 +96,7 @@ public class RevokeCommand extends TableOperation {
     final Token cmd = new Token(getName());
     cmd.addSubcommand(new Token(TablePermission.printableValues()));
     cmd.addSubcommand(new Token(SystemPermission.printableValues()));
+    cmd.addSubcommand(new Token(TableNamespacePermission.printableValues()));
     root.addSubcommand(cmd);
   }
   
@@ -96,9 +109,13 @@ public class RevokeCommand extends TableOperation {
     
     systemOpt = new Option("s", "system", false, "revoke a system permission");
     
+    optTableNamespace = new Option(Shell.tableNamespaceOption, "table-namespace", true, "name of a table namespace to operate on");
+    optTableNamespace.setArgName("tableNamespace");
+        
     group.addOption(systemOpt);
     group.addOption(optTableName);
     group.addOption(optTablePattern);
+    group.addOption(optTableNamespace);
     
     o.addOptionGroup(group);
     userOpt = new Option(Shell.userOption, "user", true, "user to operate on");

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/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 79d78da..25d9d54 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
@@ -21,6 +21,7 @@ import java.io.IOException;
 import org.apache.accumulo.core.client.AccumuloException;
 import org.apache.accumulo.core.client.AccumuloSecurityException;
 import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.util.shell.Shell;
 import org.apache.accumulo.core.util.shell.Shell.Command;
@@ -62,12 +63,29 @@ public class UserPermissionsCommand extends Command {
       runOnce = 0;
     }
     shellState.getReader().println();
+    
+    for (String n : shellState.getConnector().tableNamespaceOperations().list()) {
+      delim = "";
+      for (TableNamespacePermission p : TableNamespacePermission.values()) {
+        if (p != null && shellState.getConnector().securityOperations().hasTableNamespacePermission(user, n, p)) {
+          if (runOnce == 0) {
+            shellState.getReader().print("\nTable Namespace permissions (" + n + "): ");
+            runOnce++;
+          }
+          shellState.getReader().print(delim + "Namespace." + p.name());
+          delim = ", ";
+        }
+      }
+      runOnce = 0;
+    }
+    shellState.getReader().println();
+    
     return 0;
   }
   
   @Override
   public String description() {
-    return "displays a user's system and table permissions";
+    return "displays a user's system, table, and table namespace permissions";
   }
   
   @Override

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/core/src/main/thrift/client.thrift
----------------------------------------------------------------------
diff --git a/core/src/main/thrift/client.thrift b/core/src/main/thrift/client.thrift
index 67f43d8..7c340d7 100644
--- a/core/src/main/thrift/client.thrift
+++ b/core/src/main/thrift/client.thrift
@@ -72,9 +72,10 @@ enum SecurityErrorCode {
     AUTHENTICATOR_FAILED = 12,
     AUTHORIZOR_FAILED = 13,
     PERMISSIONHANDLER_FAILED = 14,
-    TOKEN_EXPIRED = 15
-    SERIALIZATION_ERROR = 16;
-    INSUFFICIENT_PROPERTIES = 17;
+    TOKEN_EXPIRED = 15,
+    SERIALIZATION_ERROR = 16,
+    INSUFFICIENT_PROPERTIES = 17,
+    TABLE_NAMESPACE_DOESNT_EXIST = 18;
 }
 
 exception ThriftSecurityException {
@@ -127,15 +128,18 @@ service ClientService {
     // permissions-related methods
     bool hasSystemPermission(4:trace.TInfo tinfo, 5:security.TCredentials credentials, 2:string principal, 3:byte sysPerm) throws (1:ThriftSecurityException sec)
     bool hasTablePermission(5:trace.TInfo tinfo, 6:security.TCredentials credentials, 2:string principal, 3:string tableName, 4:byte tblPerm) throws (1:ThriftSecurityException sec, 2:ThriftTableOperationException tope)
+    bool hasTableNamespacePermission(1:trace.TInfo tinfo, 2:security.TCredentials credentials, 3:string principal, 4:string tableNamespace, 5:byte tblNspcPerm) throws (1:ThriftSecurityException sec, 2:ThriftTableOperationException tope)
     void grantSystemPermission(4:trace.TInfo tinfo, 5:security.TCredentials credentials, 2:string principal, 3:byte permission) throws (1:ThriftSecurityException sec)
     void revokeSystemPermission(4:trace.TInfo tinfo, 5:security.TCredentials credentials, 2:string principal, 3:byte permission) throws (1:ThriftSecurityException sec)
     void grantTablePermission(5:trace.TInfo tinfo, 6:security.TCredentials credentials, 2:string principal, 3:string tableName, 4:byte permission) throws (1:ThriftSecurityException sec, 2:ThriftTableOperationException tope)
     void revokeTablePermission(5:trace.TInfo tinfo, 6:security.TCredentials credentials, 2:string principal, 3:string tableName, 4:byte permission) throws (1:ThriftSecurityException sec, 2:ThriftTableOperationException tope)
+    void grantTableNamespacePermission(1:trace.TInfo tinfo, 2:security.TCredentials credentials, 3:string principal, 4:string tableNamespace, 5:byte permission) throws (1:ThriftSecurityException sec, 2:ThriftTableOperationException tope)
+    void revokeTableNamespacePermission(1:trace.TInfo tinfo, 2:security.TCredentials credentials, 3:string principal, 4:string tableNamespace, 5:byte permission) throws (1:ThriftSecurityException sec, 2:ThriftTableOperationException tope)
 
     // configuration methods
     map<string, string> getConfiguration(2:trace.TInfo tinfo, 3:security.TCredentials credentials, 1:ConfigurationType type);
     map<string, string> getTableConfiguration(1:trace.TInfo tinfo, 3:security.TCredentials credentials, 2:string tableName) throws (1:ThriftTableOperationException tope);
-    map<string, string> getTableNamespaceConfiguration(1:trace.TInfo tinfo, 3:security.TCredentials credentials, 2:string ns) throws (1:ThriftTableOperationException tope);
+    map<string, string> getTableNamespaceConfiguration(1:trace.TInfo tinfo, 2:security.TCredentials credentials, 3:string ns) throws (1:ThriftTableOperationException tope);
     bool checkClass(1:trace.TInfo tinfo, 4:security.TCredentials credentials, 2:string className, 3:string interfaceMatch);
     bool checkTableClass(1:trace.TInfo tinfo, 5:security.TCredentials credentials, 2:string tableId, 3:string className, 4:string interfaceMatch) throws (1:ThriftSecurityException sec, 2:ThriftTableOperationException tope);
     bool checkTableNamespaceClass(1:trace.TInfo tinfo, 2:security.TCredentials credentials, 3:string namespaceId, 4:string className, 5:string interfaceMatch) throws (1:ThriftSecurityException sec, 2:ThriftTableOperationException tope);

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/server/base/src/main/java/org/apache/accumulo/server/client/ClientServiceHandler.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/client/ClientServiceHandler.java b/server/base/src/main/java/org/apache/accumulo/server/client/ClientServiceHandler.java
index 0421ec1..3148a3d 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/client/ClientServiceHandler.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/client/ClientServiceHandler.java
@@ -53,6 +53,7 @@ import org.apache.accumulo.core.security.Authorizations;
 import org.apache.accumulo.core.security.Credentials;
 import org.apache.accumulo.core.security.SystemPermission;
 import org.apache.accumulo.core.security.TablePermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 import org.apache.accumulo.core.security.thrift.TCredentials;
 import org.apache.accumulo.server.conf.ServerConfiguration;
 import org.apache.accumulo.server.fs.VolumeManager;
@@ -185,6 +186,13 @@ public class ClientServiceHandler implements ClientService.Iface {
   }
 
   @Override
+  public void grantTableNamespacePermission(TInfo tinfo, TCredentials credentials, String user, String tableNamespace, byte permission) throws ThriftSecurityException,
+      ThriftTableOperationException {
+    String namespaceId = checkTableNamespaceId(tableNamespace, TableOperation.PERMISSION);
+    security.grantTableNamespacePermission(credentials, user, namespaceId, TableNamespacePermission.getPermissionById(permission));
+  }
+  
+  @Override
   public void revokeSystemPermission(TInfo tinfo, TCredentials credentials, String user, byte permission) throws ThriftSecurityException {
     security.revokeSystemPermission(credentials, user, SystemPermission.getPermissionById(permission));
   }
@@ -209,6 +217,20 @@ public class ClientServiceHandler implements ClientService.Iface {
   }
 
   @Override
+  public boolean hasTableNamespacePermission(TInfo tinfo, TCredentials credentials, String user, String tableNamespace, byte perm) throws ThriftSecurityException,
+      ThriftTableOperationException {
+    String namespaceId = checkTableNamespaceId(tableNamespace, TableOperation.PERMISSION);
+    return security.hasTableNamespacePermission(credentials, user, namespaceId, TableNamespacePermission.getPermissionById(perm));
+  }
+  
+  @Override
+  public void revokeTableNamespacePermission(TInfo tinfo, TCredentials credentials, String user, String tableNamespace, byte permission) throws ThriftSecurityException,
+      ThriftTableOperationException {
+    String namespaceId = checkTableNamespaceId(tableNamespace, TableOperation.PERMISSION);
+    security.revokeTableNamespacePermission(credentials, user, namespaceId, TableNamespacePermission.getPermissionById(permission));
+  }
+  
+  @Override
   public Set<String> listLocalUsers(TInfo tinfo, TCredentials credentials) throws ThriftSecurityException {
     return security.listUsers(credentials);
   }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/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 f00159c..cad84d0 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
@@ -23,8 +23,10 @@ import java.util.Set;
 
 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;
 import org.apache.accumulo.core.client.admin.SecurityOperationsImpl;
+import org.apache.accumulo.core.client.impl.Tables;
 import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode;
 import org.apache.accumulo.core.client.impl.thrift.ThriftSecurityException;
 import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
@@ -40,6 +42,7 @@ import org.apache.accumulo.core.metadata.RootTable;
 import org.apache.accumulo.core.security.Authorizations;
 import org.apache.accumulo.core.security.Credentials;
 import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.security.thrift.TCredentials;
 import org.apache.accumulo.server.client.HdfsZooInstance;
@@ -304,6 +307,64 @@ public class SecurityOperation {
     }
   }
   
+  /**
+   * Checks if a user has a table namespace permission
+   * 
+   * @return true if a user exists and has permission; false otherwise
+   */
+  protected boolean hasTableNamespacePermission(TCredentials credentials, String tableNamespace, TableNamespacePermission permission, boolean useCached)
+      throws ThriftSecurityException {
+    if (isSystemUser(credentials))
+      return true;
+    return _hasTableNamespacePermission(credentials.getPrincipal(), tableNamespace, permission, useCached);
+  }
+  
+  /**
+   * Checks if a user has a table namespace permission given a tableId
+   * 
+   * @return true if a user exists and has permission; false otherwise
+   */
+  protected boolean hasTableNamespacePermissionForTableId(TCredentials credentials, String tableId, TableNamespacePermission permission, boolean useCached)
+      throws ThriftSecurityException {
+    String tableNamespace = Tables.getNamespace(HdfsZooInstance.getInstance(), tableId);
+    return hasTableNamespacePermission(credentials, tableNamespace, permission, useCached);
+  }
+  
+  /**
+   * Checks if a user has a table namespace permission given a tableName
+   * 
+   * @return true if a user exists and has permission; false otherwise
+   */
+  protected boolean hasTableNamespacePermissionForTableName(TCredentials credentials, String tableName, TableNamespacePermission permission, boolean useCached)
+      throws ThriftSecurityException {
+    String tableNamespace = Tables.extractNamespace(tableName);
+    return hasTableNamespacePermission(credentials, tableNamespace, permission, useCached);
+  }
+  
+  /**
+   * Checks if a user has a table namespace permission<br/>
+   * This cannot check if a system user has permission.
+   * 
+   * @return true if a user exists and has permission; false otherwise
+   */
+  protected boolean _hasTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission, boolean useCached)
+      throws ThriftSecurityException {
+    targetUserExists(user);
+    
+    if (tableNamespace.equals(Constants.SYSTEM_TABLE_NAMESPACE_ID) && permission.equals(TableNamespacePermission.READ))
+      return true;
+    
+    try {
+      if (useCached)
+        return permHandle.hasCachedTableNamespacePermission(user, tableNamespace, permission);
+      return permHandle.hasTableNamespacePermission(user, tableNamespace, permission);
+    } catch (AccumuloSecurityException e) {
+      throw e.asThriftException();
+    } catch (TableNamespaceNotFoundException e) {
+      throw new ThriftSecurityException(user, SecurityErrorCode.TABLE_NAMESPACE_DOESNT_EXIST);
+    }
+  }
+  
   // some people just aren't allowed to ask about other users; here are those who can ask
   private boolean canAskAboutOtherUsers(TCredentials credentials, String user) throws ThriftSecurityException {
     authenticate(credentials);
@@ -325,7 +386,8 @@ public class SecurityOperation {
   
   public boolean canScan(TCredentials credentials, String table) throws ThriftSecurityException {
     authenticate(credentials);
-    return hasTablePermission(credentials, table, TablePermission.READ, true);
+    return hasTablePermission(credentials, table, TablePermission.READ, true)
+        || hasTableNamespacePermissionForTableId(credentials, table, TableNamespacePermission.READ, true);
   }
   
   public boolean canScan(TCredentials credentials, String table, TRange range, List<TColumn> columns, List<IterInfo> ssiList,
@@ -340,20 +402,25 @@ public class SecurityOperation {
   
   public boolean canWrite(TCredentials credentials, String table) throws ThriftSecurityException {
     authenticate(credentials);
-    return hasTablePermission(credentials, table, TablePermission.WRITE, true);
+    return hasTablePermission(credentials, table, TablePermission.WRITE, true)
+        || hasTableNamespacePermissionForTableId(credentials, table, TableNamespacePermission.WRITE, true);
   }
   
   public boolean canConditionallyUpdate(TCredentials credentials, String tableID, List<ByteBuffer> authorizations) throws ThriftSecurityException {
     
     authenticate(credentials);
     
-    return hasTablePermission(credentials, tableID, TablePermission.WRITE, true) && hasTablePermission(credentials, tableID, TablePermission.READ, true);
+    return (hasTablePermission(credentials, tableID, TablePermission.WRITE, true) || hasTableNamespacePermissionForTableId(credentials, tableID,
+        TableNamespacePermission.WRITE, true))
+        && (hasTablePermission(credentials, tableID, TablePermission.READ, true) || hasTableNamespacePermissionForTableId(credentials, tableID,
+            TableNamespacePermission.READ, true));
   }
   
   public boolean canSplitTablet(TCredentials credentials, String table) throws ThriftSecurityException {
     authenticate(credentials);
     return hasSystemPermission(credentials, SystemPermission.ALTER_TABLE, false) || hasSystemPermission(credentials, SystemPermission.SYSTEM, false)
-        || hasTablePermission(credentials, table, TablePermission.ALTER_TABLE, false);
+        || hasTablePermission(credentials, table, TablePermission.ALTER_TABLE, false)
+        || hasTableNamespacePermissionForTableId(credentials, table, TableNamespacePermission.ALTER_TABLE, false);
   }
   
   /**
@@ -366,16 +433,19 @@ public class SecurityOperation {
   
   public boolean canFlush(TCredentials c, String tableId) throws ThriftSecurityException {
     authenticate(c);
-    return hasTablePermission(c, tableId, TablePermission.WRITE, false) || hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false);
+    return hasTablePermission(c, tableId, TablePermission.WRITE, false) || hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.ALTER_TABLE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.WRITE, false);
   }
   
   public boolean canAlterTable(TCredentials c, String tableId) throws ThriftSecurityException {
     authenticate(c);
-    return hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false) || hasSystemPermission(c, SystemPermission.ALTER_TABLE, false);
+    return hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false) || hasSystemPermission(c, SystemPermission.ALTER_TABLE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.ALTER_TABLE, false);
   }
   
   public boolean canCreateTable(TCredentials c, String tableName) throws ThriftSecurityException {
-    return canCreateTable(c);
+    return canCreateTable(c) || hasTableNamespacePermissionForTableName(c, tableName, TableNamespacePermission.CREATE_TABLE, false);
   }
   
   public boolean canCreateTable(TCredentials c) throws ThriftSecurityException {
@@ -385,34 +455,41 @@ public class SecurityOperation {
   
   public boolean canRenameTable(TCredentials c, String tableId, String oldTableName, String newTableName) throws ThriftSecurityException {
     authenticate(c);
-    return hasSystemPermission(c, SystemPermission.ALTER_TABLE, false) || hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false);
+    return hasSystemPermission(c, SystemPermission.ALTER_TABLE, false) || hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.ALTER_TABLE, false);
   }
   
   public boolean canCloneTable(TCredentials c, String tableId, String tableName) throws ThriftSecurityException {
     authenticate(c);
-    return hasSystemPermission(c, SystemPermission.CREATE_TABLE, false) && hasTablePermission(c, tableId, TablePermission.READ, false);
+    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));
   }
   
   public boolean canDeleteTable(TCredentials c, String tableId) throws ThriftSecurityException {
     authenticate(c);
-    return hasSystemPermission(c, SystemPermission.DROP_TABLE, false) || hasTablePermission(c, tableId, TablePermission.DROP_TABLE, false);
+    return hasSystemPermission(c, SystemPermission.DROP_TABLE, false) || hasTablePermission(c, tableId, TablePermission.DROP_TABLE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.DROP_TABLE, false);
   }
   
   public boolean canOnlineOfflineTable(TCredentials c, String tableId, TableOperation op) throws ThriftSecurityException {
     authenticate(c);
     return hasSystemPermission(c, SystemPermission.SYSTEM, false) || hasSystemPermission(c, SystemPermission.ALTER_TABLE, false)
-        || hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false);
+        || hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.ALTER_TABLE, false);
   }
   
   public boolean canMerge(TCredentials c, String tableId) throws ThriftSecurityException {
     authenticate(c);
     return hasSystemPermission(c, SystemPermission.SYSTEM, false) || hasSystemPermission(c, SystemPermission.ALTER_TABLE, false)
-        || hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false);
+        || hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.ALTER_TABLE, false);
   }
   
   public boolean canDeleteRange(TCredentials c, String tableId, String tableName, Text startRow, Text endRow) throws ThriftSecurityException {
     authenticate(c);
-    return hasSystemPermission(c, SystemPermission.SYSTEM, false) || hasTablePermission(c, tableId, TablePermission.WRITE, false);
+    return hasSystemPermission(c, SystemPermission.SYSTEM, false) || hasTablePermission(c, tableId, TablePermission.WRITE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.WRITE, false);
   }
   
   public boolean canBulkImport(TCredentials c, String tableId, String tableName, String dir, String failDir) throws ThriftSecurityException {
@@ -421,13 +498,16 @@ public class SecurityOperation {
   
   public boolean canBulkImport(TCredentials c, String tableId) throws ThriftSecurityException {
     authenticate(c);
-    return hasTablePermission(c, tableId, TablePermission.BULK_IMPORT, false);
+    return hasTablePermission(c, tableId, TablePermission.BULK_IMPORT, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.BULK_IMPORT, false);
   }
   
   public boolean canCompact(TCredentials c, String tableId) throws ThriftSecurityException {
     authenticate(c);
     return hasSystemPermission(c, SystemPermission.ALTER_TABLE, false) || hasTablePermission(c, tableId, TablePermission.ALTER_TABLE, false)
-        || hasTablePermission(c, tableId, TablePermission.WRITE, false);
+        || hasTablePermission(c, tableId, TablePermission.WRITE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.ALTER_TABLE, false)
+        || hasTableNamespacePermissionForTableId(c, tableId, TableNamespacePermission.WRITE, false);
   }
   
   public boolean canChangeAuthorizations(TCredentials c, String user) throws ThriftSecurityException {
@@ -462,7 +542,14 @@ public class SecurityOperation {
   
   public boolean canGrantTable(TCredentials c, String user, String table) throws ThriftSecurityException {
     authenticate(c);
-    return hasSystemPermission(c, SystemPermission.ALTER_TABLE, false) || hasTablePermission(c, table, TablePermission.GRANT, false);
+    return hasSystemPermission(c, SystemPermission.ALTER_TABLE, false) || hasTablePermission(c, table, TablePermission.GRANT, false)
+        || hasTableNamespacePermissionForTableId(c, table, TableNamespacePermission.ALTER_TABLE, false);
+  }
+  
+  public boolean canGrantTableNamespace(TCredentials c, String user, String tableNamespace) throws ThriftSecurityException {
+    authenticate(c);
+    return hasSystemPermission(c, SystemPermission.ALTER_NAMESPACE, false)
+        || hasTableNamespacePermission(c, tableNamespace, TableNamespacePermission.GRANT, false);
   }
   
   public boolean canRevokeSystem(TCredentials c, String user, SystemPermission sysPerm) throws ThriftSecurityException {
@@ -480,7 +567,13 @@ public class SecurityOperation {
   
   public boolean canRevokeTable(TCredentials c, String user, String table) throws ThriftSecurityException {
     authenticate(c);
-    return hasSystemPermission(c, SystemPermission.ALTER_TABLE, false) || hasTablePermission(c, table, TablePermission.GRANT, false);
+    return hasSystemPermission(c, SystemPermission.ALTER_TABLE, false) || hasTablePermission(c, table, TablePermission.GRANT, false)
+        || hasTableNamespacePermissionForTableId(c, table, TableNamespacePermission.ALTER_TABLE, false);
+  }
+  
+  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);
   }
   
   public void changeAuthorizations(TCredentials credentials, String user, Authorizations authorizations) throws ThriftSecurityException {
@@ -568,6 +661,24 @@ public class SecurityOperation {
     }
   }
   
+  public void grantTableNamespacePermission(TCredentials c, String user, String tableNamespace, TableNamespacePermission permission)
+      throws ThriftSecurityException {
+    if (!canGrantTableNamespace(c, user, tableNamespace))
+      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
+    
+    targetUserExists(user);
+    
+    try {
+      permHandle.grantTableNamespacePermission(user, tableNamespace, permission);
+      log.info("Granted table namespace permission " + permission + " for user " + user + " on the table namespace " + tableNamespace
+          + " at the request of user " + c.getPrincipal());
+    } catch (AccumuloSecurityException e) {
+      throw e.asThriftException();
+    } catch (TableNamespaceNotFoundException e) {
+      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.TABLE_NAMESPACE_DOESNT_EXIST);
+    }
+  }
+  
   public void revokeSystemPermission(TCredentials credentials, String user, SystemPermission permission) throws ThriftSecurityException {
     if (!canRevokeSystem(credentials, user, permission))
       throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
@@ -600,6 +711,25 @@ public class SecurityOperation {
     }
   }
   
+  public void revokeTableNamespacePermission(TCredentials c, String user, String tableNamespace, TableNamespacePermission permission)
+      throws ThriftSecurityException {
+    if (!canRevokeTableNamespace(c, user, tableNamespace))
+      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
+    
+    targetUserExists(user);
+    
+    try {
+      permHandle.revokeTableNamespacePermission(user, tableNamespace, permission);
+      log.info("Revoked table namespace permission " + permission + " for user " + user + " on the table namespace " + tableNamespace
+          + " at the request of user " + c.getPrincipal());
+      
+    } catch (AccumuloSecurityException e) {
+      throw e.asThriftException();
+    } catch (TableNamespaceNotFoundException e) {
+      throw new ThriftSecurityException(c.getPrincipal(), SecurityErrorCode.TABLE_NAMESPACE_DOESNT_EXIST);
+    }
+  }
+  
   public boolean hasSystemPermission(TCredentials credentials, String user, SystemPermission permissionById) throws ThriftSecurityException {
     if (!canAskAboutOtherUsers(credentials, user))
       throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
@@ -612,6 +742,13 @@ public class SecurityOperation {
     return _hasTablePermission(user, tableId, permissionById, false);
   }
   
+  public boolean hasTableNamespacePermission(TCredentials credentials, String user, String tableNamespace, TableNamespacePermission permissionById)
+      throws ThriftSecurityException {
+    if (!canAskAboutOtherUsers(credentials, user))
+      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
+    return _hasTableNamespacePermission(user, tableNamespace, permissionById, false);
+  }
+  
   public Set<String> listUsers(TCredentials credentials) throws ThriftSecurityException {
     authenticate(credentials);
     try {
@@ -634,13 +771,29 @@ public class SecurityOperation {
     }
   }
   
+  public void deleteTableNamespace(TCredentials credentials, String tableNamespace) throws ThriftSecurityException {
+    if (!canDeleteTable(credentials, tableNamespace))
+      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.PERMISSION_DENIED);
+    try {
+      permHandle.cleanTableNamespacePermissions(tableNamespace);
+    } catch (AccumuloSecurityException e) {
+      e.setUser(credentials.getPrincipal());
+      throw e.asThriftException();
+    } catch (TableNamespaceNotFoundException e) {
+      throw new ThriftSecurityException(credentials.getPrincipal(), SecurityErrorCode.TABLE_NAMESPACE_DOESNT_EXIST);
+    }
+  }
+  
   public boolean canExport(TCredentials credentials, String tableId, String tableName, String exportDir) throws ThriftSecurityException {
     authenticate(credentials);
-    return hasTablePermission(credentials, tableId, TablePermission.READ, false);
+    return hasTablePermission(credentials, tableId, TablePermission.READ, false)
+        || hasTableNamespacePermissionForTableId(credentials, tableId, TableNamespacePermission.READ, false);
   }
   
   public boolean canImport(TCredentials credentials, String tableName, String importDir) throws ThriftSecurityException {
     authenticate(credentials);
-    return hasSystemPermission(credentials, SystemPermission.CREATE_TABLE, false);
+    String tableId = Tables.getNamespace(HdfsZooInstance.getInstance(), tableName);
+    return hasSystemPermission(credentials, SystemPermission.CREATE_TABLE, false)
+        || hasTableNamespacePermissionForTableId(credentials, tableId, TableNamespacePermission.CREATE_TABLE, false);
   }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/server/base/src/main/java/org/apache/accumulo/server/security/handler/InsecurePermHandler.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/InsecurePermHandler.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/InsecurePermHandler.java
index b57abfe..f1d69e8 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/InsecurePermHandler.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/InsecurePermHandler.java
@@ -17,8 +17,10 @@
 package org.apache.accumulo.server.security.handler;
 
 import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.TableNamespaceNotFoundException;
 import org.apache.accumulo.core.client.TableNotFoundException;
 import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.security.thrift.TCredentials;
 
@@ -99,5 +101,34 @@ public class InsecurePermHandler implements PermissionHandler {
   
   @Override
   public void initTable(String table) throws AccumuloSecurityException {}
+
+  @Override
+  public boolean hasTableNamespacePermission(String user, String namespace, TableNamespacePermission permission) throws AccumuloSecurityException,
+      TableNamespaceNotFoundException {
+    return true;
+  }
+
+  @Override
+  public boolean hasCachedTableNamespacePermission(String user, String namespace, TableNamespacePermission permission) throws AccumuloSecurityException,
+      TableNamespaceNotFoundException {
+    return true;
+  }
+
+  @Override
+  public void grantTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException,
+      TableNamespaceNotFoundException {
+    return;
+  }
+
+  @Override
+  public void revokeTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException,
+      TableNamespaceNotFoundException {
+    return;
+  }
+
+  @Override
+  public void cleanTableNamespacePermissions(String tableNamespace) throws AccumuloSecurityException, TableNamespaceNotFoundException {
+    return;
+  }
   
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/server/base/src/main/java/org/apache/accumulo/server/security/handler/PermissionHandler.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/PermissionHandler.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/PermissionHandler.java
index 72c64b5..63e7208 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/PermissionHandler.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/PermissionHandler.java
@@ -17,9 +17,11 @@
 package org.apache.accumulo.server.security.handler;
 
 import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.TableNamespaceNotFoundException;
 import org.apache.accumulo.core.client.TableNotFoundException;
 import org.apache.accumulo.core.client.impl.thrift.ThriftSecurityException;
 import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.security.thrift.TCredentials;
 
@@ -66,6 +68,16 @@ public interface PermissionHandler {
   public boolean hasCachedTablePermission(String user, String table, TablePermission permission) throws AccumuloSecurityException, TableNotFoundException;
   
   /**
+   * Used to get the table namespace permission of a user for a table namespace
+   */
+  public boolean hasTableNamespacePermission(String user, String namespace, TableNamespacePermission permission) throws AccumuloSecurityException, TableNamespaceNotFoundException;
+  
+  /**
+   * Used to get the table namespace permission of a user for a table namespace, with caching. This method is for high frequency operations
+   */
+  public boolean hasCachedTableNamespacePermission(String user, String namespace, TableNamespacePermission permission) throws AccumuloSecurityException, TableNamespaceNotFoundException;
+  
+  /**
    * Gives the user the given system permission
    */
   public void grantSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException;
@@ -86,11 +98,27 @@ public interface PermissionHandler {
   public void revokeTablePermission(String user, String table, TablePermission permission) throws AccumuloSecurityException, TableNotFoundException;
   
   /**
+   * Gives the user the given table namespace permission
+   */
+  public void grantTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException, TableNamespaceNotFoundException;
+  
+  /**
+   * Denies the user the given table namespace permission.
+   */
+  public void revokeTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException, TableNamespaceNotFoundException;
+  
+  
+  /**
    * Cleans up the permissions for a table. Used when a table gets deleted.
    */
   public void cleanTablePermissions(String table) throws AccumuloSecurityException, TableNotFoundException;
   
   /**
+   * Cleans up the permissions for a table namespace. Used when a table namespace gets deleted.
+   */
+  public void cleanTableNamespacePermissions(String tableNamespace) throws AccumuloSecurityException, TableNamespaceNotFoundException;
+  
+  /**
    * Initializes a new user
    */
   public void initUser(String user) throws AccumuloSecurityException;

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/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 f219603..78b79a1 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
@@ -24,11 +24,13 @@ import java.util.Set;
 import java.util.TreeSet;
 
 import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.TableNamespaceNotFoundException;
 import org.apache.accumulo.core.client.TableNotFoundException;
 import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode;
 import org.apache.accumulo.core.metadata.MetadataTable;
 import org.apache.accumulo.core.metadata.RootTable;
 import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.security.thrift.TCredentials;
 import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
@@ -49,9 +51,11 @@ public class ZKPermHandler implements PermissionHandler {
   
   private String ZKUserPath;
   private String ZKTablePath;
+  private String ZKNamespacePath;
   private final ZooCache zooCache;
   private final String ZKUserSysPerms = "/System";
   private final String ZKUserTablePerms = "/Tables";
+  private final String ZKUserNamespacePerms = "/Namespaces";
   
   public static synchronized PermissionHandler getInstance() {
     if (zkPermHandlerInstance == null)
@@ -63,6 +67,7 @@ public class ZKPermHandler implements PermissionHandler {
   public void initialize(String instanceId, boolean initialize) {
     ZKUserPath = ZKSecurityTool.getInstancePath(instanceId) + "/users";
     ZKTablePath = ZKSecurityTool.getInstancePath(instanceId) + "/tables";
+    ZKNamespacePath = ZKSecurityTool.getInstancePath(instanceId) + "/namespaces";
   }
   
   public ZKPermHandler() {
@@ -118,6 +123,54 @@ public class ZKPermHandler implements PermissionHandler {
   }
   
   @Override
+  public boolean hasTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws TableNamespaceNotFoundException {
+    byte[] serializedPerms;
+    try {
+      String path = ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + tableNamespace;
+      ZooReaderWriter.getRetryingInstance().sync(path);
+      serializedPerms = ZooReaderWriter.getRetryingInstance().getData(path, null);
+    } catch (KeeperException e) {
+      if (e.code() == Code.NONODE) {
+        // maybe the table namespace was just deleted?
+        try {
+          // check for existence:
+          ZooReaderWriter.getRetryingInstance().getData(ZKNamespacePath + "/" + tableNamespace, null);
+          // it's there, you don't have permission
+          return false;
+        } catch (InterruptedException ex) {
+          log.warn("Unhandled InterruptedException, failing closed for table namespace permission check", e);
+          return false;
+        } catch (KeeperException ex) {
+          // not there, throw an informative exception
+          if (e.code() == Code.NONODE) {
+            throw new TableNamespaceNotFoundException(null, tableNamespace, "while checking permissions");
+          }
+          log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
+        }
+        return false;
+      }
+      log.warn("Unhandled KeeperException, failing closed for table permission check", e);
+      return false;
+    } catch (InterruptedException e) {
+      log.warn("Unhandled InterruptedException, failing closed for table permission check", e);
+      return false;
+    }
+    if (serializedPerms != null) {
+      return ZKSecurityTool.convertTableNamespacePermissions(serializedPerms).contains(permission);
+    }
+    return false;
+  }
+  
+  @Override
+  public boolean hasCachedTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException, TableNamespaceNotFoundException {
+    byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + tableNamespace);
+    if (serializedPerms != null) {
+      return ZKSecurityTool.convertTableNamespacePermissions(serializedPerms).contains(permission);
+    }
+    return false;
+  }
+  
+  @Override
   public void grantSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
     try {
       byte[] permBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
@@ -172,6 +225,33 @@ public class ZKPermHandler implements PermissionHandler {
   }
   
   @Override
+  public void grantTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException {
+    Set<TableNamespacePermission> tableNamespacePerms;
+    byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + tableNamespace);
+    if (serializedPerms != null)
+      tableNamespacePerms = ZKSecurityTool.convertTableNamespacePermissions(serializedPerms);
+    else
+      tableNamespacePerms = new TreeSet<TableNamespacePermission>();
+    
+    try {
+      if (tableNamespacePerms.add(permission)) {
+        synchronized (zooCache) {
+          zooCache.clear(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + tableNamespace);
+          IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+          zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + tableNamespace, ZKSecurityTool.convertTableNamespacePermissions(tableNamespacePerms),
+              NodeExistsPolicy.OVERWRITE);
+        }
+      }
+    } catch (KeeperException e) {
+      log.error(e, e);
+      throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
+    } catch (InterruptedException e) {
+      log.error(e, e);
+      throw new RuntimeException(e);
+    }
+  }
+  
+  @Override
   public void revokeSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
     byte[] sysPermBytes = zooCache.get(ZKUserPath + "/" + user + ZKUserSysPerms);
     
@@ -227,6 +307,34 @@ public class ZKPermHandler implements PermissionHandler {
   }
   
   @Override
+  public void revokeTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException {
+    byte[] serializedPerms = zooCache.get(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + tableNamespace);
+    
+    // User had no table namespace permission, nothing to revoke.
+    if (serializedPerms == null)
+      return;
+    
+    Set<TableNamespacePermission> tableNamespacePerms = ZKSecurityTool.convertTableNamespacePermissions(serializedPerms);
+    try {
+      if (tableNamespacePerms.remove(permission)) {
+        zooCache.clear();
+        IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+        if (tableNamespacePerms.size() == 0)
+          zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + tableNamespace, NodeMissingPolicy.SKIP);
+        else
+          zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + tableNamespace, ZKSecurityTool.convertTableNamespacePermissions(tableNamespacePerms),
+              NodeExistsPolicy.OVERWRITE);
+      }
+    } catch (KeeperException e) {
+      log.error(e, e);
+      throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
+    } catch (InterruptedException e) {
+      log.error(e, e);
+      throw new RuntimeException(e);
+    }
+  }
+  
+  @Override
   public void cleanTablePermissions(String table) throws AccumuloSecurityException {
     try {
       synchronized (zooCache) {
@@ -245,6 +353,24 @@ public class ZKPermHandler implements PermissionHandler {
   }
   
   @Override
+  public void cleanTableNamespacePermissions(String tableNamespace) throws AccumuloSecurityException {
+    try {
+      synchronized (zooCache) {
+        zooCache.clear();
+        IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+        for (String user : zooCache.getChildren(ZKUserPath))
+          zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + tableNamespace, NodeMissingPolicy.SKIP);
+      }
+    } catch (KeeperException e) {
+      log.error(e, e);
+      throw new AccumuloSecurityException("unknownUser", SecurityErrorCode.CONNECTION_ERROR, e);
+    } catch (InterruptedException e) {
+      log.error(e, e);
+      throw new RuntimeException(e);
+    }
+  }
+  
+  @Override
   public void initializeSecurity(TCredentials itw, String rootuser) throws AccumuloSecurityException {
     IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
     
@@ -285,6 +411,7 @@ public class ZKPermHandler implements PermissionHandler {
     try {
       zoo.putPersistentData(ZKUserPath + "/" + user, new byte[0], NodeExistsPolicy.SKIP);
       zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms, new byte[0], NodeExistsPolicy.SKIP);
+      zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms, new byte[0], NodeExistsPolicy.SKIP);
     } catch (KeeperException e) {
       log.error(e, e);
       throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKSecurityTool.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKSecurityTool.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKSecurityTool.java
index 3b9d8b2..ce62b7e 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKSecurityTool.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKSecurityTool.java
@@ -31,6 +31,7 @@ import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.core.client.AccumuloException;
 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.security.TablePermission;
 import org.apache.log4j.Logger;
 
@@ -149,6 +150,26 @@ class ZKSecurityTool {
     return toReturn;
   }
   
+  public static byte[] convertTableNamespacePermissions(Set<TableNamespacePermission> namespacepermissions) {
+    ByteArrayOutputStream bytes = new ByteArrayOutputStream(namespacepermissions.size());
+    DataOutputStream out = new DataOutputStream(bytes);
+    try {
+      for (TableNamespacePermission tnp : namespacepermissions)
+        out.writeByte(tnp.getId());
+    } catch (IOException e) {
+      log.error(e, e);
+      throw new RuntimeException(e); // this is impossible with ByteArrayOutputStream; crash hard if this happens
+    }
+    return bytes.toByteArray();
+  }
+  
+  public static Set<TableNamespacePermission> convertTableNamespacePermissions(byte[] namespacepermissions) {
+    Set<TableNamespacePermission> toReturn = new HashSet<TableNamespacePermission>();
+    for (byte b : namespacepermissions)
+      toReturn.add(TableNamespacePermission.getPermissionById(b));
+    return toReturn;
+  }
+  
   public static String getInstancePath(String instanceId) {
     return Constants.ZROOT + "/" + instanceId;
   }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/test/src/main/java/org/apache/accumulo/test/randomwalk/security/WalkingSecurity.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/accumulo/test/randomwalk/security/WalkingSecurity.java b/test/src/main/java/org/apache/accumulo/test/randomwalk/security/WalkingSecurity.java
index 0ddb752..08fd395 100644
--- a/test/src/main/java/org/apache/accumulo/test/randomwalk/security/WalkingSecurity.java
+++ b/test/src/main/java/org/apache/accumulo/test/randomwalk/security/WalkingSecurity.java
@@ -27,6 +27,7 @@ import java.util.Set;
 import java.util.TreeSet;
 
 import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.TableNamespaceNotFoundException;
 import org.apache.accumulo.core.client.TableNotFoundException;
 import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode;
 import org.apache.accumulo.core.client.impl.thrift.ThriftSecurityException;
@@ -35,6 +36,7 @@ import org.apache.accumulo.core.client.security.tokens.PasswordToken;
 import org.apache.accumulo.core.security.Authorizations;
 import org.apache.accumulo.core.security.Credentials;
 import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TableNamespacePermission;
 import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.security.thrift.TCredentials;
 import org.apache.accumulo.core.util.CachedConfiguration;
@@ -59,6 +61,7 @@ public class WalkingSecurity extends SecurityOperation implements Authorizor, Au
   private static final String userPass = "UserPass";
   private static final String userExists = "UserExists";
   private static final String tableExists = "TableExists";
+  private static final String tableNamespaceExists = "TableNamespaceExists";
   
   private static final String connector = "UserConnection";
   
@@ -205,6 +208,16 @@ public class WalkingSecurity extends SecurityOperation implements Authorizor, Au
   }
   
   @Override
+  public boolean hasTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException, TableNamespaceNotFoundException {
+    return Boolean.parseBoolean(state.getString("Nsp-" + user + '-' + permission.name()));
+  }
+  
+  @Override
+  public boolean hasCachedTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException, TableNamespaceNotFoundException {
+    return hasTableNamespacePermission(user, tableNamespace, permission);
+  }
+  
+  @Override
   public void grantSystemPermission(String user, SystemPermission permission) throws AccumuloSecurityException {
     setSysPerm(state, user, permission, true);
   }
@@ -239,6 +252,25 @@ public class WalkingSecurity extends SecurityOperation implements Authorizor, Au
   }
   
   @Override
+  public void grantTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException, TableNamespaceNotFoundException {
+    setNspPerm(state, user, permission, tableNamespace, true);
+  }
+  
+  private void setNspPerm(State state, String userName, TableNamespacePermission tnp, String tableNamespace, boolean value) {
+    if (tableNamespace.equals(userName))
+      throw new RuntimeException("I don't even know");
+    log.debug((value ? "Gave" : "Took") + " the table permission " + tnp.name() + (value ? " to" : " from") + " user " + userName);
+    state.set("Nsp-" + userName + '-' + tnp.name(), Boolean.toString(value));
+    if (tnp.equals(TableNamespacePermission.READ) || tnp.equals(TableNamespacePermission.WRITE))
+      state.set("Nsp-" + userName + '-' + tnp.name() + '-' + "time", System.currentTimeMillis());
+  }
+  
+  @Override
+  public void revokeTableNamespacePermission(String user, String tableNamespace, TableNamespacePermission permission) throws AccumuloSecurityException, TableNamespaceNotFoundException {
+    setNspPerm(state, user, permission, tableNamespace, false);
+  }
+  
+  @Override
   public void cleanTablePermissions(String table) throws AccumuloSecurityException, TableNotFoundException {
     for (String user : new String[] {getSysUserName(), getTabUserName()}) {
       for (TablePermission tp : TablePermission.values()) {
@@ -249,6 +281,16 @@ public class WalkingSecurity extends SecurityOperation implements Authorizor, Au
   }
   
   @Override
+  public void cleanTableNamespacePermissions(String tableNamespace) throws AccumuloSecurityException, TableNamespaceNotFoundException {
+    for (String user : new String[] {getSysUserName(), getNspUserName()}) {
+      for (TableNamespacePermission tnp : TableNamespacePermission.values()) {
+        revokeTableNamespacePermission(user, tableNamespace, tnp);
+      }
+    }
+    state.set(tableNamespaceExists, Boolean.toString(false));
+  }
+  
+  @Override
   public void cleanUser(String user) throws AccumuloSecurityException {
     if (getTableExists())
       for (TablePermission tp : TablePermission.values())
@@ -267,11 +309,20 @@ public class WalkingSecurity extends SecurityOperation implements Authorizor, Au
     return state.getString("system" + userName);
   }
   
+  public String getNspUserName() {
+    return state.getString("namespace" + userName);
+  }
+  
   public void setTabUserName(String name) {
     state.set("table" + userName, name);
     state.set(name + userExists, Boolean.toString(false));
   }
   
+  public void setNspUserName(String name) {
+    state.set("namespace" + userName, name);
+    state.set(name + userExists, Boolean.toString(false));
+  }
+  
   public void setSysUserName(String name) {
     state.set("system" + userName, name);
   }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/dfdf5113/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 584991e..b779152 100644
--- a/test/src/test/java/org/apache/accumulo/test/TableNamespacesIT.java
+++ b/test/src/test/java/org/apache/accumulo/test/TableNamespacesIT.java
@@ -30,6 +30,7 @@ import java.util.Set;
 
 import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
 import org.apache.accumulo.core.client.BatchWriter;
 import org.apache.accumulo.core.client.BatchWriterConfig;
 import org.apache.accumulo.core.client.Connector;
@@ -42,6 +43,7 @@ import org.apache.accumulo.core.client.TableNamespaceNotFoundException;
 import org.apache.accumulo.core.client.TableNotFoundException;
 import org.apache.accumulo.core.client.impl.TableNamespaces;
 import org.apache.accumulo.core.client.impl.Tables;
+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;
@@ -49,6 +51,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.TableNamespacePermission;
 import org.apache.accumulo.core.util.UtilWaitThread;
 import org.apache.accumulo.examples.simple.constraints.NumericValueConstraint;
 import org.apache.accumulo.minicluster.MiniAccumuloCluster;
@@ -404,12 +407,12 @@ public class TableNamespacesIT {
     } catch (MutationsRejectedException e) {
       // supposed to be thrown
     }
-    
     int num = c.tableNamespaceOperations().listConstraints(namespace).get(NumericValueConstraint.class.getName());
     c.tableNamespaceOperations().removeConstraint(namespace, num);
   }
   
   /**
+<<<<<<< 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
@@ -447,6 +450,38 @@ public class TableNamespacesIT {
     }
     assertTrue(!hasProp);
   }
+  /**
+   *  Tests new Namespace permissions as well as modifications to Table permissions because of namespaces 
+   */
+  @Test
+  public void testPermissions() throws Exception {
+    Connector c = accumulo.getConnector("root", secret);
+    
+    PasswordToken pass = new PasswordToken(secret);
+    
+    String n1 = "namespace1";
+
+    String user1 = "dude";
+
+    c.tableNamespaceOperations().create(n1);
+    c.tableOperations().create(n1 + ".table1");
+    
+    c.securityOperations().createLocalUser(user1, pass);
+    
+    Connector user1Con = accumulo.getConnector(user1, secret);
+    
+    try {
+      user1Con.tableOperations().create(n1 + ".table2");
+      fail();
+    } catch (AccumuloSecurityException e) {
+      // supposed to happen
+    }
+    
+    c.securityOperations().grantTableNamespacePermission(user1, n1, TableNamespacePermission.CREATE_TABLE);
+    
+    user1Con.tableOperations().create(n1 + ".table2");
+    assertTrue(c.tableOperations().list().contains(n1 + ".table2"));
+  }
   
   private boolean checkTableHasProp(Connector c, String t, String propKey, String propVal) throws AccumuloException, TableNotFoundException {
     for (Entry<String,String> e : c.tableOperations().getProperties(t)) {