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

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


The following commit(s) were added to refs/heads/main by this push:
     new 8a53e8dab5 Print warning in shell when user does not have permission 
to get config (#3015)
8a53e8dab5 is described below

commit 8a53e8dab51aca58a04b513116763bbe4817f0a2
Author: Dave Marion <dlmar...@apache.org>
AuthorDate: Fri Oct 14 07:16:38 2022 -0400

    Print warning in shell when user does not have permission to get config 
(#3015)
    
    Modified ConfigCommand to only show the user properties that they have
    permission to see. When a user is unable to see the properties at a
    specific level warnings are printed in the shell letting them know what
    permission they are missing and that the properties that they are seeing
    for the table or namespace may actually be set at a higher level that they
    can't see. Override information is still shown, but only for levels that 
the user
    has access to.
---
 .../core/clientImpl/NamespaceOperationsImpl.java   |   6 +-
 .../core/clientImpl/TableOperationsHelper.java     |   4 +-
 .../core/clientImpl/TableOperationsImpl.java       |   4 +-
 .../server/client/ClientServiceHandler.java        |  14 ++-
 .../org/apache/accumulo/server/util/Admin.java     |   3 +-
 shell/pom.xml                                      |   4 +
 .../accumulo/shell/commands/ConfigCommand.java     | 113 ++++++++++++++++++---
 .../accumulo/test/NewTableConfigurationIT.java     |   3 +-
 8 files changed, 126 insertions(+), 25 deletions(-)

diff --git 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/NamespaceOperationsImpl.java
 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/NamespaceOperationsImpl.java
index 88b1e116ee..cd0dd2b580 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/NamespaceOperationsImpl.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/NamespaceOperationsImpl.java
@@ -285,12 +285,14 @@ public class NamespaceOperationsImpl extends 
NamespaceOperationsHelper {
 
   @Override
   public Map<String,String> getConfiguration(final String namespace)
-      throws AccumuloException, NamespaceNotFoundException {
+      throws AccumuloException, AccumuloSecurityException, 
NamespaceNotFoundException {
     EXISTING_NAMESPACE_NAME.validate(namespace);
 
     try {
       return ThriftClientTypes.CLIENT.execute(context, client -> client
           .getNamespaceConfiguration(TraceUtil.traceInfo(), 
context.rpcCreds(), namespace));
+    } catch (AccumuloSecurityException e) {
+      throw e;
     } catch (AccumuloException e) {
       Throwable t = e.getCause();
       if (t instanceof ThriftTableOperationException) {
@@ -395,7 +397,7 @@ public class NamespaceOperationsImpl extends 
NamespaceOperationsHelper {
   }
 
   private void checkLocalityGroups(String namespace, String propChanged)
-      throws AccumuloException, NamespaceNotFoundException {
+      throws AccumuloSecurityException, AccumuloException, 
NamespaceNotFoundException {
     EXISTING_NAMESPACE_NAME.validate(namespace);
 
     if (LocalityGroupUtil.isLocalityGroupProperty(propChanged)) {
diff --git 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsHelper.java
 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsHelper.java
index 27f7a9f4a5..1748592792 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsHelper.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsHelper.java
@@ -81,7 +81,7 @@ public abstract class TableOperationsHelper implements 
TableOperations {
 
   @Override
   public IteratorSetting getIteratorSetting(String tableName, String name, 
IteratorScope scope)
-      throws AccumuloException, TableNotFoundException {
+      throws AccumuloSecurityException, AccumuloException, 
TableNotFoundException {
     EXISTING_TABLE_NAME.validate(tableName);
     checkArgument(name != null, "name is null");
     checkArgument(scope != null, "scope is null");
@@ -113,7 +113,7 @@ public abstract class TableOperationsHelper implements 
TableOperations {
 
   @Override
   public Map<String,EnumSet<IteratorScope>> listIterators(String tableName)
-      throws AccumuloException, TableNotFoundException {
+      throws AccumuloSecurityException, AccumuloException, 
TableNotFoundException {
     EXISTING_TABLE_NAME.validate(tableName);
 
     Map<String,EnumSet<IteratorScope>> result = new TreeMap<>();
diff --git 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
index 65222bf5f9..1f66da5630 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
@@ -1098,7 +1098,7 @@ public class TableOperationsImpl extends 
TableOperationsHelper {
   }
 
   void checkLocalityGroups(String tableName, String propChanged)
-      throws AccumuloException, TableNotFoundException {
+      throws AccumuloException, AccumuloSecurityException, 
TableNotFoundException {
     if (LocalityGroupUtil.isLocalityGroupProperty(propChanged)) {
       Map<String,String> allProps = getConfiguration(tableName);
       try {
@@ -1840,7 +1840,7 @@ public class TableOperationsImpl extends 
TableOperationsHelper {
 
   @Override
   public SamplerConfiguration getSamplerConfiguration(String tableName)
-      throws TableNotFoundException, AccumuloException {
+      throws TableNotFoundException, AccumuloSecurityException, 
AccumuloException {
     EXISTING_TABLE_NAME.validate(tableName);
 
     AccumuloConfiguration conf = new 
ConfigurationCopy(this.getProperties(tableName));
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 6d943e81f6..24d345b87f 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
@@ -320,8 +320,11 @@ public class ClientServiceHandler implements 
ClientService.Iface {
 
   private void checkTablePermission(TCredentials credentials, TableId tableId,
       TablePermission tablePermission) throws ThriftSecurityException {
-    if (!(checkSystemUserAndAuthenticate(credentials) || 
security.hasTablePermission(credentials,
-        credentials.getPrincipal(), tableId, tablePermission))) {
+    if (!(checkSystemUserAndAuthenticate(credentials)
+        || security.hasSystemPermission(credentials, 
credentials.getPrincipal(),
+            SystemPermission.SYSTEM)
+        || security.hasTablePermission(credentials, 
credentials.getPrincipal(), tableId,
+            tablePermission))) {
       throw new ThriftSecurityException(credentials.getPrincipal(),
           SecurityErrorCode.PERMISSION_DENIED);
     }
@@ -329,8 +332,11 @@ public class ClientServiceHandler implements 
ClientService.Iface {
 
   private void checkNamespacePermission(TCredentials credentials, NamespaceId 
namespaceId,
       NamespacePermission namespacePermission) throws ThriftSecurityException {
-    if (!(checkSystemUserAndAuthenticate(credentials) || 
security.hasNamespacePermission(
-        credentials, credentials.getPrincipal(), namespaceId, 
namespacePermission))) {
+    if (!(checkSystemUserAndAuthenticate(credentials)
+        || security.hasSystemPermission(credentials, 
credentials.getPrincipal(),
+            SystemPermission.SYSTEM)
+        || security.hasNamespacePermission(credentials, 
credentials.getPrincipal(), namespaceId,
+            namespacePermission))) {
       throw new ThriftSecurityException(credentials.getPrincipal(),
           SecurityErrorCode.PERMISSION_DENIED);
     }
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java 
b/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java
index 2f5010846e..a4cc0c11c6 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java
@@ -743,7 +743,8 @@ public class Admin implements KeywordExecutable {
   @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN",
       justification = "code runs in same security context as user who provided 
input")
   private void printTableConfiguration(AccumuloClient accumuloClient, String 
tableName,
-      File outputDirectory) throws AccumuloException, TableNotFoundException, 
IOException {
+      File outputDirectory)
+      throws AccumuloSecurityException, AccumuloException, 
TableNotFoundException, IOException {
     File tableBackup = new File(outputDirectory, tableName + ".cfg");
     try (BufferedWriter writer = new BufferedWriter(new 
FileWriter(tableBackup, UTF_8))) {
       writer.write(createTableFormat.format(new String[] {tableName}));
diff --git a/shell/pom.xml b/shell/pom.xml
index 773ae756d7..d5694e05bf 100644
--- a/shell/pom.xml
+++ b/shell/pom.xml
@@ -71,6 +71,10 @@
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-collections4</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-client-api</artifactId>
diff --git 
a/shell/src/main/java/org/apache/accumulo/shell/commands/ConfigCommand.java 
b/shell/src/main/java/org/apache/accumulo/shell/commands/ConfigCommand.java
index d17f3a8c74..3774cfa780 100644
--- a/shell/src/main/java/org/apache/accumulo/shell/commands/ConfigCommand.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ConfigCommand.java
@@ -18,6 +18,8 @@
  */
 package org.apache.accumulo.shell.commands;
 
+import static 
org.apache.accumulo.core.client.security.SecurityErrorCode.PERMISSION_DENIED;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -44,6 +46,7 @@ import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.OptionGroup;
 import org.apache.commons.cli.Options;
+import org.apache.commons.lang3.StringUtils;
 import org.jline.reader.LineReader;
 
 import com.google.common.collect.ImmutableSortedMap;
@@ -153,16 +156,38 @@ public class ConfigCommand extends Command {
         Shell.log.debug("Successfully set system configuration option.");
       }
     } else {
+      boolean warned = false;
       // display properties
       final TreeMap<String,String> systemConfig = new TreeMap<>();
-      systemConfig
-          
.putAll(shellState.getAccumuloClient().instanceOperations().getSystemConfiguration());
+      try {
+        systemConfig
+            
.putAll(shellState.getAccumuloClient().instanceOperations().getSystemConfiguration());
+      } catch (AccumuloSecurityException e) {
+        if (e.getSecurityErrorCode() == PERMISSION_DENIED) {
+          Shell.log.warn(
+              "User unable to retrieve system configuration (requires 
System.SYSTEM permission)");
+          warned = true;
+        } else {
+          throw e;
+        }
+      }
 
       final String outputFile = cl.getOptionValue(outputFileOpt.getOpt());
       final PrintFile printFile = outputFile == null ? null : new 
PrintFile(outputFile);
 
       final TreeMap<String,String> siteConfig = new TreeMap<>();
-      
siteConfig.putAll(shellState.getAccumuloClient().instanceOperations().getSiteConfiguration());
+      try {
+        siteConfig
+            
.putAll(shellState.getAccumuloClient().instanceOperations().getSiteConfiguration());
+      } catch (AccumuloSecurityException e) {
+        if (e.getSecurityErrorCode() == PERMISSION_DENIED) {
+          Shell.log.warn(
+              "User unable to retrieve site configuration (requires 
System.SYSTEM permission)");
+          warned = true;
+        } else {
+          throw e;
+        }
+      }
 
       final TreeMap<String,String> defaults = new TreeMap<>();
       for (Entry<String,String> defaultEntry : 
DefaultConfiguration.getInstance()) {
@@ -173,16 +198,58 @@ public class ConfigCommand extends Command {
       if (tableName != null) {
         String n = Namespaces.getNamespaceName(shellState.getContext(),
             
shellState.getContext().getNamespaceId(shellState.getContext().getTableId(tableName)));
-        
shellState.getAccumuloClient().namespaceOperations().getConfiguration(n)
-            .forEach(namespaceConfig::put);
+        try {
+          
shellState.getAccumuloClient().namespaceOperations().getConfiguration(n)
+              .forEach(namespaceConfig::put);
+        } catch (AccumuloSecurityException e) {
+          if (e.getSecurityErrorCode() == PERMISSION_DENIED) {
+            Shell.log.warn(
+                "User unable to retrieve {} namespace configuration (requires 
Namespace.ALTER_NAMESPACE permission)",
+                StringUtils.isEmpty(n) ? "default" : n);
+            warned = true;
+          } else {
+            throw e;
+          }
+        }
+      }
+
+      Map<String,String> acuconf = systemConfig;
+      if (acuconf.isEmpty()) {
+        acuconf = defaults;
       }
 
-      Map<String,String> acuconf =
-          
shellState.getAccumuloClient().instanceOperations().getSystemConfiguration();
       if (tableName != null) {
-        acuconf = 
shellState.getAccumuloClient().tableOperations().getConfiguration(tableName);
+        if (warned) {
+          Shell.log.warn(
+              "User does not have permission to see entire configuration 
heirarchy. Property values shown below may be set above the table level.");
+        }
+        try {
+          acuconf = 
shellState.getAccumuloClient().tableOperations().getConfiguration(tableName);
+        } catch (AccumuloException e) {
+          if (e.getCause() != null && e.getCause() instanceof 
AccumuloSecurityException) {
+            AccumuloSecurityException ase = (AccumuloSecurityException) 
e.getCause();
+            if (ase.getSecurityErrorCode() == PERMISSION_DENIED) {
+              Shell.log.error(
+                  "User unable to retrieve {} table configuration (requires 
Table.ALTER_TABLE permission)",
+                  tableName);
+            }
+          }
+          throw e;
+        }
       } else if (namespace != null) {
-        acuconf = 
shellState.getAccumuloClient().namespaceOperations().getConfiguration(namespace);
+        if (warned) {
+          Shell.log.warn(
+              "User does not have permission to see entire configuration 
heirarchy. Property values shown below may be set above the namespace level.");
+        }
+        try {
+          acuconf =
+              
shellState.getAccumuloClient().namespaceOperations().getConfiguration(namespace);
+        } catch (AccumuloSecurityException e) {
+          Shell.log.error(
+              "User unable to retrieve {} namespace configuration (requires 
Namespace.ALTER_NAMESPACE permission)",
+              StringUtils.isEmpty(namespace) ? "default" : namespace);
+          throw e;
+        }
       }
       final Map<String,String> sortedConf = ImmutableSortedMap.copyOf(acuconf);
 
@@ -223,10 +290,10 @@ public class ConfigCommand extends Command {
         String nspVal = namespaceConfig.get(key);
         boolean printed = false;
 
-        if (dfault != null && key.toLowerCase().contains("password")) {
-          siteVal = sysVal = dfault = curVal = curVal.replaceAll(".", "*");
-        }
         if (sysVal != null) {
+          if (dfault != null && key.toLowerCase().contains("password")) {
+            siteVal = sysVal = dfault = curVal = curVal.replaceAll(".", "*");
+          }
           if (defaults.containsKey(key) && 
!Property.getPropertyByKey(key).isExperimental()) {
             printConfLine(output, "default", key, dfault);
             printed = true;
@@ -240,9 +307,15 @@ public class ConfigCommand extends Command {
             printConfLine(output, "system", printed ? "   @override" : key, 
sysVal);
             printed = true;
           }
-
         }
         if (nspVal != null) {
+          // If the user can't see the system configuration, then print the 
default
+          // configuration value if the current namespace value is different 
from it.
+          if (sysVal == null && dfault != null && !dfault.equals(nspVal)
+              && !Property.getPropertyByKey(key).isExperimental()) {
+            printConfLine(output, "default", key, dfault);
+            printed = true;
+          }
           if (!systemConfig.containsKey(key) || !sysVal.equals(nspVal)) {
             printConfLine(output, "namespace", printed ? "   @override" : key, 
nspVal);
             printed = true;
@@ -251,8 +324,22 @@ public class ConfigCommand extends Command {
 
         // show per-table value only if it is different (overridden)
         if (tableName != null && !curVal.equals(nspVal)) {
+          // If the user can't see the system configuration, then print the 
default
+          // configuration value if the current table value is different from 
it.
+          if (nspVal == null && dfault != null && !dfault.equals(curVal)
+              && !Property.getPropertyByKey(key).isExperimental()) {
+            printConfLine(output, "default", key, dfault);
+            printed = true;
+          }
           printConfLine(output, "table", printed ? "   @override" : key, 
curVal);
         } else if (namespace != null && !curVal.equals(sysVal)) {
+          // If the user can't see the system configuration, then print the 
default
+          // configuration value if the current namespace value is different 
from it.
+          if (sysVal == null && dfault != null && !dfault.equals(curVal)
+              && !Property.getPropertyByKey(key).isExperimental()) {
+            printConfLine(output, "default", key, dfault);
+            printed = true;
+          }
           printConfLine(output, "namespace", printed ? "   @override" : key, 
curVal);
         }
       }
diff --git 
a/test/src/main/java/org/apache/accumulo/test/NewTableConfigurationIT.java 
b/test/src/main/java/org/apache/accumulo/test/NewTableConfigurationIT.java
index 95af781007..ae4e1a5685 100644
--- a/test/src/main/java/org/apache/accumulo/test/NewTableConfigurationIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/NewTableConfigurationIT.java
@@ -521,7 +521,8 @@ public class NewTableConfigurationIT extends 
SharedMiniClusterBase {
    * Verify the expected iterator properties exist.
    */
   private void verifyIterators(AccumuloClient client, String tablename, 
String[] values,
-      boolean withDefaultIts) throws AccumuloException, TableNotFoundException 
{
+      boolean withDefaultIts)
+      throws AccumuloSecurityException, AccumuloException, 
TableNotFoundException {
     Map<String,String> expected = new TreeMap<>();
     if (withDefaultIts) {
       expected.put("table.iterator.scan.vers",

Reply via email to