in sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java [285:394]
protected void processUserAuth(int cmd, Buffer buffer, AuthFuture authFuture) throws Exception {
ClientSession session = getClientSession();
if (cmd == SshConstants.SSH_MSG_USERAUTH_SUCCESS) {
if (log.isDebugEnabled()) {
log.debug("processUserAuth({}) SSH_MSG_USERAUTH_SUCCESS Succeeded with {}",
session, (currentUserAuth == null) ? "<unknown>" : currentUserAuth.getName());
}
if (currentUserAuth != null) {
try {
currentUserAuth.signalAuthMethodSuccess(session, service, buffer);
} finally {
clearUserAuth();
}
} else {
destroyPubkeyAuth();
}
session.setAuthenticated();
((ClientSessionImpl) session).switchToNextService();
// Will wake up anyone sitting in waitFor
authFuture.setAuthed(true);
return;
}
authFuture.setCancellable(true);
if (authFuture.isCanceled()) {
authFuture.getCancellation().setCanceled();
clearUserAuth();
return;
}
if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
String methods = buffer.getString();
boolean partial = buffer.getBoolean();
if (log.isDebugEnabled()) {
log.debug("processUserAuth({}) Received SSH_MSG_USERAUTH_FAILURE - partial={}, methods={}",
session, partial, methods);
}
List<String> allowedMethods;
if (GenericUtils.isEmpty(methods)) {
if (serverMethods == null) {
// RFC 4252 section 5.2 says that in the SSH_MSG_USERAUTH_FAILURE response
// to a 'none' request a server MAY return a list of methods. Here it didn't,
// so we just assume all methods that the client knows are fine.
//
// https://datatracker.ietf.org/doc/html/rfc4252#section-5.2
allowedMethods = new ArrayList<>(clientMethods);
} else if (partial) {
// Don't reset to an empty list; keep going with the previous methods. Sending
// a partial success without methods that may continue makes no sense and would
// be a server bug.
//
// currentUserAuth should always be set here!
if (log.isDebugEnabled()) {
log.debug(
"processUserAuth({}) : potential bug in {} server: SSH_MSG_USERAUTH_FAILURE with partial success after {} authentication, but without continuation methods",
session, session.getServerVersion(),
currentUserAuth != null ? currentUserAuth.getName() : "UNKNOWN");
}
allowedMethods = serverMethods;
} else {
allowedMethods = new ArrayList<>();
}
} else {
allowedMethods = Arrays.asList(GenericUtils.split(methods, ','));
}
if (currentUserAuth != null) {
try {
currentUserAuth.signalAuthMethodFailure(session, service, partial,
Collections.unmodifiableList(allowedMethods), buffer);
} catch (Exception e) {
clearUserAuth();
throw e;
}
// Check if the current method is still allowed.
if (allowedMethods.indexOf(currentUserAuth.getName()) < 0) {
if (currentUserAuth == pubkeyAuth) {
// Don't destroy it yet, we might still need it later on
currentUserAuth = null;
} else {
destroyUserAuth();
}
}
}
if (partial || (serverMethods == null)) {
currentMethod = 0;
}
serverMethods = allowedMethods;
tryNext(cmd, authFuture);
return;
}
if (currentUserAuth == null) {
throw new IllegalStateException("Received unknown packet: " + SshConstants.getCommandMessageName(cmd));
}
if (log.isDebugEnabled()) {
log.debug("processUserAuth({}) delegate processing of {} to {}",
session, SshConstants.getCommandMessageName(cmd), currentUserAuth.getName());
}
buffer.rpos(buffer.rpos() - 1);
if (!currentUserAuth.process(buffer)) {
tryNext(cmd, authFuture);
} else {
authFuture.setCancellable(currentUserAuth.isCancellable());
}
}