From 0b36dcda7cbac51c725224a8e0abef4eaa004fd8 Mon Sep 17 00:00:00 2001 From: Robert Kanter Date: Fri, 4 Nov 2016 09:24:21 -0700 Subject: [PATCH] HADOOP-7930. Kerberos relogin interval in UserGroupInformation should be configurable (xiaochen via rkanter) --- .../fs/CommonConfigurationKeysPublic.java | 6 ++++ .../hadoop/security/UserGroupInformation.java | 26 +++++++++----- .../src/main/resources/core-default.xml | 8 +++++ .../security/TestUserGroupInformation.java | 36 +++++++++++++++++++ 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeysPublic.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeysPublic.java index 742c880912e..84cdccfb028 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeysPublic.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeysPublic.java @@ -585,6 +585,12 @@ public class CommonConfigurationKeysPublic { /** Only used by HttpServer. */ public static final boolean HADOOP_SSL_ENABLED_DEFAULT = false; + /** See core-default.xml */ + public static final String HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN = + "hadoop.kerberos.min.seconds.before.relogin"; + /** Default value for HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN */ + public static final int HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN_DEFAULT = + 60; // HTTP policies to be used in configuration // Use HttpPolicy.name() instead diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java index 45247b0b136..79e56e7cd61 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java @@ -17,6 +17,8 @@ */ package org.apache.hadoop.security; +import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN; +import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN_DEFAULT; import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS; import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_TOKEN_FILES; import static org.apache.hadoop.security.UGIExceptionMessages.*; @@ -253,13 +255,11 @@ public class UserGroupInformation { private static AuthenticationMethod authenticationMethod; /** Server-side groups fetching service */ private static Groups groups; + /** Min time (in seconds) before relogin for Kerberos */ + private static long kerberosMinSecondsBeforeRelogin; /** The configuration to use */ private static Configuration conf; - - /** Leave 10 minutes between relogin attempts. */ - private static final long MIN_TIME_BEFORE_RELOGIN = 10 * 60 * 1000L; - /**Environment variable pointing to the token cache file*/ public static final String HADOOP_TOKEN_FILE_LOCATION = "HADOOP_TOKEN_FILE_LOCATION"; @@ -293,6 +293,16 @@ public class UserGroupInformation { "Problem with Kerberos auth_to_local name configuration", ioe); } } + try { + kerberosMinSecondsBeforeRelogin = 1000L * conf.getLong( + HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN, + HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN_DEFAULT); + } + catch(NumberFormatException nfe) { + throw new IllegalArgumentException("Invalid attribute value for " + + HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN + " of " + + conf.get(HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN)); + } // If we haven't set up testing groups, use the configuration to find it if (!(groups instanceof TestingGroups)) { groups = Groups.getUserToGroupsMappingService(conf); @@ -973,7 +983,7 @@ public class UserGroupInformation { return; } nextRefresh = Math.max(getRefreshTime(tgt), - now + MIN_TIME_BEFORE_RELOGIN); + now + kerberosMinSecondsBeforeRelogin); } catch (InterruptedException ie) { LOG.warn("Terminating renewal thread"); return; @@ -1265,10 +1275,10 @@ public class UserGroupInformation { } private boolean hasSufficientTimeElapsed(long now) { - if (now - user.getLastLogin() < MIN_TIME_BEFORE_RELOGIN ) { + if (now - user.getLastLogin() < kerberosMinSecondsBeforeRelogin ) { LOG.warn("Not attempting to re-login since the last re-login was " + - "attempted less than " + (MIN_TIME_BEFORE_RELOGIN/1000) + " seconds"+ - " before. Last Login=" + user.getLastLogin()); + "attempted less than " + (kerberosMinSecondsBeforeRelogin/1000) + + " seconds before. Last Login=" + user.getLastLogin()); return false; } return true; diff --git a/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml b/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml index d31654001b4..c2f088c5452 100644 --- a/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml +++ b/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml @@ -546,6 +546,14 @@ + + hadoop.kerberos.min.seconds.before.relogin + 60 + The minimum time between relogin attempts for Kerberos, in + seconds. + + + hadoop.security.auth_to_local diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUserGroupInformation.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUserGroupInformation.java index 171c9408489..1cdc4c426a6 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUserGroupInformation.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUserGroupInformation.java @@ -40,6 +40,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.lang.reflect.Method; import java.security.PrivilegedExceptionAction; import java.util.Collection; import java.util.ConcurrentModificationException; @@ -975,4 +976,39 @@ public class TestUserGroupInformation { }); } + + /** Test hasSufficientTimeElapsed method */ + @Test + public void testHasSufficientTimeElapsed() throws Exception { + // Make hasSufficientTimeElapsed public + Method method = UserGroupInformation.class + .getDeclaredMethod("hasSufficientTimeElapsed", long.class); + method.setAccessible(true); + + UserGroupInformation ugi = UserGroupInformation.getCurrentUser(); + User user = ugi.getSubject().getPrincipals(User.class).iterator().next(); + long now = System.currentTimeMillis(); + + // Using default relogin time (1 minute) + user.setLastLogin(now - 2 * 60 * 1000); // 2 minutes before "now" + assertTrue((Boolean)method.invoke(ugi, now)); + user.setLastLogin(now - 30 * 1000); // 30 seconds before "now" + assertFalse((Boolean)method.invoke(ugi, now)); + + // Using relogin time of 10 minutes + Configuration conf2 = new Configuration(conf); + conf2.setLong( + CommonConfigurationKeysPublic.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN, + 10 * 60); + UserGroupInformation.setConfiguration(conf2); + user.setLastLogin(now - 15 * 60 * 1000); // 15 minutes before "now" + assertTrue((Boolean)method.invoke(ugi, now)); + user.setLastLogin(now - 6 * 60 * 1000); // 6 minutes before "now" + assertFalse((Boolean)method.invoke(ugi, now)); + // Restore original conf to UGI + UserGroupInformation.setConfiguration(conf); + + // Restore hasSufficientTimElapsed back to private + method.setAccessible(false); + } }