浏览代码

HADOOP-6791. Refresh for proxy superuser config

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@951081 13f79535-47bb-0310-9956-ffa450edef68
Boris Shkolnik 15 年之前
父节点
当前提交
9e2c3bf9ed

+ 3 - 0
CHANGES.txt

@@ -3,6 +3,9 @@ Hadoop Change Log
 Trunk (unreleased changes)
 Trunk (unreleased changes)
 
 
   NEW FEATURES
   NEW FEATURES
+   HADOOP-6791.  Refresh for proxy superuser config
+    (common part for HDFS-1096) (boryas)
+
    HADOOP-6581. Add authenticated TokenIdentifiers to UGI so that 
    HADOOP-6581. Add authenticated TokenIdentifiers to UGI so that 
    they can be used for authorization (Kan Zhang and Jitendra Pandey 
    they can be used for authorization (Kan Zhang and Jitendra Pandey 
    via jghoman)
    via jghoman)

+ 23 - 0
src/java/org/apache/hadoop/conf/Configuration.java

@@ -1718,6 +1718,29 @@ public class Configuration implements Iterable<Map.Entry<String,String>>,
       org.apache.hadoop.io.Text.writeString(out, (String) item.getValue());
       org.apache.hadoop.io.Text.writeString(out, (String) item.getValue());
     }
     }
   }
   }
+  
+  /**
+   * get keys matching the the regex 
+   * @param regex
+   * @return Map<String,String> with matching keys
+   */
+  public Map<String,String> getValByRegex(String regex) {
+    Pattern p = Pattern.compile(regex);
+
+    Map<String,String> result = new HashMap<String,String>();
+    Matcher m;
+
+    for(Map.Entry<Object,Object> item: getProps().entrySet()) {
+      if (item.getKey() instanceof String && 
+          item.getValue() instanceof String) {
+        m = p.matcher((String)item.getKey());
+        if(m.find()) { // match
+          result.put((String) item.getKey(), (String) item.getValue());
+        }
+      }
+    }
+    return result;
+  }
 
 
   //Load deprecated keys in common
   //Load deprecated keys in common
   private static void addDeprecatedKeys() {
   private static void addDeprecatedKeys() {

+ 9 - 1
src/java/org/apache/hadoop/security/RefreshUserToGroupMappingsProtocol.java → src/java/org/apache/hadoop/security/RefreshUserMappingsProtocol.java

@@ -30,7 +30,7 @@ import org.apache.hadoop.security.KerberosInfo;
  */
  */
 @KerberosInfo(
 @KerberosInfo(
     serverPrincipal=CommonConfigurationKeys.HADOOP_SECURITY_SERVICE_USER_NAME_KEY)
     serverPrincipal=CommonConfigurationKeys.HADOOP_SECURITY_SERVICE_USER_NAME_KEY)
-public interface RefreshUserToGroupMappingsProtocol extends VersionedProtocol {
+public interface RefreshUserMappingsProtocol extends VersionedProtocol {
   
   
   /**
   /**
    * Version 1: Initial version.
    * Version 1: Initial version.
@@ -43,4 +43,12 @@ public interface RefreshUserToGroupMappingsProtocol extends VersionedProtocol {
    * @throws IOException
    * @throws IOException
    */
    */
   public void refreshUserToGroupsMappings(Configuration conf) throws IOException;
   public void refreshUserToGroupsMappings(Configuration conf) throws IOException;
+  
+  /**
+   * Refresh superuser proxy group list
+   * @param conf
+   * @throws IOException
+   */
+  public void refreshSuperUserGroupsConfiguration(Configuration conf) 
+  throws IOException;
 }
 }

+ 67 - 18
src/java/org/apache/hadoop/security/authorize/ProxyUsers.java

@@ -21,54 +21,101 @@ package org.apache.hadoop.security.authorize;
 import java.net.InetAddress;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.net.UnknownHostException;
 import java.util.Collection;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
 
 
+import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.UserGroupInformation;
-import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.util.StringUtils;
 
 
 @InterfaceAudience.Private
 @InterfaceAudience.Private
 public class ProxyUsers {
 public class ProxyUsers {
 
 
-  /*
+  private static final String CONF_HOSTS = ".hosts";
+  public static final String CONF_GROUPS = ".groups";
+  public static final String CONF_HADOOP_PROXYUSER = "hadoop.proxyuser.";
+  public static final String CONF_HADOOP_PROXYUSER_RE = "hadoop\\.proxyuser\\.";
+  private static Configuration conf=null;
+  // list of groups and hosts per proxyuser
+  private static Map<String, Collection<String>> proxyGroups = 
+    new HashMap<String, Collection<String>>();
+  private static Map<String, Collection<String>> proxyHosts = 
+    new HashMap<String, Collection<String>>();
+
+  /**
+   * reread the conf and get new values for "hadoop.proxyuser.*.groups/hosts"
+   */
+  public static synchronized void refreshSuperUserGroupsConfiguration(Configuration cn) {
+    conf = cn;
+
+    // remove alle existing stuff
+    proxyGroups.clear();
+    proxyHosts.clear();
+
+    // get all the new keys for groups
+    String regex = CONF_HADOOP_PROXYUSER_RE+"[^.]*\\"+CONF_GROUPS;
+    Map<String,String> allMatchKeys = conf.getValByRegex(regex);
+    for(Entry<String, String> entry : allMatchKeys.entrySet()) {
+      proxyGroups.put(entry.getKey(), 
+          StringUtils.getStringCollection(entry.getValue()));
+    }
+
+    // now hosts
+    regex = CONF_HADOOP_PROXYUSER_RE+"[^.]*\\"+CONF_HOSTS;
+    allMatchKeys = conf.getValByRegex(regex);
+    for(Entry<String, String> entry : allMatchKeys.entrySet()) {
+      proxyHosts.put(entry.getKey(),
+          StringUtils.getStringCollection(entry.getValue()));
+    }
+  }
+
+  /**
    * Returns configuration key for effective user groups allowed for a superuser
    * Returns configuration key for effective user groups allowed for a superuser
    * 
    * 
    * @param userName name of the superuser
    * @param userName name of the superuser
    * @return configuration key for superuser groups
    * @return configuration key for superuser groups
    */
    */
   public static String getProxySuperuserGroupConfKey(String userName) {
   public static String getProxySuperuserGroupConfKey(String userName) {
-    return "hadoop.proxyuser."+userName+".groups";
+    return ProxyUsers.CONF_HADOOP_PROXYUSER+userName+ProxyUsers.CONF_GROUPS;
   }
   }
   
   
-  /*
+  /**
    * Return configuration key for superuser ip addresses
    * Return configuration key for superuser ip addresses
    * 
    * 
    * @param userName name of the superuser
    * @param userName name of the superuser
    * @return configuration key for superuser ip-addresses
    * @return configuration key for superuser ip-addresses
    */
    */
   public static String getProxySuperuserIpConfKey(String userName) {
   public static String getProxySuperuserIpConfKey(String userName) {
-    return "hadoop.proxyuser."+userName+".hosts";
+    return ProxyUsers.CONF_HADOOP_PROXYUSER+userName+ProxyUsers.CONF_HOSTS;
   }
   }
   
   
-  /*
+  /**
    * Authorize the superuser which is doing doAs
    * Authorize the superuser which is doing doAs
    * 
    * 
    * @param user ugi of the effective or proxy user which contains a real user
    * @param user ugi of the effective or proxy user which contains a real user
    * @param remoteAddress the ip address of client
    * @param remoteAddress the ip address of client
-   * @param conf configuration
+   * @param newConf configuration
    * @throws AuthorizationException
    * @throws AuthorizationException
    */
    */
-  public static void authorize(UserGroupInformation user, String remoteAddress,
-      Configuration conf) throws AuthorizationException {
+  public static synchronized void authorize(UserGroupInformation user, 
+      String remoteAddress, Configuration newConf) throws AuthorizationException {
+
+    if(conf == null) {
+      refreshSuperUserGroupsConfiguration(newConf); 
+    }
 
 
     if (user.getRealUser() == null) {
     if (user.getRealUser() == null) {
       return;
       return;
     }
     }
     boolean groupAuthorized = false;
     boolean groupAuthorized = false;
+    boolean ipAuthorized = false;
     UserGroupInformation superUser = user.getRealUser();
     UserGroupInformation superUser = user.getRealUser();
 
 
-    Collection<String> allowedUserGroups = conf
-        .getStringCollection(getProxySuperuserGroupConfKey(superUser
-            .getShortUserName()));
+    Collection<String> allowedUserGroups = proxyGroups.get(
+        getProxySuperuserGroupConfKey(superUser.getShortUserName()));
+    
     if (!allowedUserGroups.isEmpty()) {
     if (!allowedUserGroups.isEmpty()) {
       for (String group : user.getGroupNames()) {
       for (String group : user.getGroupNames()) {
         if (allowedUserGroups.contains(group)) {
         if (allowedUserGroups.contains(group)) {
@@ -83,9 +130,9 @@ public class ProxyUsers {
           + " is not allowed to impersonate " + user.getUserName());
           + " is not allowed to impersonate " + user.getUserName());
     }
     }
     
     
-    Collection<String> ipList = conf
-        .getStringCollection(getProxySuperuserIpConfKey(superUser
-            .getShortUserName()));
+    Collection<String> ipList = proxyHosts.get(
+        getProxySuperuserIpConfKey(superUser.getShortUserName()));
+    
     if (!ipList.isEmpty()) {
     if (!ipList.isEmpty()) {
       for (String allowedHost : ipList) {
       for (String allowedHost : ipList) {
         InetAddress hostAddr;
         InetAddress hostAddr;
@@ -96,11 +143,13 @@ public class ProxyUsers {
         }
         }
         if (hostAddr.getHostAddress().equals(remoteAddress)) {
         if (hostAddr.getHostAddress().equals(remoteAddress)) {
           // Authorization is successful
           // Authorization is successful
-          return;
+          ipAuthorized = true;
         }
         }
       }
       }
     }
     }
-    throw new AuthorizationException("Unauthorized connection for super-user: "
-        + superUser.getUserName() + " from IP " + remoteAddress);
+    if(!ipAuthorized) {
+      throw new AuthorizationException("Unauthorized connection for super-user: "
+          + superUser.getUserName() + " from IP " + remoteAddress);
+    }
   }
   }
 }
 }

+ 21 - 2
src/test/core/org/apache/hadoop/conf/TestConfiguration.java

@@ -24,14 +24,14 @@ import java.io.IOException;
 import java.io.StringWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashMap;
+import java.util.Map;
 import java.util.Random;
 import java.util.Random;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
 
 
 import junit.framework.TestCase;
 import junit.framework.TestCase;
 
 
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.fs.Path;
-import org.codehaus.jackson.map.ObjectMapper;
-
+import org.codehaus.jackson.map.ObjectMapper; 
 
 
 public class TestConfiguration extends TestCase {
 public class TestConfiguration extends TestCase {
 
 
@@ -636,6 +636,25 @@ public class TestConfiguration extends TestCase {
     }
     }
   }
   }
   
   
+    
+  public void testGetValByRegex() {
+    Configuration conf = new Configuration();
+    String key1 = "t.abc.key1";
+    String key2 = "t.abc.key2";
+    String key3 = "tt.abc.key3";
+    String key4 = "t.abc.ey3";
+    conf.set(key1, "value1");
+    conf.set(key2, "value2");
+    conf.set(key3, "value3");
+    conf.set(key4, "value3");
+
+    Map<String,String> res = conf.getValByRegex("^t\\..*\\.key\\d");
+    assertTrue("Conf didn't get key " + key1, res.containsKey(key1));
+    assertTrue("Conf didn't get key " + key2, res.containsKey(key2));
+    assertTrue("Picked out wrong key " + key3, !res.containsKey(key3));
+    assertTrue("Picked out wrong key " + key4, !res.containsKey(key4));
+  }
+
   public static void main(String[] argv) throws Exception {
   public static void main(String[] argv) throws Exception {
     junit.textui.TestRunner.main(new String[]{
     junit.textui.TestRunner.main(new String[]{
       TestConfiguration.class.getName()
       TestConfiguration.class.getName()

+ 18 - 2
src/test/core/org/apache/hadoop/security/TestDoAsEffectiveUser.java

@@ -222,6 +222,8 @@ public class TestDoAsEffectiveUser {
     Server server = RPC.getServer(TestProtocol.class, new TestImpl(), ADDRESS,
     Server server = RPC.getServer(TestProtocol.class, new TestImpl(), ADDRESS,
         0, 2, false, conf, null);
         0, 2, false, conf, null);
 
 
+    refreshConf(conf);
+    
     try {
     try {
       server.start();
       server.start();
 
 
@@ -339,6 +341,7 @@ public class TestDoAsEffectiveUser {
     Server server = RPC.getServer(TestProtocol.class, new TestImpl(), ADDRESS,
     Server server = RPC.getServer(TestProtocol.class, new TestImpl(), ADDRESS,
         0, 2, false, conf, null);
         0, 2, false, conf, null);
 
 
+    
     try {
     try {
       server.start();
       server.start();
 
 
@@ -388,7 +391,8 @@ public class TestDoAsEffectiveUser {
     server.start();
     server.start();
 
 
     final UserGroupInformation current = UserGroupInformation
     final UserGroupInformation current = UserGroupInformation
-        .createRemoteUser(REAL_USER_NAME);
+        .createRemoteUser(REAL_USER_NAME);    
+    
     final InetSocketAddress addr = NetUtils.getConnectAddress(server);
     final InetSocketAddress addr = NetUtils.getConnectAddress(server);
     TestTokenIdentifier tokenId = new TestTokenIdentifier(new Text(current
     TestTokenIdentifier tokenId = new TestTokenIdentifier(new Text(current
         .getUserName()), new Text("SomeSuperUser"));
         .getUserName()), new Text("SomeSuperUser"));
@@ -400,6 +404,9 @@ public class TestDoAsEffectiveUser {
     UserGroupInformation proxyUserUgi = UserGroupInformation
     UserGroupInformation proxyUserUgi = UserGroupInformation
         .createProxyUserForTesting(PROXY_USER_NAME, current, GROUP_NAMES);
         .createProxyUserForTesting(PROXY_USER_NAME, current, GROUP_NAMES);
     proxyUserUgi.addToken(token);
     proxyUserUgi.addToken(token);
+    
+    refreshConf(conf);
+    
     String retVal = proxyUserUgi.doAs(new PrivilegedExceptionAction<String>() {
     String retVal = proxyUserUgi.doAs(new PrivilegedExceptionAction<String>() {
       @Override
       @Override
       public String run() throws Exception {
       public String run() throws Exception {
@@ -441,6 +448,9 @@ public class TestDoAsEffectiveUser {
 
 
     final UserGroupInformation current = UserGroupInformation
     final UserGroupInformation current = UserGroupInformation
         .createUserForTesting(REAL_USER_NAME, GROUP_NAMES);
         .createUserForTesting(REAL_USER_NAME, GROUP_NAMES);
+    
+    refreshConf(newConf);
+    
     final InetSocketAddress addr = NetUtils.getConnectAddress(server);
     final InetSocketAddress addr = NetUtils.getConnectAddress(server);
     TestTokenIdentifier tokenId = new TestTokenIdentifier(new Text(current
     TestTokenIdentifier tokenId = new TestTokenIdentifier(new Text(current
         .getUserName()), new Text("SomeSuperUser"));
         .getUserName()), new Text("SomeSuperUser"));
@@ -469,6 +479,12 @@ public class TestDoAsEffectiveUser {
         }
         }
       }
       }
     });
     });
-    Assert.assertEquals(REAL_USER_NAME + " via SomeSuperUser", retVal);
+    String expected = REAL_USER_NAME + " via SomeSuperUser";
+    Assert.assertEquals(retVal + "!=" + expected, expected, retVal);
+  }
+  
+  //
+  private void refreshConf(Configuration conf) throws IOException {
+    ProxyUsers.refreshSuperUserGroupsConfiguration(conf);
   }
   }
 }
 }