Repository: accumulo
Updated Branches:
  refs/heads/1.7 81f1c7d80 -> e43e9273e
  refs/heads/master 860ee35eb -> cf75edb45


ACCUMULO-4135 Add impersonation configuration keys which don't put the 
principal in the key.

Apparently, Ambari has a very hard time handling configuration keys that have 
'/'
characters in them. As such, this breaks the impersonation config keys, as they
will near always have a '/' in them (e.g. primary/instance@REALM). This is sad.

This commit introduces an alternate strategy for specifying the same 
configuration
items but only using the values.

Closes apache/accumulo#67


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/e43e9273
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/e43e9273
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/e43e9273

Branch: refs/heads/1.7
Commit: e43e9273e5297f56b0cc51349ab9bdc25d6e956d
Parents: 81f1c7d
Author: Josh Elser <els...@apache.org>
Authored: Sat Feb 6 16:40:03 2016 -0500
Committer: Josh Elser <els...@apache.org>
Committed: Sat Feb 6 16:40:03 2016 -0500

----------------------------------------------------------------------
 .../org/apache/accumulo/core/conf/Property.java |   5 +
 docs/src/main/asciidoc/chapters/kerberos.txt    |  52 ++--
 .../server/security/UserImpersonation.java      |  97 ++++++-
 ...redentialsUpdatingInvocationHandlerTest.java |  55 ++--
 .../server/security/UserImpersonationTest.java  | 259 ++++++++++++++++++-
 5 files changed, 422 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/e43e9273/core/src/main/java/org/apache/accumulo/core/conf/Property.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/conf/Property.java 
b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
index 559c460..28cc861 100644
--- a/core/src/main/java/org/apache/accumulo/core/conf/Property.java
+++ b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
@@ -158,8 +158,13 @@ public enum Property {
    */
   INSTANCE_RPC_SASL_ENABLED("instance.rpc.sasl.enabled", "false", 
PropertyType.BOOLEAN,
       "Configures Thrift RPCs to require SASL with GSSAPI which supports 
Kerberos authentication. Mutually exclusive with SSL RPC configuration."),
+  @Deprecated
   INSTANCE_RPC_SASL_PROXYUSERS("instance.rpc.sasl.impersonation.", null, 
PropertyType.PREFIX,
       "Prefix that allows configuration of users that are allowed to 
impersonate other users"),
+  
INSTANCE_RPC_SASL_ALLOWED_USER_IMPERSONATION("instance.rpc.sasl.allowed.user.impersonation",
 "", PropertyType.STRING,
+      "One-line configuration property controlling what users are allowed to 
impersonate other users"),
+  
INSTANCE_RPC_SASL_ALLOWED_HOST_IMPERSONATION("instance.rpc.sasl.allowed.host.impersonation",
 "", PropertyType.STRING,
+      "One-line configuration property controlling the network locations 
(hostnames) that are allowed to impersonate other users"),
 
   // general properties
   GENERAL_PREFIX("general.", null, PropertyType.PREFIX,

http://git-wip-us.apache.org/repos/asf/accumulo/blob/e43e9273/docs/src/main/asciidoc/chapters/kerberos.txt
----------------------------------------------------------------------
diff --git a/docs/src/main/asciidoc/chapters/kerberos.txt 
b/docs/src/main/asciidoc/chapters/kerberos.txt
index ca482b2..fec9277 100644
--- a/docs/src/main/asciidoc/chapters/kerberos.txt
+++ b/docs/src/main/asciidoc/chapters/kerberos.txt
@@ -35,7 +35,7 @@ Kerberos implements. In the Java programming language, the 
language itself also
 GSSAPI which is leveraged by other applications, like Apache Hadoop and Apache 
Thrift.
 SASL, simple authentication and security layer, is a framework for 
authentication and
 and security over the network. SASL provides a number of mechanisms for 
authentication,
-one of which is GSSAPI. Thus, SASL provides the transport which authenticates 
+one of which is GSSAPI. Thus, SASL provides the transport which authenticates
 using GSSAPI that Kerberos implements.
 
 Kerberos is a very complicated software application and is deserving of much
@@ -269,29 +269,45 @@ it can only connect to Accumulo as itself. Impersonation, 
in this context, refer
 of the proxy to authenticate to Accumulo as itself, but act on behalf of an 
Accumulo user.
 
 Accumulo supports basic impersonation of end-users by a third party via static 
rules in Accumulo's
-site configuration file.
+site configuration file. These two properties are semi-colon separated 
properties which are aligned
+by index. This first element in the user impersonation property value matches 
the first element
+in the host impersonation property value, etc.
 
 ----
 <property>
-  <name>instance.rpc.sasl.impersonation.$PROXY_USER.users</name>
-  <value>*</value>
+  <name>instance.rpc.sasl.allowed.user.impersonation</name>
+  <value>$PROXY_USER:*</value>
 </property>
 
 <property>
-  <name>instance.rpc.sasl.impersonation.$PROXY_USER.hosts</name>
+  <name>instance.rpc.sasl.allowed.host.impersonation</name>
   <value>*</value>
 </property>
 ----
 
-The value +$PROXY_USER+ is the Kerberos principal of the server which is 
acting on behalf of a user.
-Impersonation is enforced by the Kerberos principal and the host from which 
the RPC originated. Both
-of the above properties expects values which are comma-separated lists. The 
value of each user in the
-list should be the complete Kerberos principal of the user which the give 
+$PROXY_USER+ can impersonate,
-and each value of the hosts list should be the FQDN of the machine which the 
+$PROXY_USER+ can submit
-requests from.
+Here, +$PROXY_USER+ can impersonate any user from any host.
+
+The following is an example of specifying a subset of users +$PROXY_USER+ can 
impersonate and also
+limiting the hosts from which +$PROXY_USER+ can initiate requests from.
+
+----
+<property>
+  <name>instance.rpc.sasl.allowed.user.impersonation</name>
+  <value>$PROXY_USER:user1,user2;$PROXY_USER2:user2,user4</value>
+</property>
+
+<property>
+  <name>instance.rpc.sasl.allowed.host.impersonation</name>
+  <value>host1.domain.com,host2.domain.com;*</value>
+</property>
+----
+
+Here, +$PROXY_USER+ can impersonate user1 and user2 only from host1.domain.com 
or host2.domain.com.
++$PROXY_USER2+ can impersonate user2 and user4 from any host.
 
-Both the hosts and users configuration properties also accept a value of +*+ 
to denote that any user or host
-is acceptable for +$PROXY_USER+.
+In these examples, the value +$PROXY_USER+ is the Kerberos principal of the 
server which is acting on behalf of a user.
+Impersonation is enforced by the Kerberos principal and the host from which 
the RPC originated (from the perspective
+of the Accumulo TabletServers/Masters). An asterisk (*) can be used to specify 
all users or all hosts (depending on the context).
 
 ===== Delegation Tokens
 
@@ -299,7 +315,7 @@ Within Accumulo services, the primary task to implement 
delegation tokens is the
 of a shared secret among all Accumulo tabletservers and the master. The secret 
key allows for generation
 of delegation tokens for users and verification of delegation tokens presented 
by clients. If a server
 process is unaware of the secret key used to create a delegation token, the 
client cannot be authenticated.
-As ZooKeeper distribution is an asynchronous operation (typically on the order 
of seconds), the 
+As ZooKeeper distribution is an asynchronous operation (typically on the order 
of seconds), the
 value for `general.delegation.token.update.interval` should be on the order of 
hours to days to reduce the
 likelihood of servers rejecting valid clients because the server did not yet 
see a new secret key.
 
@@ -422,7 +438,7 @@ JVM to each YARN task is secure, even in multi-tenant 
instances.
 
 ==== Debugging
 
-*Q*: I have valid Kerberos credentials and a correct client configuration file 
but 
+*Q*: I have valid Kerberos credentials and a correct client configuration file 
but
 I still get errors like:
 
 ----
@@ -436,7 +452,7 @@ value, and ensure it matches the value reported by `klist`.
 ----
 $ echo $KRB5CCNAME
 
-$ klist 
+$ klist
 Ticket cache: FILE:/tmp/krb5cc_123
 Default principal: u...@example.com
 
@@ -462,7 +478,7 @@ diagnose some high-level configuration problem. Client 
applications can add this
 hand to the command line and Accumulo server processes or applications started 
using the `accumulo`
 script by adding the property to +ACCUMULO_GENERAL_OPTS+ in 
+$ACCUMULO_CONF_DIR/accumulo-env.sh+.
 
-Additionally, you can increase the log4j levels on 
+org.apache.hadoop.security+, which includes the 
+Additionally, you can increase the log4j levels on 
+org.apache.hadoop.security+, which includes the
 Hadoop +UserGroupInformation+ class, which will include some high-level debug 
statements. This
 can be controlled in your client application, or using 
+$ACCUMULO_CONF_DIR/generic_logger.xml+
 
@@ -513,7 +529,7 @@ Caused by: KrbException: Identifier doesn't match expected 
value (906)
         ... 25 more
 ----
 
-or 
+or
 
 ----
 2015-01-12 14:47:29,440 [server.TThreadPoolServer] ERROR: Error occurred 
during processing of message.

http://git-wip-us.apache.org/repos/asf/accumulo/blob/e43e9273/server/base/src/main/java/org/apache/accumulo/server/security/UserImpersonation.java
----------------------------------------------------------------------
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/security/UserImpersonation.java
 
b/server/base/src/main/java/org/apache/accumulo/server/security/UserImpersonation.java
index 2a1fd00..97bc858 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/security/UserImpersonation.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/security/UserImpersonation.java
@@ -35,9 +35,12 @@ import org.slf4j.LoggerFactory;
  * When SASL is enabled, this parses properties from the site configuration to 
build up a set of all users capable of impersonating another user, the users
  * which may be impersonated and the hosts in which the impersonator may issue 
requests from.
  *
- * <code>rpc_user=&gt;{allowed_accumulo_users=[...], 
allowed_client_hosts=[...]</code>
+ * <code>INSTANCE_RPC_SASL_PROXYUSERS=rpc_user={allowed_accumulo_users=[...], 
allowed_client_hosts=[...]</code>
+ * 
<code>INSTANCE_RPC_SASL_ALLOWED_USER_IMPERSONATION=rpc_user:user,user,user;...</code>
+ * <code>INSTANCE_RPC_SASL_ALLOWED_HOST_IMPERSONATION=host,host:host...</code>
  *
- * @see Property#INSTANCE_RPC_SASL_PROXYUSERS
+ * @see Property#INSTANCE_RPC_SASL_ALLOWED_USER_IMPERSONATION
+ * @see Property#INSTANCE_RPC_SASL_ALLOWED_HOST_IMPERSONATION
  */
 public class UserImpersonation {
 
@@ -170,11 +173,97 @@ public class UserImpersonation {
 
   private final Map<String,UsersWithHosts> proxyUsers;
 
+  @SuppressWarnings("deprecation")
   public UserImpersonation(AccumuloConfiguration conf) {
-    Map<String,String> entries = 
conf.getAllPropertiesWithPrefix(Property.INSTANCE_RPC_SASL_PROXYUSERS);
     proxyUsers = new HashMap<>();
+
+    // Property.INSTANCE_RPC_SASL_ALLOWED_USER_IMPERSONATION is treated as the 
"new config style" switch
+    final String userConfig = 
conf.get(Property.INSTANCE_RPC_SASL_ALLOWED_USER_IMPERSONATION);
+    if 
(!Property.INSTANCE_RPC_SASL_ALLOWED_USER_IMPERSONATION.getDefaultValue().equals(userConfig))
 {
+      String hostConfig = 
conf.get(Property.INSTANCE_RPC_SASL_ALLOWED_HOST_IMPERSONATION);
+      parseOnelineConfiguration(userConfig, hostConfig);
+    } else {
+      // Otherwise, assume the old-style
+      
parseMultiPropertyConfiguration(conf.getAllPropertiesWithPrefix(Property.INSTANCE_RPC_SASL_PROXYUSERS));
+    }
+  }
+
+  /**
+   * Parses the impersonation configuration for all users from a single 
property.
+   *
+   * @param userConfigString
+   *          Semi-colon separated list of {@code 
remoteUser:alloweduser,alloweduser,...}.
+   * @param hostConfigString
+   *          Semi-colon separated list of hosts.
+   */
+  private void parseOnelineConfiguration(String userConfigString, String 
hostConfigString) {
+    // Pull out the config values, defaulting to at least one value
+    final String[] userConfigs;
+    if (userConfigString.trim().isEmpty()) {
+      userConfigs = new String[] {""};
+    } else {
+      userConfigs = StringUtils.split(userConfigString, ';');
+    }
+    final String[] hostConfigs;
+    if (hostConfigString.trim().isEmpty()) {
+      hostConfigs = new String[] {""};
+    } else {
+      hostConfigs = StringUtils.split(hostConfigString, ';');
+    }
+
+    if (userConfigs.length != hostConfigs.length) {
+      String msg = String.format("Should have equal number of user and host 
impersonation elements in configuration. Got %d and %d elements, respectively.",
+          userConfigs.length, hostConfigs.length);
+      throw new IllegalArgumentException(msg);
+    }
+
+    for (int i = 0; i < userConfigs.length; i++) {
+      final String userConfig = userConfigs[i];
+      final String hostConfig = hostConfigs[i];
+
+      final String[] splitUserConfig = StringUtils.split(userConfig, ':');
+      if (2 != splitUserConfig.length) {
+        throw new IllegalArgumentException("Expect a single colon-separated 
pair, but found '" + userConfig + "'");
+      }
+
+      final String remoteUser = splitUserConfig[0];
+      final String allowedImpersonationsForRemoteUser = splitUserConfig[1];
+      final UsersWithHosts usersWithHosts = new UsersWithHosts();
+
+      proxyUsers.put(remoteUser.trim(), usersWithHosts);
+
+      if (ALL.equals(allowedImpersonationsForRemoteUser)) {
+        usersWithHosts.setAcceptAllUsers(true);
+      } else {
+        String[] allowedUsers = 
StringUtils.split(allowedImpersonationsForRemoteUser, ",");
+        Set<String> usersSet = new HashSet<>();
+        usersSet.addAll(Arrays.asList(allowedUsers));
+        usersWithHosts.setUsers(usersSet);
+      }
+
+      if (ALL.equals(hostConfig)) {
+        usersWithHosts.setAcceptAllHosts(true);
+      } else {
+        String[] allowedHosts = StringUtils.split(hostConfig, ",");
+        Set<String> hostsSet = new HashSet<>();
+        hostsSet.addAll(Arrays.asList(allowedHosts));
+        usersWithHosts.setHosts(hostsSet);
+      }
+    }
+  }
+
+  /**
+   * Parses all properties that start with {@link 
Property#INSTANCE_RPC_SASL_PROXYUSERS}. This approach was the original 
configuration method, but does not work
+   * with Ambari.
+   *
+   * @param configProperties
+   *          The relevant configuration properties for impersonation.
+   */
+  @SuppressWarnings("javadoc")
+  private void parseMultiPropertyConfiguration(Map<String,String> 
configProperties) {
+    @SuppressWarnings("deprecation")
     final String configKey = Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey();
-    for (Entry<String,String> entry : entries.entrySet()) {
+    for (Entry<String,String> entry : configProperties.entrySet()) {
       String aclKey = entry.getKey().substring(configKey.length());
       int index = aclKey.lastIndexOf('.');
 

http://git-wip-us.apache.org/repos/asf/accumulo/blob/e43e9273/server/base/src/test/java/org/apache/accumulo/server/rpc/TCredentialsUpdatingInvocationHandlerTest.java
----------------------------------------------------------------------
diff --git 
a/server/base/src/test/java/org/apache/accumulo/server/rpc/TCredentialsUpdatingInvocationHandlerTest.java
 
b/server/base/src/test/java/org/apache/accumulo/server/rpc/TCredentialsUpdatingInvocationHandlerTest.java
index c2d182e..740acd9 100644
--- 
a/server/base/src/test/java/org/apache/accumulo/server/rpc/TCredentialsUpdatingInvocationHandlerTest.java
+++ 
b/server/base/src/test/java/org/apache/accumulo/server/rpc/TCredentialsUpdatingInvocationHandlerTest.java
@@ -17,6 +17,7 @@
 package org.apache.accumulo.server.rpc;
 
 import java.nio.ByteBuffer;
+import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -24,7 +25,9 @@ import 
org.apache.accumulo.core.client.impl.thrift.ThriftSecurityException;
 import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
 import org.apache.accumulo.core.client.security.tokens.KerberosToken;
 import org.apache.accumulo.core.client.security.tokens.PasswordToken;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.ConfigurationCopy;
+import org.apache.accumulo.core.conf.DefaultConfiguration;
 import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.core.security.thrift.TCredentials;
 import org.junit.After;
@@ -32,14 +35,34 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.base.Predicate;
+
 public class TCredentialsUpdatingInvocationHandlerTest {
+  private static final DefaultConfiguration DEFAULT_CONFIG = 
DefaultConfiguration.getInstance();
 
   TCredentialsUpdatingInvocationHandler<Object> proxy;
-  ConfigurationCopy conf;
+  ConfigurationCopy cc;
+  AccumuloConfiguration conf;
 
   @Before
   public void setup() {
-    conf = new ConfigurationCopy();
+    cc = new ConfigurationCopy();
+    conf = new AccumuloConfiguration() {
+      @Override
+      public String get(Property property) {
+        String value = cc.get(property);
+        if (null == value) {
+          return DEFAULT_CONFIG.get(property);
+        }
+        return value;
+      }
+
+      @Override
+      public void getProperties(Map<String,String> props, Predicate<String> 
filter) {
+        cc.getProperties(props, filter);
+      }
+    };
+
     proxy = new TCredentialsUpdatingInvocationHandler<Object>(new Object(), 
conf);
   }
 
@@ -97,8 +120,8 @@ public class TCredentialsUpdatingInvocationHandlerTest {
   @Test
   public void testAllowedAnyImpersonationForAnyUser() throws Exception {
     final String proxyServer = "proxy";
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".users", "*");
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".hosts", "*");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".users", "*");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".hosts", "*");
     proxy = new TCredentialsUpdatingInvocationHandler<Object>(new Object(), 
conf);
     TCredentials tcreds = new TCredentials("client", 
KerberosToken.class.getName(), ByteBuffer.allocate(0), 
UUID.randomUUID().toString());
     UGIAssumingProcessor.rpcPrincipal.set(proxyServer);
@@ -108,8 +131,8 @@ public class TCredentialsUpdatingInvocationHandlerTest {
   @Test
   public void testAllowedImpersonationForSpecificUsers() throws Exception {
     final String proxyServer = "proxy";
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".users", "client1,client2");
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".hosts", "*");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".users", "client1,client2");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".hosts", "*");
     proxy = new TCredentialsUpdatingInvocationHandler<Object>(new Object(), 
conf);
     TCredentials tcreds = new TCredentials("client1", 
KerberosToken.class.getName(), ByteBuffer.allocate(0), 
UUID.randomUUID().toString());
     UGIAssumingProcessor.rpcPrincipal.set(proxyServer);
@@ -122,8 +145,8 @@ public class TCredentialsUpdatingInvocationHandlerTest {
   public void testDisallowedImpersonationForUser() throws Exception {
     final String proxyServer = "proxy";
     // let "otherproxy" impersonate, but not "proxy"
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy" + 
".users", "*");
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy" + 
".hosts", "*");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy" + 
".users", "*");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy" + 
".hosts", "*");
     proxy = new TCredentialsUpdatingInvocationHandler<Object>(new Object(), 
conf);
     TCredentials tcreds = new TCredentials("client", 
KerberosToken.class.getName(), ByteBuffer.allocate(0), 
UUID.randomUUID().toString());
     UGIAssumingProcessor.rpcPrincipal.set(proxyServer);
@@ -134,10 +157,10 @@ public class TCredentialsUpdatingInvocationHandlerTest {
   public void testDisallowedImpersonationForMultipleUsers() throws Exception {
     final String proxyServer = "proxy";
     // let "otherproxy" impersonate, but not "proxy"
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy1" + 
".users", "*");
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy1" + 
".hosts", "*");
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy2" + 
".users", "client1,client2");
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy2" + 
".hosts", "*");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy1" + 
".users", "*");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy1" + 
".hosts", "*");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy2" + 
".users", "client1,client2");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + "otherproxy2" + 
".hosts", "*");
     proxy = new TCredentialsUpdatingInvocationHandler<Object>(new Object(), 
conf);
     TCredentials tcreds = new TCredentials("client1", 
KerberosToken.class.getName(), ByteBuffer.allocate(0), 
UUID.randomUUID().toString());
     UGIAssumingProcessor.rpcPrincipal.set(proxyServer);
@@ -147,8 +170,8 @@ public class TCredentialsUpdatingInvocationHandlerTest {
   @Test
   public void testAllowedImpersonationFromSpecificHost() throws Exception {
     final String proxyServer = "proxy", client = "client", host = 
"host.domain.com";
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".users", client);
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".hosts", host);
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".users", client);
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".hosts", host);
     proxy = new TCredentialsUpdatingInvocationHandler<Object>(new Object(), 
conf);
     TCredentials tcreds = new TCredentials("client", 
KerberosToken.class.getName(), ByteBuffer.allocate(0), 
UUID.randomUUID().toString());
     UGIAssumingProcessor.rpcPrincipal.set(proxyServer);
@@ -159,8 +182,8 @@ public class TCredentialsUpdatingInvocationHandlerTest {
   @Test(expected = ThriftSecurityException.class)
   public void testDisallowedImpersonationFromSpecificHost() throws Exception {
     final String proxyServer = "proxy", client = "client", host = 
"host.domain.com";
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".users", client);
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".hosts", host);
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".users", client);
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + proxyServer + 
".hosts", host);
     proxy = new TCredentialsUpdatingInvocationHandler<Object>(new Object(), 
conf);
     TCredentials tcreds = new TCredentials("client", 
KerberosToken.class.getName(), ByteBuffer.allocate(0), 
UUID.randomUUID().toString());
     UGIAssumingProcessor.rpcPrincipal.set(proxyServer);

http://git-wip-us.apache.org/repos/asf/accumulo/blob/e43e9273/server/base/src/test/java/org/apache/accumulo/server/security/UserImpersonationTest.java
----------------------------------------------------------------------
diff --git 
a/server/base/src/test/java/org/apache/accumulo/server/security/UserImpersonationTest.java
 
b/server/base/src/test/java/org/apache/accumulo/server/security/UserImpersonationTest.java
index 0f4159b..7422db4 100644
--- 
a/server/base/src/test/java/org/apache/accumulo/server/security/UserImpersonationTest.java
+++ 
b/server/base/src/test/java/org/apache/accumulo/server/security/UserImpersonationTest.java
@@ -24,8 +24,12 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
 
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.ConfigurationCopy;
+import org.apache.accumulo.core.conf.DefaultConfiguration;
 import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.server.security.UserImpersonation.AlwaysTrueSet;
 import org.apache.accumulo.server.security.UserImpersonation.UsersWithHosts;
@@ -33,17 +37,34 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
 
-/**
- *
- */
 public class UserImpersonationTest {
 
-  private ConfigurationCopy conf;
+  private ConfigurationCopy cc;
+  private AccumuloConfiguration conf;
 
   @Before
   public void setup() {
-    conf = new ConfigurationCopy(new HashMap<String,String>());
+    cc = new ConfigurationCopy(new HashMap<String,String>());
+    conf = new AccumuloConfiguration() {
+      DefaultConfiguration defaultConfig = DefaultConfiguration.getInstance();
+
+      @Override
+      public String get(Property property) {
+        String value = cc.get(property);
+        if (null == value) {
+          return defaultConfig.get(property);
+        }
+        return value;
+      }
+
+      @Override
+      public void getProperties(Map<String,String> props, Predicate<String> 
filter) {
+        cc.getProperties(props, filter);
+      }
+    };
   }
 
   void setValidHosts(String user, String hosts) {
@@ -54,8 +75,24 @@ public class UserImpersonationTest {
     setUsersOrHosts(user, ".users", users);
   }
 
+  @SuppressWarnings("deprecation")
   void setUsersOrHosts(String user, String suffix, String value) {
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + user + suffix, 
value);
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + user + suffix, 
value);
+  }
+
+  void setValidHostsNewConfig(String user, String... hosts) {
+    cc.set(Property.INSTANCE_RPC_SASL_ALLOWED_HOST_IMPERSONATION.getKey(), 
Joiner.on(';').join(hosts));
+  }
+
+  void setValidUsersNewConfig(Map<String,String> remoteToAllowedUsers) {
+    StringBuilder sb = new StringBuilder();
+    for (Entry<String,String> entry : remoteToAllowedUsers.entrySet()) {
+      if (sb.length() > 0) {
+        sb.append(";");
+      }
+      sb.append(entry.getKey()).append(":").append(entry.getValue());
+    }
+    cc.set(Property.INSTANCE_RPC_SASL_ALLOWED_USER_IMPERSONATION, 
sb.toString());
   }
 
   @Test
@@ -76,6 +113,23 @@ public class UserImpersonationTest {
   }
 
   @Test
+  public void testAnyUserAndHostsNewConfig() {
+    String server = "server";
+    setValidHostsNewConfig(server, "*");
+    setValidUsersNewConfig(ImmutableMap.of(server, "*"));
+    UserImpersonation impersonation = new UserImpersonation(conf);
+
+    UsersWithHosts uwh = impersonation.get(server);
+    assertNotNull(uwh);
+
+    assertTrue(uwh.acceptsAllHosts());
+    assertTrue(uwh.acceptsAllUsers());
+
+    assertEquals(AlwaysTrueSet.class, uwh.getHosts().getClass());
+    assertEquals(AlwaysTrueSet.class, uwh.getUsers().getClass());
+  }
+
+  @Test
   public void testNoHostByDefault() {
     String server = "server";
     setValidUsers(server, "*");
@@ -92,6 +146,22 @@ public class UserImpersonationTest {
   }
 
   @Test
+  public void testNoHostByDefaultNewConfig() {
+    String server = "server";
+    setValidUsersNewConfig(ImmutableMap.of(server, "*"));
+    UserImpersonation impersonation = new UserImpersonation(conf);
+
+    UsersWithHosts uwh = impersonation.get(server);
+    assertNotNull(uwh);
+
+    assertFalse(uwh.acceptsAllHosts());
+    assertTrue(uwh.acceptsAllUsers());
+
+    assertNotEquals(AlwaysTrueSet.class, uwh.getHosts().getClass());
+    assertEquals(AlwaysTrueSet.class, uwh.getUsers().getClass());
+  }
+
+  @Test
   public void testNoUsersByDefault() {
     String server = "server";
     setValidHosts(server, "*");
@@ -108,6 +178,16 @@ public class UserImpersonationTest {
   }
 
   @Test
+  public void testNoUsersByDefaultNewConfig() {
+    String server = "server";
+    setValidHostsNewConfig(server, "*");
+    UserImpersonation impersonation = new UserImpersonation(conf);
+
+    UsersWithHosts uwh = impersonation.get(server);
+    assertNull("Impersonation config should be drive by user element, not 
host", uwh);
+  }
+
+  @Test
   public void testSingleUserAndHost() {
     String server = "server", host = "single_host.domain.com", client = 
"single_client";
     setValidHosts(server, host);
@@ -131,6 +211,29 @@ public class UserImpersonationTest {
   }
 
   @Test
+  public void testSingleUserAndHostNewConfig() {
+    String server = "server", host = "single_host.domain.com", client = 
"single_client";
+    setValidHostsNewConfig(server, host);
+    setValidUsersNewConfig(ImmutableMap.of(server, client));
+    UserImpersonation impersonation = new UserImpersonation(conf);
+
+    UsersWithHosts uwh = impersonation.get(server);
+    assertNotNull(uwh);
+
+    assertFalse(uwh.acceptsAllHosts());
+    assertFalse(uwh.acceptsAllUsers());
+
+    assertNotEquals(AlwaysTrueSet.class, uwh.getHosts().getClass());
+    assertNotEquals(AlwaysTrueSet.class, uwh.getUsers().getClass());
+
+    assertTrue(uwh.getUsers().contains(client));
+    assertTrue(uwh.getHosts().contains(host));
+
+    assertFalse(uwh.getUsers().contains("some_other_user"));
+    assertFalse(uwh.getHosts().contains("other_host.domain.com"));
+  }
+
+  @Test
   public void testMultipleExplicitUsers() {
     String server = "server", client1 = "client1", client2 = "client2", 
client3 = "client3";
     setValidHosts(server, "*");
@@ -153,6 +256,28 @@ public class UserImpersonationTest {
   }
 
   @Test
+  public void testMultipleExplicitUsersNewConfig() {
+    String server = "server", client1 = "client1", client2 = "client2", 
client3 = "client3";
+    setValidHostsNewConfig(server, "*");
+    setValidUsersNewConfig(ImmutableMap.of(server, 
Joiner.on(',').join(client1, client2, client3)));
+    UserImpersonation impersonation = new UserImpersonation(conf);
+
+    UsersWithHosts uwh = impersonation.get(server);
+    assertNotNull(uwh);
+
+    assertTrue(uwh.acceptsAllHosts());
+    assertFalse(uwh.acceptsAllUsers());
+
+    assertEquals(AlwaysTrueSet.class, uwh.getHosts().getClass());
+    assertNotEquals(AlwaysTrueSet.class, uwh.getUsers().getClass());
+
+    assertTrue(uwh.getUsers().contains(client1));
+    assertTrue(uwh.getUsers().contains(client2));
+    assertTrue(uwh.getUsers().contains(client3));
+    assertFalse(uwh.getUsers().contains("other_client"));
+  }
+
+  @Test
   public void testMultipleExplicitHosts() {
     String server = "server", host1 = "host1", host2 = "host2", host3 = 
"host3";
     setValidHosts(server, Joiner.on(',').join(host1, host2, host3));
@@ -175,6 +300,28 @@ public class UserImpersonationTest {
   }
 
   @Test
+  public void testMultipleExplicitHostsNewConfig() {
+    String server = "server", host1 = "host1", host2 = "host2", host3 = 
"host3";
+    setValidHostsNewConfig(server, Joiner.on(',').join(host1, host2, host3));
+    setValidUsersNewConfig(ImmutableMap.of(server, "*"));
+    UserImpersonation impersonation = new UserImpersonation(conf);
+
+    UsersWithHosts uwh = impersonation.get(server);
+    assertNotNull(uwh);
+
+    assertFalse(uwh.acceptsAllHosts());
+    assertTrue(uwh.acceptsAllUsers());
+
+    assertNotEquals(AlwaysTrueSet.class, uwh.getHosts().getClass());
+    assertEquals(AlwaysTrueSet.class, uwh.getUsers().getClass());
+
+    assertTrue(uwh.getHosts().contains(host1));
+    assertTrue(uwh.getHosts().contains(host2));
+    assertTrue(uwh.getHosts().contains(host3));
+    assertFalse(uwh.getHosts().contains("other_host"));
+  }
+
+  @Test
   public void testMultipleExplicitUsersHosts() {
     String server = "server", host1 = "host1", host2 = "host2", host3 = 
"host3", client1 = "client1", client2 = "client2", client3 = "client3";
     setValidHosts(server, Joiner.on(',').join(host1, host2, host3));
@@ -202,6 +349,33 @@ public class UserImpersonationTest {
   }
 
   @Test
+  public void testMultipleExplicitUsersHostsNewConfig() {
+    String server = "server", host1 = "host1", host2 = "host2", host3 = 
"host3", client1 = "client1", client2 = "client2", client3 = "client3";
+    setValidHostsNewConfig(server, Joiner.on(',').join(host1, host2, host3));
+    setValidUsersNewConfig(ImmutableMap.of(server, 
Joiner.on(',').join(client1, client2, client3)));
+    UserImpersonation impersonation = new UserImpersonation(conf);
+
+    UsersWithHosts uwh = impersonation.get(server);
+    assertNotNull(uwh);
+
+    assertFalse(uwh.acceptsAllHosts());
+    assertFalse(uwh.acceptsAllUsers());
+
+    assertNotEquals(AlwaysTrueSet.class, uwh.getHosts().getClass());
+    assertNotEquals(AlwaysTrueSet.class, uwh.getUsers().getClass());
+
+    assertTrue(uwh.getUsers().contains(client1));
+    assertTrue(uwh.getUsers().contains(client2));
+    assertTrue(uwh.getUsers().contains(client3));
+    assertFalse(uwh.getUsers().contains("other_client"));
+
+    assertTrue(uwh.getHosts().contains(host1));
+    assertTrue(uwh.getHosts().contains(host2));
+    assertTrue(uwh.getHosts().contains(host3));
+    assertFalse(uwh.getHosts().contains("other_host"));
+  }
+
+  @Test
   public void testMultipleAllowedImpersonators() {
     String server1 = "server1", server2 = "server2", host1 = "host1", host2 = 
"host2", host3 = "host3", client1 = "client1", client2 = "client2", client3 = 
"client3";
     // server1 can impersonate client1 and client2 from host1 or host2
@@ -255,10 +429,79 @@ public class UserImpersonationTest {
   }
 
   @Test
+  public void testMultipleAllowedImpersonatorsNewConfig() {
+    String server1 = "server1", server2 = "server2", host1 = "host1", host2 = 
"host2", host3 = "host3", client1 = "client1", client2 = "client2", client3 = 
"client3";
+    // server1 can impersonate client1 and client2 from host1 or host2
+    // server2 can impersonate only client3 from host3
+    setValidHostsNewConfig(server1, Joiner.on(',').join(host1, host2), host3);
+    setValidUsersNewConfig(ImmutableMap.of(server1, 
Joiner.on(',').join(client1, client2), server2, client3));
+    UserImpersonation impersonation = new UserImpersonation(conf);
+
+    UsersWithHosts uwh = impersonation.get(server1);
+    assertNotNull(uwh);
+
+    assertFalse(uwh.acceptsAllHosts());
+    assertFalse(uwh.acceptsAllUsers());
+
+    assertNotEquals(AlwaysTrueSet.class, uwh.getHosts().getClass());
+    assertNotEquals(AlwaysTrueSet.class, uwh.getUsers().getClass());
+
+    assertTrue(uwh.getUsers().contains(client1));
+    assertTrue(uwh.getUsers().contains(client2));
+    assertFalse(uwh.getUsers().contains(client3));
+    assertFalse(uwh.getUsers().contains("other_client"));
+
+    assertTrue(uwh.getHosts().contains(host1));
+    assertTrue(uwh.getHosts().contains(host2));
+    assertFalse(uwh.getHosts().contains(host3));
+    assertFalse(uwh.getHosts().contains("other_host"));
+
+    uwh = impersonation.get(server2);
+    assertNotNull(uwh);
+
+    assertFalse(uwh.acceptsAllHosts());
+    assertFalse(uwh.acceptsAllUsers());
+
+    assertNotEquals(AlwaysTrueSet.class, uwh.getHosts().getClass());
+    assertNotEquals(AlwaysTrueSet.class, uwh.getUsers().getClass());
+
+    assertFalse(uwh.getUsers().contains(client1));
+    assertFalse(uwh.getUsers().contains(client2));
+    assertTrue(uwh.getUsers().contains(client3));
+    assertFalse(uwh.getUsers().contains("other_client"));
+
+    assertFalse(uwh.getHosts().contains(host1));
+    assertFalse(uwh.getHosts().contains(host2));
+    assertTrue(uwh.getHosts().contains(host3));
+    assertFalse(uwh.getHosts().contains("other_host"));
+
+    // client3 is not allowed to impersonate anyone
+    assertNull(impersonation.get(client3));
+  }
+
+  @SuppressWarnings("deprecation")
+  @Test
   public void testSingleUser() throws Exception {
     final String server = "server/hostn...@example.com", client = 
"cli...@example.com";
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + server + 
".users", client);
-    conf.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + server + 
".hosts", "*");
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + server + ".users", 
client);
+    cc.set(Property.INSTANCE_RPC_SASL_PROXYUSERS.getKey() + server + ".hosts", 
"*");
+    UserImpersonation impersonation = new UserImpersonation(conf);
+
+    UsersWithHosts uwh = impersonation.get(server);
+
+    assertNotNull(uwh);
+
+    assertTrue(uwh.acceptsAllHosts());
+    assertFalse(uwh.acceptsAllUsers());
+
+    assertTrue(uwh.getUsers().contains(client));
+  }
+
+  @Test
+  public void testSingleUserNewConfig() throws Exception {
+    final String server = "server/hostn...@example.com", client = 
"cli...@example.com";
+    cc.set(Property.INSTANCE_RPC_SASL_ALLOWED_USER_IMPERSONATION, server + ":" 
+ client);
+    cc.set(Property.INSTANCE_RPC_SASL_ALLOWED_HOST_IMPERSONATION, "*");
     UserImpersonation impersonation = new UserImpersonation(conf);
 
     UsersWithHosts uwh = impersonation.get(server);

Reply via email to