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 2019/10/04 23:03:41 UTC
[accumulo] branch 1.9 updated: Expanded InputConfigurator
permissions checks to include Namespace.READ (#1371)
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 <ri...@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];