sshd: better error report when user cancels authentication
Use a dedicated exception class to be able to detect this case in the SshdSessionFactory and skip the generic SshException in that case. Change-Id: I2a0bacf47bae82f154a0f4e79efbb2af2a17d0cf Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
parent
e21d7b2d3c
commit
3459239dfc
|
@ -1,4 +1,4 @@
|
|||
authenticationCanceled=Authentication canceled: no password
|
||||
authenticationCanceled=SSH authentication canceled: no password given
|
||||
authenticationOnClosedSession=Authentication canceled: session is already closing or closed
|
||||
closeListenerFailed=Ssh session close listener failed
|
||||
configInvalidPath=Invalid path in ssh config key {0}: {1}
|
||||
|
@ -49,7 +49,7 @@ knownHostsUnknownKeyPrompt=Accept and store this key, and continue connecting?
|
|||
knownHostsUnknownKeyType=Cannot read server key from known hosts file {0}; line {1}
|
||||
knownHostsUserAskCreationMsg=File {0} does not exist.
|
||||
knownHostsUserAskCreationPrompt=Create file {0} ?
|
||||
loginDenied=Log-in denied at {0}:{1}
|
||||
loginDenied=Cannot log in at {0}:{1}
|
||||
passwordPrompt=Password
|
||||
proxyCannotAuthenticate=Cannot authenticate to proxy {0}
|
||||
proxyHttpFailure=HTTP Proxy connection to {0} failed with code {1}: {2}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (C) 2020, Thomas Wolf <thomas.wolf@paranor.ch> and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||
* https://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
package org.eclipse.jgit.internal.transport.sshd;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
/**
|
||||
* An exception to report that the user canceled the SSH authentication.
|
||||
*/
|
||||
public class AuthenticationCanceledException extends CancellationException {
|
||||
|
||||
// If this is not a CancellationException sshd will try other authentication
|
||||
// mechanisms.
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AuthenticationCanceledException}.
|
||||
*/
|
||||
public AuthenticationCanceledException() {
|
||||
super(SshdText.get().authenticationCanceled);
|
||||
}
|
||||
}
|
|
@ -9,8 +9,6 @@
|
|||
*/
|
||||
package org.eclipse.jgit.internal.transport.sshd;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
import org.apache.sshd.client.ClientAuthenticationManager;
|
||||
import org.apache.sshd.client.auth.keyboard.UserInteraction;
|
||||
import org.apache.sshd.client.auth.password.UserAuthPassword;
|
||||
|
@ -49,7 +47,7 @@ protected boolean sendAuthDataRequest(ClientSession session, String service)
|
|||
}
|
||||
String password = getPassword(session, interaction);
|
||||
if (password == null) {
|
||||
throw new CancellationException();
|
||||
throw new AuthenticationCanceledException();
|
||||
}
|
||||
// sendPassword takes a buffer as first argument, but actually doesn't
|
||||
// use it and creates its own buffer...
|
||||
|
|
|
@ -19,13 +19,14 @@
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
import org.eclipse.jgit.annotations.NonNull;
|
||||
import org.eclipse.jgit.internal.transport.sshd.AuthenticationCanceledException;
|
||||
import org.eclipse.jgit.internal.transport.sshd.SshdText;
|
||||
import org.eclipse.jgit.transport.CredentialItem;
|
||||
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||
import org.eclipse.jgit.transport.URIish;
|
||||
import org.eclipse.jgit.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link KeyPasswordProvider} based on a {@link CredentialsProvider}.
|
||||
|
@ -155,34 +156,83 @@ protected char[] getPassword(URIish uri, int attempt, @NonNull State state)
|
|||
state.incCount();
|
||||
String message = state.count == 1 ? SshdText.get().keyEncryptedMsg
|
||||
: SshdText.get().keyEncryptedRetry;
|
||||
char[] pass = getPassword(uri, message);
|
||||
char[] pass = getPassword(uri, format(message, uri));
|
||||
state.setPassword(pass);
|
||||
return pass;
|
||||
}
|
||||
|
||||
private char[] getPassword(URIish uri, String message) {
|
||||
/**
|
||||
* Retrieves the JGit {@link CredentialsProvider} to use for user
|
||||
* interaction.
|
||||
*
|
||||
* @return the {@link CredentialsProvider} or {@code null} if none
|
||||
* configured
|
||||
* @since 5.10
|
||||
*/
|
||||
protected CredentialsProvider getCredentialsProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the passphrase/password for an encrypted private key via the
|
||||
* {@link #getCredentialsProvider() configured CredentialsProvider}.
|
||||
*
|
||||
* @param uri
|
||||
* identifying the resource to obtain a password for
|
||||
* @param message
|
||||
* optional message text to display; may be {@code null} or empty
|
||||
* if none
|
||||
* @return the password entered, or {@code null} if no
|
||||
* {@link CredentialsProvider} is configured or none was entered
|
||||
* @throws java.util.concurrent.CancellationException
|
||||
* if the user canceled the operation
|
||||
* @since 5.10
|
||||
*/
|
||||
protected char[] getPassword(URIish uri, String message) {
|
||||
if (provider == null) {
|
||||
return null;
|
||||
}
|
||||
List<CredentialItem> items = new ArrayList<>(2);
|
||||
items.add(new CredentialItem.InformationalMessage(
|
||||
format(message, uri)));
|
||||
boolean haveMessage = !StringUtils.isEmptyOrNull(message);
|
||||
List<CredentialItem> items = new ArrayList<>(haveMessage ? 2 : 1);
|
||||
if (haveMessage) {
|
||||
items.add(new CredentialItem.InformationalMessage(message));
|
||||
}
|
||||
CredentialItem.Password password = new CredentialItem.Password(
|
||||
SshdText.get().keyEncryptedPrompt);
|
||||
items.add(password);
|
||||
try {
|
||||
provider.get(uri, items);
|
||||
boolean completed = provider.get(uri, items);
|
||||
char[] pass = password.getValue();
|
||||
if (pass == null) {
|
||||
throw new CancellationException(
|
||||
SshdText.get().authenticationCanceled);
|
||||
if (!completed) {
|
||||
cancelAuthentication();
|
||||
return null;
|
||||
}
|
||||
return pass.clone();
|
||||
return pass == null ? null : pass.clone();
|
||||
} finally {
|
||||
password.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the authentication process. Called by
|
||||
* {@link #getPassword(URIish, String)} when the user interaction has been
|
||||
* canceled. If this throws a
|
||||
* {@link java.util.concurrent.CancellationException}, the authentication
|
||||
* process is aborted; otherwise it may continue with the next configured
|
||||
* authentication mechanism, if any.
|
||||
* <p>
|
||||
* This default implementation always throws a
|
||||
* {@link java.util.concurrent.CancellationException}.
|
||||
* </p>
|
||||
*
|
||||
* @throws java.util.concurrent.CancellationException
|
||||
* always
|
||||
* @since 5.10
|
||||
*/
|
||||
protected void cancelAuthentication() {
|
||||
throw new AuthenticationCanceledException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to inform the password provider about the decoding result.
|
||||
*
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory;
|
||||
import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
|
||||
import org.apache.sshd.client.config.hosts.HostConfigEntryResolver;
|
||||
import org.apache.sshd.common.SshException;
|
||||
import org.apache.sshd.common.compression.BuiltinCompressions;
|
||||
import org.apache.sshd.common.config.keys.FilePasswordProvider;
|
||||
import org.apache.sshd.common.config.keys.loader.openssh.kdf.BCryptKdfOptions;
|
||||
|
@ -41,6 +42,7 @@
|
|||
import org.eclipse.jgit.annotations.NonNull;
|
||||
import org.eclipse.jgit.errors.TransportException;
|
||||
import org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile;
|
||||
import org.eclipse.jgit.internal.transport.sshd.AuthenticationCanceledException;
|
||||
import org.eclipse.jgit.internal.transport.sshd.CachingKeyPairProvider;
|
||||
import org.eclipse.jgit.internal.transport.sshd.GssApiWithMicAuthFactory;
|
||||
import org.eclipse.jgit.internal.transport.sshd.JGitPasswordAuthFactory;
|
||||
|
@ -233,7 +235,13 @@ public SshdSession getSession(URIish uri,
|
|||
if (e instanceof TransportException) {
|
||||
throw (TransportException) e;
|
||||
}
|
||||
throw new TransportException(uri, e.getMessage(), e);
|
||||
Throwable cause = e;
|
||||
if (e instanceof SshException && e
|
||||
.getCause() instanceof AuthenticationCanceledException) {
|
||||
// Results in a nicer error message
|
||||
cause = e.getCause();
|
||||
}
|
||||
throw new TransportException(uri, cause.getMessage(), cause);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue