From a7aacdc2d66c6f80704d5ff11fc600acb61c8bf2 Mon Sep 17 00:00:00 2001 From: Boris Shkolnik Date: Wed, 26 May 2010 18:29:30 +0000 Subject: [PATCH] HADOOP6638. try to relogin in a case of failed RPC connection (expired tgt) only in case the subject is loginUser or proxyUgi.realUser. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@948523 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES.txt | 4 ++- src/java/org/apache/hadoop/ipc/Client.java | 24 ++++++++----- .../hadoop/security/UserGroupInformation.java | 36 +++++++++++-------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 61b5996ebed..84e52ef1d44 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -28,8 +28,10 @@ Trunk (unreleased changes) (Patrick Angeles via cdouglas) BUG FIXES + HADOOP-6638. try to relogin in a case of failed RPC connection (expired tgt) + only in case the subject is loginUser or proxyUgi.realUser. (boryas) - HADOOP-6781. security audit log shouldn't have exception in it. + HADOOP-6781. security audit log shouldn't have exception in it. (boryas) HADOOP-6612. Protocols RefreshUserToGroupMappingsProtocol and RefreshAuthorizationPolicyProtocol will fail with security enabled (boryas) diff --git a/src/java/org/apache/hadoop/ipc/Client.java b/src/java/org/apache/hadoop/ipc/Client.java index 68d96e15b4d..e99493ceee9 100644 --- a/src/java/org/apache/hadoop/ipc/Client.java +++ b/src/java/org/apache/hadoop/ipc/Client.java @@ -377,26 +377,34 @@ public class Client { serverPrincipal); return saslRpcClient.saslConnect(in2, out2); } catch (javax.security.sasl.SaslException je) { + UserGroupInformation loginUser = UserGroupInformation.getLoginUser(); + UserGroupInformation currentUser = UserGroupInformation.getCurrentUser(); + UserGroupInformation realUser = currentUser.getRealUser(); if (authMethod == AuthMethod.KERBEROS && - UserGroupInformation.isLoginKeytabBased()) { - //try re-login - UserGroupInformation.getCurrentUser().reloginFromKeytab(); //try setting up the connection again + UserGroupInformation.isLoginKeytabBased() && + // relogin only in case it is the login user (e.g. JT) + // or superuser (like oozie). + ((currentUser != null && currentUser.equals(loginUser)) || + (realUser != null && realUser.equals(loginUser)))) { try { + //try re-login + loginUser.reloginFromKeytab(); disposeSasl(); saslRpcClient = new SaslRpcClient(authMethod, token, serverPrincipal); return saslRpcClient.saslConnect(in2, out2); } catch (javax.security.sasl.SaslException jee) { - UserGroupInformation. - setLastUnsuccessfulAuthenticationAttemptTime - (System.currentTimeMillis()); LOG.warn("Couldn't setup connection for " + - UserGroupInformation.getCurrentUser().getUserName() + + loginUser.getUserName() + " to " + serverPrincipal + " even after relogin."); throw jee; + } catch (IOException ie) { + ie.initCause(je); + throw ie; } - } else throw je; + } + throw je; } } /** Connect to the server and set up the I/O streams. It then sends diff --git a/src/java/org/apache/hadoop/security/UserGroupInformation.java b/src/java/org/apache/hadoop/security/UserGroupInformation.java index ed1fce42a67..c074c0f5d24 100644 --- a/src/java/org/apache/hadoop/security/UserGroupInformation.java +++ b/src/java/org/apache/hadoop/security/UserGroupInformation.java @@ -129,8 +129,6 @@ public class UserGroupInformation { private static boolean useKerberos; /** Server-side groups fetching service */ private static Groups groups; - /** The last authentication time */ - private static long lastUnsuccessfulAuthenticationAttemptTime; public static final long MIN_TIME_BEFORE_RELOGIN = 10 * 60 * 1000L; @@ -138,6 +136,9 @@ public class UserGroupInformation { public static final String HADOOP_TOKEN_FILE_LOCATION = "HADOOP_TOKEN_FILE_LOCATION"; + /** The last relogin attempt */ + private long lastReloginTime = 0; + /** * A method to initialize the fields that depend on a configuration. * Must be called before useKerberos or groups is used. @@ -205,7 +206,7 @@ public class UserGroupInformation { private final Subject subject; - private static LoginContext login; + private LoginContext login; private static final String OS_LOGIN_MODULE_NAME; private static final Class OS_PRINCIPAL_CLASS; @@ -359,12 +360,18 @@ public class UserGroupInformation { static UserGroupInformation getLoginUser() throws IOException { if (loginUser == null) { try { + Subject subject = new Subject(); + loginUser = new UserGroupInformation(subject); + LoginContext login; if (isSecurityEnabled()) { - login = new LoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME); + login = new LoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME, + subject); } else { - login = new LoginContext(HadoopConfiguration.SIMPLE_CONFIG_NAME); + login = new LoginContext(HadoopConfiguration.SIMPLE_CONFIG_NAME, + subject); } login.login(); + loginUser.login = login; loginUser = new UserGroupInformation(login.getSubject()); String tokenFile = System.getenv(HADOOP_TOKEN_FILE_LOCATION); if (tokenFile != null && isSecurityEnabled()) { @@ -393,11 +400,14 @@ public class UserGroupInformation { keytabFile = path; keytabPrincipal = user; + Subject subject = new Subject(); + LoginContext login; try { login = - new LoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME); + new LoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, subject); login.login(); - loginUser = new UserGroupInformation(login.getSubject()); + loginUser = new UserGroupInformation(subject); + loginUser.login = login; } catch (LoginException le) { throw new IOException("Login failure for " + user + " from keytab " + path, le); @@ -420,13 +430,15 @@ public class UserGroupInformation { if (login == null || keytabFile == null) { throw new IOException("loginUserFromKeyTab must be done first"); } - if (System.currentTimeMillis() -lastUnsuccessfulAuthenticationAttemptTime < - MIN_TIME_BEFORE_RELOGIN) { + long now = System.currentTimeMillis(); + if (now - lastReloginTime < MIN_TIME_BEFORE_RELOGIN ) { LOG.warn("Not attempting to re-login since the last re-login was " + "attempted less than " + (MIN_TIME_BEFORE_RELOGIN/1000) + " seconds"+ " before."); return; } + // register most recent relogin + lastReloginTime = System.currentTimeMillis(); try { LOG.info("Initiating logout for " + getUserName()); //clear up the kerberos state. But the tokens are not cleared! As per @@ -446,11 +458,7 @@ public class UserGroupInformation { } } - public synchronized static void - setLastUnsuccessfulAuthenticationAttemptTime(long time) { - lastUnsuccessfulAuthenticationAttemptTime = time; - } - + public synchronized static boolean isLoginKeytabBased() { return keytabFile != null; }