This is an automated email from the ASF dual-hosted git repository.

ctubbsii pushed a commit to branch 1.9
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/1.9 by this push:
     new 375cfbc  Expanded InputConfigurator permissions checks to include 
Namespace.READ (#1371)
375cfbc is described below

commit 375cfbc898fe49b80f8ae6fc26167ded332e3709
Author: Richard W. Eggert II <richard.egg...@gmail.com>
AuthorDate: Fri Oct 4 19:03:36 2019 -0400

    Expanded InputConfigurator permissions checks to include Namespace.READ 
(#1371)
    
    * created tests to cover #1370
    
    * expanded checks in InputConfigurator.validatePermissions to include 
Namespace.READ and resolve #1370
    
    * auto-adjusted formatting
    
    * removed unnecessary assertions from 
testGetSplitsWithNamespaceReadPermission
---
 .../mapreduce/lib/impl/InputConfigurator.java      | 21 +++++-
 .../test/mapreduce/AccumuloInputFormatIT.java      | 74 ++++++++++++++++++++++
 2 files changed, 93 insertions(+), 2 deletions(-)

diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/mapreduce/lib/impl/InputConfigurator.java
 
b/core/src/main/java/org/apache/accumulo/core/client/mapreduce/lib/impl/InputConfigurator.java
index c978060..f5efdf7 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/mapreduce/lib/impl/InputConfigurator.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/mapreduce/lib/impl/InputConfigurator.java
@@ -66,6 +66,7 @@ import org.apache.accumulo.core.metadata.MetadataTable;
 import org.apache.accumulo.core.metadata.schema.MetadataSchema;
 import org.apache.accumulo.core.sample.impl.SamplerConfigurationImpl;
 import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.security.NamespacePermission;
 import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.util.Base64;
 import org.apache.accumulo.core.util.DeprecationUtil;
@@ -778,6 +779,15 @@ public class InputConfigurator extends ConfiguratorBase {
     return getInstance(implementingClass, conf);
   }
 
+  private static String extractNamespace(final String tableName) {
+    final int delimiterPos = tableName.indexOf('.');
+    if (delimiterPos < 1) {
+      return ""; // default namespace
+    } else {
+      return tableName.substring(0, delimiterPos);
+    }
+  }
+
   /**
    * Validates that the user has permissions on the requested tables
    *
@@ -796,10 +806,17 @@ public class InputConfigurator extends ConfiguratorBase {
       if (getInputTableConfigs(implementingClass, conf).size() == 0)
         throw new IOException("No table set.");
 
+      final String principal = getPrincipal(implementingClass, conf);
       for (Map.Entry<String,InputTableConfig> tableConfig : 
inputTableConfigs.entrySet()) {
-        if 
(!conn.securityOperations().hasTablePermission(getPrincipal(implementingClass, 
conf),
-            tableConfig.getKey(), TablePermission.READ))
+        final String tableName = tableConfig.getKey();
+        final String namespace = extractNamespace(tableName);
+        final boolean hasTableRead = 
conn.securityOperations().hasTablePermission(principal,
+            tableName, TablePermission.READ);
+        final boolean hasNamespaceRead = 
conn.securityOperations().hasNamespacePermission(principal,
+            namespace, NamespacePermission.READ);
+        if (!hasTableRead && !hasNamespaceRead) {
           throw new IOException("Unable to access table");
+        }
       }
       for (Map.Entry<String,InputTableConfig> tableConfigEntry : 
inputTableConfigs.entrySet()) {
         InputTableConfig tableConfig = tableConfigEntry.getValue();
diff --git 
a/test/src/main/java/org/apache/accumulo/test/mapreduce/AccumuloInputFormatIT.java
 
b/test/src/main/java/org/apache/accumulo/test/mapreduce/AccumuloInputFormatIT.java
index e9f1bd8..afce3ee 100644
--- 
a/test/src/main/java/org/apache/accumulo/test/mapreduce/AccumuloInputFormatIT.java
+++ 
b/test/src/main/java/org/apache/accumulo/test/mapreduce/AccumuloInputFormatIT.java
@@ -55,6 +55,7 @@ import org.apache.accumulo.core.data.Mutation;
 import org.apache.accumulo.core.data.Range;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.util.Pair;
 import org.apache.accumulo.harness.AccumuloClusterHarness;
 import org.apache.accumulo.minicluster.impl.MiniAccumuloConfigImpl;
@@ -463,6 +464,79 @@ public class AccumuloInputFormatIT extends 
AccumuloClusterHarness {
     assertEquals(level, risplit.getLogLevel());
   }
 
+  @Test(expected = IOException.class)
+  public void testGetSplitsNoReadPermission() throws Exception {
+    Job job = Job.getInstance();
+
+    String table = getUniqueNames(1)[0];
+    Authorizations auths = new Authorizations("foo");
+    Collection<Pair<Text,Text>> fetchColumns =
+        Collections.singleton(new Pair<>(new Text("foo"), new Text("bar")));
+    boolean isolated = true, localIters = true;
+    Level level = Level.WARN;
+
+    Connector connector = getConnector();
+    connector.tableOperations().create(table);
+    connector.securityOperations().revokeTablePermission(connector.whoami(), 
table,
+        TablePermission.READ);
+
+    AccumuloInputFormat.setZooKeeperInstance(job, cluster.getClientConfig());
+    AccumuloInputFormat.setConnectorInfo(job, getAdminPrincipal(), 
getAdminToken());
+
+    AccumuloInputFormat.setInputTableName(job, table);
+    AccumuloInputFormat.setScanAuthorizations(job, auths);
+    AccumuloInputFormat.setScanIsolation(job, isolated);
+    AccumuloInputFormat.setLocalIterators(job, localIters);
+    AccumuloInputFormat.fetchColumns(job, fetchColumns);
+    AccumuloInputFormat.setLogLevel(job, level);
+
+    AccumuloInputFormat aif = new AccumuloInputFormat();
+
+    aif.getSplits(job);
+  }
+
+  /*
+   * This tests the case where we do not have Table.READ permission, but we do 
have Namespace.READ.
+   * See issue #1370.
+   */
+  @Test
+  public void testGetSplitsWithNamespaceReadPermission() throws Exception {
+    Job job = Job.getInstance();
+
+    final String[] namespaceAndTable = getUniqueNames(2);
+    final String namespace = namespaceAndTable[0];
+    final String tableSimpleName = namespaceAndTable[1];
+    final String table = namespace + "." + tableSimpleName;
+    Authorizations auths = new Authorizations("foo");
+    Collection<Pair<Text,Text>> fetchColumns =
+        Collections.singleton(new Pair<>(new Text("foo"), new Text("bar")));
+    final boolean isolated = true;
+    final boolean localIters = true;
+    Level level = Level.WARN;
+
+    Connector connector = getConnector();
+    connector.namespaceOperations().create(namespace); // creating namespace 
implies Namespace.READ
+    connector.tableOperations().create(table);
+    connector.securityOperations().revokeTablePermission(connector.whoami(), 
table,
+        TablePermission.READ);
+
+    AccumuloInputFormat.setZooKeeperInstance(job, cluster.getClientConfig());
+    AccumuloInputFormat.setConnectorInfo(job, getAdminPrincipal(), 
getAdminToken());
+
+    AccumuloInputFormat.setInputTableName(job, table);
+    AccumuloInputFormat.setScanAuthorizations(job, auths);
+    AccumuloInputFormat.setScanIsolation(job, isolated);
+    AccumuloInputFormat.setLocalIterators(job, localIters);
+    AccumuloInputFormat.fetchColumns(job, fetchColumns);
+    AccumuloInputFormat.setLogLevel(job, level);
+
+    AccumuloInputFormat aif = new AccumuloInputFormat();
+
+    List<InputSplit> splits = aif.getSplits(job);
+
+    assertEquals(1, splits.size());
+  }
+
   @Test
   public void testPartialInputSplitDelegationToConfiguration() throws 
Exception {
     String table = getUniqueNames(1)[0];

Reply via email to