Repository: incubator-ranger
Updated Branches:
  refs/heads/ranger-0.5 3c509cd45 -> 34f7e3b07


RANGER-552 Ranger KMS not able to audit to kerberos HDFS


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

Branch: refs/heads/ranger-0.5
Commit: de946a3f01cf22d37110e25faff03b4ce9aa4b55
Parents: 3c509cd
Author: Don Bosco Durai <[email protected]>
Authored: Fri Jun 12 16:40:45 2015 -0700
Committer: sneethiraj <[email protected]>
Committed: Tue Jun 30 02:57:55 2015 -0400

----------------------------------------------------------------------
 .../audit/destination/HDFSAuditDestination.java |   2 +-
 .../apache/ranger/audit/provider/MiscUtil.java  | 183 +++++++++++++++++--
 .../kafka/authorizer/RangerKafkaAuthorizer.java |  41 +----
 .../kms/authorizer/RangerKmsAuthorizer.java     |  44 ++++-
 4 files changed, 225 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/de946a3f/agents-audit/src/main/java/org/apache/ranger/audit/destination/HDFSAuditDestination.java
----------------------------------------------------------------------
diff --git 
a/agents-audit/src/main/java/org/apache/ranger/audit/destination/HDFSAuditDestination.java
 
b/agents-audit/src/main/java/org/apache/ranger/audit/destination/HDFSAuditDestination.java
index 4fc3a0b..49e5fbb 100644
--- 
a/agents-audit/src/main/java/org/apache/ranger/audit/destination/HDFSAuditDestination.java
+++ 
b/agents-audit/src/main/java/org/apache/ranger/audit/destination/HDFSAuditDestination.java
@@ -216,7 +216,7 @@ public class HDFSAuditDestination extends AuditDestination {
                        FileSystem fileSystem = FileSystem.get(uri, conf);
 
                        Path hdfPath = new Path(fullPath);
-                       logger.info("Checking whether log file exists. 
hdfPath=" + fullPath);
+                       logger.info("Checking whether log file exists. 
hdfPath=" + fullPath + ", UGI=" + MiscUtil.getUGILoginUser());
                        int i = 0;
                        while (fileSystem.exists(hdfPath)) {
                                i++;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/de946a3f/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java
----------------------------------------------------------------------
diff --git 
a/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java 
b/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java
index 6eee55c..bfded93 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java
@@ -20,6 +20,7 @@ import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.rmi.dgc.VMID;
+import java.security.Principal;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -30,18 +31,27 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.UUID;
+import java.util.regex.Pattern;
 
 import javax.security.auth.Subject;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authentication.util.KerberosName;
+import org.apache.hadoop.security.authentication.util.KerberosUtil;
 import org.apache.log4j.helpers.LogLog;
 import org.apache.ranger.authorization.hadoop.utils.RangerCredentialProvider;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 
+import static org.apache.hadoop.util.PlatformName.IBM_JAVA;
+
 public class MiscUtil {
        private static final Log logger = LogFactory.getLog(MiscUtil.class);
 
@@ -64,7 +74,7 @@ public class MiscUtil {
        private static UserGroupInformation ugiLoginUser = null;
        private static Subject subjectLoginUser = null;
 
-       private static Map<String, LogHistory> logHistoryList = new 
Hashtable<String,LogHistory>();
+       private static Map<String, LogHistory> logHistoryList = new 
Hashtable<String, LogHistory>();
        private static int logInterval = 30000; // 30 seconds
 
        static {
@@ -410,19 +420,51 @@ public class MiscUtil {
                return ret;
        }
 
+       public static UserGroupInformation createUGIFromSubject(Subject subject)
+                       throws IOException {
+               logger.info("SUBJECT " + (subject == null ? "not found" : 
"found"));
+               UserGroupInformation ugi = null;
+               if (subject != null) {
+                       logger.info("SUBJECT.PRINCIPALS.size()="
+                                       + subject.getPrincipals().size());
+                       java.util.Set<Principal> principals = 
subject.getPrincipals();
+                       for (Principal principal : principals) {
+                               logger.info("SUBJECT.PRINCIPAL.NAME=" + 
principal.getName());
+                       }
+                       try {
+                               // Do not remove the below statement. The 
default
+                               // getLoginUser does some initialization which 
is needed
+                               // for getUGIFromSubject() to work.
+                               logger.info("Default UGI before using Subject 
from Kafka:"
+                                               + 
UserGroupInformation.getLoginUser());
+                       } catch (Throwable t) {
+                               logger.error(t);
+                       }
+                       ugi = UserGroupInformation.getUGIFromSubject(subject);
+                       logger.info("SUBJECT.UGI.NAME=" + ugi.getUserName() + 
", ugi="
+                                       + ugi);
+               } else {
+                       logger.info("Server username is not available");
+               }
+               return ugi;
+       }
+
        /**
         * @param ugiLoginUser
         */
-       public static void setUGILoginUser(UserGroupInformation newUGI, Subject 
newSubject) {
+       public static void setUGILoginUser(UserGroupInformation newUGI,
+                       Subject newSubject) {
                if (newUGI != null) {
                        UserGroupInformation.setLoginUser(newUGI);
                        ugiLoginUser = newUGI;
-                       logger.info("Setting UGI=" + newUGI );
+                       logger.info("Setting UGI=" + newUGI);
                } else {
                        logger.error("UGI is null. Not setting it.");
                }
-               logger.info("Setting SUBJECT");
-               subjectLoginUser = newSubject;
+               if (newSubject != null) {
+                       logger.info("Setting SUBJECT");
+                       subjectLoginUser = newSubject;
+               }
        }
 
        public static UserGroupInformation getUGILoginUser() {
@@ -436,7 +478,6 @@ public class MiscUtil {
                return ugiLoginUser;
        }
 
-       
        public static Subject getSubjectLoginUser() {
                return subjectLoginUser;
        }
@@ -462,13 +503,14 @@ public class MiscUtil {
                                return groupsSet;
                        }
                } catch (Throwable e) {
-                       logErrorMessageByInterval(
-                                       logger, "Error getting groups for 
users. userName=" + userName, e);
+                       logErrorMessageByInterval(logger,
+                                       "Error getting groups for users. 
userName=" + userName, e);
                }
                return null;
        }
 
-       static public boolean logErrorMessageByInterval(Log useLogger, String 
message) {
+       static public boolean logErrorMessageByInterval(Log useLogger,
+                       String message) {
                return logErrorMessageByInterval(useLogger, message, null);
        }
 
@@ -476,7 +518,8 @@ public class MiscUtil {
         * @param string
         * @param e
         */
-       static public boolean logErrorMessageByInterval(Log useLogger, String 
message, Throwable e) {
+       static public boolean logErrorMessageByInterval(Log useLogger,
+                       String message, Throwable e) {
                LogHistory log = logHistoryList.get(message);
                if (log == null) {
                        log = new LogHistory();
@@ -494,7 +537,7 @@ public class MiscUtil {
                        } else {
                                useLogger.error(message, e);
                        }
-                       
+
                        return true;
                } else {
                        log.counter++;
@@ -503,9 +546,127 @@ public class MiscUtil {
 
        }
 
+       public static void authWithKerberos(String keytab, String principal,
+                       String nameRules) {
+
+               if (keytab == null) {
+                       return;
+               }
+               Subject serverSubject = new Subject();
+               int successLoginCount = 0;
+               String[] spnegoPrincipals = null;
+               try {
+                       if (principal.equals("*")) {
+                               spnegoPrincipals = 
KerberosUtil.getPrincipalNames(keytab,
+                                               Pattern.compile("HTTP/.*"));
+                               if (spnegoPrincipals.length == 0) {
+                                       logger.error("No principals found in 
keytab=" + keytab);
+                               }
+                       } else {
+                               spnegoPrincipals = new String[] { principal };
+                       }
+
+                       if (nameRules != null) {
+                               KerberosName.setRules(nameRules);
+                       }
+
+                       List<LoginContext> loginContexts = new 
ArrayList<LoginContext>();
+                       for (String spnegoPrincipal : spnegoPrincipals) {
+                               try {
+                                       logger.info("Login using keytab " + 
keytab
+                                                       + ", for principal " + 
spnegoPrincipal);
+                                       final KerberosConfiguration 
kerberosConfiguration = new KerberosConfiguration(
+                                                       keytab, 
spnegoPrincipal);
+                                       final LoginContext loginContext = new 
LoginContext("",
+                                                       serverSubject, null, 
kerberosConfiguration);
+                                       loginContext.login();
+                                       successLoginCount++;
+                                       logger.info("Login success keytab " + 
keytab
+                                                       + ", for principal " + 
spnegoPrincipal);
+                                       loginContexts.add(loginContext);
+                               } catch (Throwable t) {
+                                       logger.error("Login failed keytab " + 
keytab
+                                                       + ", for principal " + 
spnegoPrincipal, t);
+                               }
+                       }
+               } catch (Throwable t) {
+                       logger.error("Failed to login as [" + spnegoPrincipals 
+ "]", t);
+               }
+
+               if (successLoginCount > 0) {
+                       logger.info("Total login success count=" + 
successLoginCount);
+                       try {
+                               UserGroupInformation ugi = 
createUGIFromSubject(serverSubject);
+                               if (ugi != null) {
+                                       setUGILoginUser(ugi, serverSubject);
+                               }
+                       } catch (Throwable e) {
+                               logger.error("Error creating UGI from subject. 
subject="
+                                               + serverSubject);
+                       }
+               } else {
+                       logger.error("Total logins were successfull from 
keytab=" + keytab
+                                       + ", principal=" + principal);
+               }
+       }
+
        static class LogHistory {
                long lastLogTime = 0;
                int counter = 0;
        }
 
+       /**
+        * Kerberos context configuration for the JDK GSS library.
+        */
+       private static class KerberosConfiguration extends Configuration {
+               private String keytab;
+               private String principal;
+
+               public KerberosConfiguration(String keytab, String principal) {
+                       this.keytab = keytab;
+                       this.principal = principal;
+               }
+
+               @Override
+               public AppConfigurationEntry[] getAppConfigurationEntry(String 
name) {
+                       Map<String, String> options = new HashMap<String, 
String>();
+                       if (IBM_JAVA) {
+                               options.put("useKeytab", 
keytab.startsWith("file://") ? keytab
+                                               : "file://" + keytab);
+                               options.put("principal", principal);
+                               options.put("credsType", "acceptor");
+                       } else {
+                               options.put("keyTab", keytab);
+                               options.put("principal", principal);
+                               options.put("useKeyTab", "true");
+                               options.put("storeKey", "true");
+                               options.put("doNotPrompt", "true");
+                               options.put("useTicketCache", "true");
+                               options.put("renewTGT", "true");
+                               options.put("isInitiator", "false");
+                       }
+                       options.put("refreshKrb5Config", "true");
+                       String ticketCache = System.getenv("KRB5CCNAME");
+                       if (ticketCache != null) {
+                               if (IBM_JAVA) {
+                                       options.put("useDefaultCcache", "true");
+                                       // The first value searched when 
"useDefaultCcache" is used.
+                                       System.setProperty("KRB5CCNAME", 
ticketCache);
+                                       options.put("renewTGT", "true");
+                                       options.put("credsType", "both");
+                               } else {
+                                       options.put("ticketCache", ticketCache);
+                               }
+                       }
+                       if (logger.isDebugEnabled()) {
+                               options.put("debug", "true");
+                       }
+
+                       return new AppConfigurationEntry[] { new 
AppConfigurationEntry(
+                                       KerberosUtil.getKrb5LoginModuleName(),
+                                       
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+                                       options), };
+               }
+       }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/de946a3f/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizer.java
----------------------------------------------------------------------
diff --git 
a/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizer.java
 
b/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizer.java
index 3341f84..dbb2723 100644
--- 
a/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizer.java
+++ 
b/plugin-kafka/src/main/java/org/apache/ranger/authorization/kafka/authorizer/RangerKafkaAuthorizer.java
@@ -19,6 +19,7 @@
 
 package org.apache.ranger.authorization.kafka.authorizer;
 
+import java.io.IOException;
 import java.security.Principal;
 import java.util.Date;
 
@@ -81,43 +82,19 @@ public class RangerKafkaAuthorizer implements Authorizer {
        public void initialize(KafkaConfig kafkaConfig) {
 
                if (rangerPlugin == null) {
-                       rangerPlugin = new RangerBasePlugin("kafka", "kafka");
-
                        try {
                                Subject subject = LoginManager.subject();
-                               logger.info("SUBJECT "
-                                               + (subject == null ? "not 
found" : "found"));
-                               if (subject != null) {
-                                       logger.info("SUBJECT.PRINCIPALS.size()="
-                                                       + 
subject.getPrincipals().size());
-                                       java.util.Set<Principal> principals = 
subject
-                                                       .getPrincipals();
-                                       for (Principal principal : principals) {
-                                               
logger.info("SUBJECT.PRINCIPAL.NAME="
-                                                               + 
principal.getName());
-                                       }
-                                       try {
-                                               // Do not remove the below 
statement. The default
-                                               // getLoginUser does some 
initialization which is needed
-                                               // for getUGIFromSubject() to 
work.
-                                               logger.info("Default UGI before 
using Subject from Kafka:"
-                                                               + 
UserGroupInformation.getLoginUser());
-                                       } catch (Throwable t) {
-                                               logger.error(t);
-                                       }
-                                       UserGroupInformation ugi = 
UserGroupInformation
-                                                       
.getUGIFromSubject(subject);
-                                       logger.info("SUBJECT.UGI.NAME=" + 
ugi.getUserName()
-                                                       + ", ugi=" + ugi);
+                               UserGroupInformation ugi = MiscUtil
+                                               .createUGIFromSubject(subject);
+                               if (ugi != null) {
                                        MiscUtil.setUGILoginUser(ugi, subject);
-                               } else {
-                                       logger.info("Server username is not 
available");
                                }
                                logger.info("LoginUser=" + 
MiscUtil.getUGILoginUser());
                        } catch (Throwable t) {
                                logger.error("Error getting principal.", t);
                        }
 
+                       rangerPlugin = new RangerBasePlugin("kafka", "kafka");
                        logger.info("Calling plugin.init()");
                        rangerPlugin.init();
 
@@ -135,12 +112,12 @@ public class RangerKafkaAuthorizer implements Authorizer {
                                        "Authorizer is still not initialized");
                        return false;
                }
-               
-               //TODO: If resource type if consumer group, then allow it by 
default
-               if(resource.resourceType().equals(ResourceType.CONSUMER_GROUP)) 
{
+
+               // TODO: If resource type if consumer group, then allow it by 
default
+               if 
(resource.resourceType().equals(ResourceType.CONSUMER_GROUP)) {
                        return true;
                }
-               
+
                String userName = null;
                if (session.principal() != null) {
                        userName = session.principal().getName();

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/de946a3f/plugin-kms/src/main/java/org/apache/ranger/authorization/kms/authorizer/RangerKmsAuthorizer.java
----------------------------------------------------------------------
diff --git 
a/plugin-kms/src/main/java/org/apache/ranger/authorization/kms/authorizer/RangerKmsAuthorizer.java
 
b/plugin-kms/src/main/java/org/apache/ranger/authorization/kms/authorizer/RangerKmsAuthorizer.java
index 3407a1d..04b8b91 100755
--- 
a/plugin-kms/src/main/java/org/apache/ranger/authorization/kms/authorizer/RangerKmsAuthorizer.java
+++ 
b/plugin-kms/src/main/java/org/apache/ranger/authorization/kms/authorizer/RangerKmsAuthorizer.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.crypto.key.kms.server.KMSACLsType;
@@ -40,6 +41,7 @@ import org.apache.hadoop.security.AccessControlException;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.authorize.AccessControlList;
 import org.apache.hadoop.security.authorize.AuthorizationException;
+import org.apache.ranger.audit.provider.MiscUtil;
 import org.apache.ranger.authorization.utils.StringUtil;
 import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
 import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
@@ -81,15 +83,52 @@ public class RangerKmsAuthorizer implements Runnable, 
KeyACLs {
 
          private static volatile RangerKMSPlugin kmsPlugin = null;
 
+         /**
+          * Constant that identifies the authentication mechanism.
+          */
+         public static final String TYPE = "kerberos";
+
+         /**
+          * Constant for the configuration property that indicates the 
kerberos principal.
+          */
+         public static final String PRINCIPAL = TYPE + ".principal";
+
+         /**
+          * Constant for the configuration property that indicates the keytab 
file path.
+          */
+         public static final String KEYTAB = TYPE + ".keytab";
+
+         /**
+          * Constant for the configuration property that indicates the 
Kerberos name
+          * rules for the Kerberos principals.
+          */
+         public static final String NAME_RULES = TYPE + ".name.rules";
+
          RangerKmsAuthorizer(Configuration conf) {
+                 LOG.info("RangerKmsAuthorizer(conf)...");
+                 authWithKerberos();
                  if (conf == null) {
                      conf = loadACLs();                      
                  }
                  setKMSACLs(conf);     
                  init(conf);
+                 
          }
 
-         public RangerKmsAuthorizer() {                  
+         /**
+        * 
+        */
+       private void authWithKerberos() {
+               //Let's if we can create the login user UGI
+               Configuration kconf = new Configuration();              
+               kconf.addResource("kms-site.xml");
+               String keytab =  
kconf.get("hadoop.kms.authentication.kerberos.keytab");
+               String principal = 
kconf.get("hadoop.kms.authentication.kerberos.principal");
+           String nameRules = kconf.get(NAME_RULES);
+               MiscUtil.authWithKerberos(keytab, principal, nameRules);
+       }
+
+       public RangerKmsAuthorizer() {            
            this(null);
          }
          
@@ -241,6 +280,7 @@ public class RangerKmsAuthorizer implements Runnable, 
KeyACLs {
                                                plugin.init();
                                                
                                                kmsPlugin = plugin;
+                                               
                                        }
                                }
                        }
@@ -306,6 +346,8 @@ public class RangerKmsAuthorizer implements Runnable, 
KeyACLs {
                }
        }
 
+
+       
        class RangerKMSPlugin extends RangerBasePlugin {
                public RangerKMSPlugin() {
                        super("kms", "kms");

Reply via email to