HADOOP-18581 : Handle Server KDC re-login when Server and Client run … (#5248)

* HADOOP-18581 : Handle Server KDC re-login when Server and Client run in same JVM.
This commit is contained in:
Surendra Singh Lilhore 2023-01-08 23:55:06 +05:30 committed by GitHub
parent cd19da1309
commit a65d24488a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 2 deletions

View File

@ -123,6 +123,7 @@
import org.apache.hadoop.util.ProtoUtil;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.util.Time;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.hadoop.tracing.Span;
import org.apache.hadoop.tracing.SpanContext;
import org.apache.hadoop.tracing.TraceScope;
@ -153,6 +154,13 @@ public abstract class Server {
private ExceptionsHandler exceptionsHandler = new ExceptionsHandler();
private Tracer tracer;
private AlignmentContext alignmentContext;
/**
* Allow server to do force Kerberos re-login once after failure irrespective
* of the last login time.
*/
private final AtomicBoolean canTryForceLogin = new AtomicBoolean(true);
/**
* Logical name of the server used in metrics and monitor.
*/
@ -2206,8 +2214,24 @@ private void saslProcess(RpcSaslProto saslMessage)
AUDITLOG.warn(AUTH_FAILED_FOR + this.toString() + ":"
+ attemptingUser + " (" + e.getLocalizedMessage()
+ ") with true cause: (" + tce.getLocalizedMessage() + ")");
if (!UserGroupInformation.getLoginUser().isLoginSuccess()) {
doKerberosRelogin();
try {
// try processing message again
LOG.debug("Reprocessing sasl message for {}:{} after re-login",
this.toString(), attemptingUser);
saslResponse = processSaslMessage(saslMessage);
AUDITLOG.info("Retry {}{}:{} after failure", AUTH_SUCCESSFUL_FOR,
this.toString(), attemptingUser);
canTryForceLogin.set(true);
} catch (IOException exp) {
tce = (IOException) getTrueCause(e);
throw tce;
}
} else {
throw tce;
}
}
if (saslServer != null && saslServer.isComplete()) {
if (LOG.isDebugEnabled()) {
@ -3322,6 +3346,26 @@ protected Server(String bindAddress, int port,
metricsUpdaterInterval, metricsUpdaterInterval, TimeUnit.MILLISECONDS);
}
private synchronized void doKerberosRelogin() throws IOException {
if(UserGroupInformation.getLoginUser().isLoginSuccess()){
return;
}
LOG.warn("Initiating re-login from IPC Server");
if (canTryForceLogin.compareAndSet(true, false)) {
if (UserGroupInformation.isLoginKeytabBased()) {
UserGroupInformation.getLoginUser().forceReloginFromKeytab();
} else if (UserGroupInformation.isLoginTicketBased()) {
UserGroupInformation.getLoginUser().forceReloginFromTicketCache();
}
} else {
if (UserGroupInformation.isLoginKeytabBased()) {
UserGroupInformation.getLoginUser().reloginFromKeytab();
} else if (UserGroupInformation.isLoginTicketBased()) {
UserGroupInformation.getLoginUser().reloginFromTicketCache();
}
}
}
public synchronized void addAuxiliaryListener(int auxiliaryPort)
throws IOException {
if (auxiliaryListenerMap == null) {

View File

@ -529,6 +529,18 @@ private void setLogin(LoginContext login) {
user.setLogin(login);
}
/** This method checks for a successful Kerberos login
* and returns true by default if it is not using Kerberos.
*
* @return true on successful login
*/
public boolean isLoginSuccess() {
LoginContext login = user.getLogin();
return (login instanceof HadoopLoginContext)
? ((HadoopLoginContext) login).isLoginSuccess()
: true;
}
/**
* Set the last login time for logged in user
* @param loginTime the number of milliseconds since the beginning of time
@ -1276,6 +1288,23 @@ private void reloginFromKeytab(boolean checkTGT, boolean ignoreLastLoginTime)
relogin(login, ignoreLastLoginTime);
}
/**
* Force re-Login a user in from the ticket cache irrespective of the last
* login time. This method assumes that login had happened already. The
* Subject field of this UserGroupInformation object is updated to have the
* new credentials.
*
* @throws IOException
* raised on errors performing I/O.
* @throws KerberosAuthException
* on a failure
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public void forceReloginFromTicketCache() throws IOException {
reloginFromTicketCache(true);
}
/**
* Re-Login a user in from the ticket cache. This
* method assumes that login had happened already.
@ -1287,6 +1316,11 @@ private void reloginFromKeytab(boolean checkTGT, boolean ignoreLastLoginTime)
@InterfaceAudience.Public
@InterfaceStability.Evolving
public void reloginFromTicketCache() throws IOException {
reloginFromTicketCache(false);
}
private void reloginFromTicketCache(boolean ignoreLastLoginTime)
throws IOException {
if (!shouldRelogin() || !isFromTicket()) {
return;
}
@ -1294,7 +1328,7 @@ public void reloginFromTicketCache() throws IOException {
if (login == null) {
throw new KerberosAuthException(MUST_FIRST_LOGIN);
}
relogin(login, false);
relogin(login, ignoreLastLoginTime);
}
private void relogin(HadoopLoginContext login, boolean ignoreLastLoginTime)
@ -2083,6 +2117,11 @@ private static class HadoopLoginContext extends LoginContext {
this.conf = conf;
}
/** Get the login status. */
public boolean isLoginSuccess() {
return isLoggedIn.get();
}
String getAppName() {
return appName;
}