GP-5362 Correct password entry bug and refactor PasswordDialog/ClientAuthenticator

This commit is contained in:
ghidra1 2025-02-13 14:11:30 -05:00
parent 99ed1003b5
commit d0badde92b
12 changed files with 194 additions and 116 deletions

View file

@ -418,10 +418,6 @@ public class CreateBsimServerInfoDialog extends DialogComponentProvider {
}
String user = userField.getText().trim();
if (ClientUtil.getUserName().equals(user)) {
user = null;
}
String name = nameField.getText().trim();
String host = hostField.getText().trim();

View file

@ -334,14 +334,16 @@ public class BSimPostgresDBConnectionManager {
throw new SQLException("No registered authenticator");
}
NameCallback nameCb = new NameCallback("User ID:", bds.getUsername());
boolean allowUserIDEntry = true;
if (!serverInfo.hasDefaultLogin()) {
nameCb.setName(bds.getUsername());
allowUserIDEntry = false;
}
PasswordCallback passCb = new PasswordCallback(" ", false); // force use of default prompting
try {
if (!clientAuthenticator.processPasswordCallbacks(
"BSim Database Authentication", "BSim Database Server",
serverInfo.toString(), nameCb, passCb, null, null, loginError)) {
"BSim Database Authentication", "BSim DB Server", serverInfo.toString(),
allowUserIDEntry, nameCb, passCb, null, null, loginError)) {
throw new CancelledException();
}
bds.setPassword(new String(passCb.getPassword()));

View file

@ -376,7 +376,7 @@ public class BSimServerInfo implements Comparable<BSimServerInfo> {
}
/**
* Determine of user info was stipulated during construction
* Determine if user info was stipulated during construction
* @return true if user info was stipulated during construction
*/
public boolean hasDefaultLogin() {

View file

@ -590,8 +590,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
if (isRunningHeadless()) {
// only change client authenticator in headless mode
try {
HeadlessClientAuthenticator.installHeadlessClientAuthenticator(
ClientUtil.getUserName(), null, false);
HeadlessClientAuthenticator
.installHeadlessClientAuthenticator(ClientUtil.getUserName(), null, false);
}
catch (IOException e) {
throw new RuntimeException("Unexpected Exception", e);
@ -2629,8 +2629,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
Address choice = doAsk(Integer.class, title, message, existingValue, lastValue -> {
AskAddrDialog dialog =
new AskAddrDialog(title, message, currentProgram, lastValue);
AskAddrDialog dialog = new AskAddrDialog(title, message, currentProgram, lastValue);
if (dialog.isCanceled()) {
throw new CancelledException();
}
@ -3158,7 +3157,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
throw new ImproperUseException(
"The askPassword() method can only be used when running headed Ghidra.");
}
PasswordDialog dialog = new PasswordDialog(title, null, null, prompt, null, null);
PasswordDialog dialog = new PasswordDialog(title, null, null, prompt);
try {
state.getTool().showDialog(dialog);
if (!dialog.okWasPressed()) {

View file

@ -20,6 +20,8 @@ import java.awt.event.*;
import javax.swing.*;
import org.apache.commons.lang3.StringUtils;
import docking.DialogComponentProvider;
import docking.widgets.checkbox.GCheckBox;
import docking.widgets.combobox.GComboBox;
@ -39,26 +41,34 @@ public class PasswordDialog extends DialogComponentProvider {
private JComboBox<String> choiceCB;
private JCheckBox anonymousAccess;
private boolean okPressed = false;
private String defaultUserID;
private String defaultUserId;
/**
* Construct a new PasswordDialog.
* Construct a new PasswordDialog which may include user ID specification/prompt, if either
* {@code allowUserIdEntry} is true or a non-null {@code defaultUserId} has been specified, and
* other optional elements. The dialog includes a message text area which supports the use
* of {@link #setErrorText(String)}.
*
* @param title title of the dialog
* @param serverType 'Server' or 'Key-store' designation
* @param serverName name of server or keystore pathname
* @param passPrompt password prompt to show in the dialog; may be null, in which case
* @param passPrompt password prompt to show in the dialog; may be null/empty, in which case
* "Password:" is displayed next to the password field
* @param userIdPrompt User ID / Name prompt to show in the dialog, if null a name will not be prompted for.
* @param defaultUserID default name when prompting for a name
* @param allowUserIdEntry if true user ID entry will be supported
* @param userIdPrompt User ID / Name prompt to show in the dialog, if null "User ID:" is prompt
* if either {@code allowUserIdEntry} is true or a non-null {@code defaultUserId} has been specified.
* @param defaultUserId default name when prompting for a name
* @param choicePrompt namePrompt name prompt to show in the dialog, if null a name will not be prompted for.
* @param choices array of choices to present if choicePrompt is not null
* @param defaultChoice default choice index
* @param includeAnonymousOption true signals to add a checkbox to request anonymous login
*/
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
String userIdPrompt, String defaultUserID, String choicePrompt, String[] choices,
int defaultChoice, boolean includeAnonymousOption) {
this(title, serverType, serverName, passPrompt, userIdPrompt, defaultUserID);
boolean allowUserIdEntry, String userIdPrompt, String defaultUserId,
String choicePrompt, String[] choices, int defaultChoice,
boolean includeAnonymousOption) {
this(title, serverType, serverName, passPrompt, allowUserIdEntry, userIdPrompt,
defaultUserId, true);
if (choicePrompt != null) {
workPanel.add(new GLabel(choicePrompt));
choiceCB = new GComboBox<>(choices);
@ -89,43 +99,70 @@ public class PasswordDialog extends DialogComponentProvider {
}
/**
* Construct a new PasswordDialog.
* Construct a new PasswordDialog which only prompts for a password for a specified server
* type and name. The dialog will not include a User ID display, although server fields
* may be used for a similar display purpose. The dialog includes a message text area
* which supports the use of {@link #setErrorText(String)}.
*
* @param title title of the dialog
* @param serverType 'Server' or 'Key-store' designation
* @param serverName name of server or keystore pathname
* @param passPrompt password prompt to show in the dialog; may be null, in which case
* "Password:" is displayed next to the password field
* @param userIdPrompt User ID / Name prompt to show in the dialog, if null a name will not be prompted for.
* @param defaultUserID default name when prompting for a name
* "Password:" is prompt.
*/
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
String userIdPrompt, String defaultUserID) {
this(title, serverType, serverName, passPrompt, userIdPrompt, defaultUserID, true);
public PasswordDialog(String title, String serverType, String serverName, String passPrompt) {
this(title, serverType, serverName, passPrompt, true);
}
/**
* Construct a new PasswordDialog.
* Construct a new PasswordDialog which only prompts for a password for a specified server
* type and name. The dialog will not include a User ID display, although server fields
* may be used for a similar display purpose. The dialog optionally includes a message
* text area which supports the use of {@link #setErrorText(String)}.
*
* @param title title of the dialog
* @param serverType 'Server' or 'Key-store' designation
* @param serverName name of server or keystore pathname
* @param passPrompt password prompt to show in the dialog; may be null, in which case
* "Password:" is displayed next to the password field
* @param userIdPrompt User ID / Name prompt to show in the dialog, if null a name will not be prompted for.
* @param defaultUserID default name when prompting for a name
* @param hasMessages true if the client will set messages on this dialog. If true, the
* dialog's minimum size will be increased
* @param hasMessages true if a message text area should be included allowing for use of
* {@link #setErrorText(String)}
*/
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
String userIdPrompt, String defaultUserID, boolean hasMessages) {
boolean hasMessages) {
this(title, serverType, serverName, passPrompt, false, null, null, hasMessages);
}
/**
* Construct a new PasswordDialog which may include user ID specification/prompt if either
* {@code allowUserIdEntry} is true or a non-null {@code defaultUserId} has been specified.
* The dialog optionally includes a message text area area which supports the use of
* {@link #setErrorText(String)}.
*
* @param title title of the dialog
* @param serverType 'Server' or 'Key-store' designation
* @param serverName name of server or keystore pathname
* @param passPrompt password prompt to show in the dialog; may be null/empty, in which case
* "Password:" is displayed next to the password field
* @param allowUserIdEntry if true user ID entry will be supported
* @param userIdPrompt User ID / Name prompt to show in the dialog, if null "User ID:" is prompt
* if either {@code allowUserIdEntry} is true or a non-null {@code defaultUserId} has been specified.
* @param defaultUserId default name when prompting for a name
* @param hasMessages true if a message text area should be included allowing for use of
* {@link #setErrorText(String)}
*/
public PasswordDialog(String title, String serverType, String serverName, String passPrompt,
boolean allowUserIdEntry, String userIdPrompt, String defaultUserId,
boolean hasMessages) {
super(title, true);
this.defaultUserID = defaultUserID;
this.defaultUserId = defaultUserId;
setRememberSize(false);
setTransient(true);
if (hasMessages) {
setMinimumSize(300, 150);
setMinimumSize(350, 150);
}
workPanel = new JPanel(new PairLayout(5, 5));
@ -136,20 +173,27 @@ public class PasswordDialog extends DialogComponentProvider {
workPanel.add(new GLabel(serverName));
}
if (userIdPrompt != null) {
if (StringUtils.isBlank(userIdPrompt)) {
userIdPrompt = "User ID:";
}
if (StringUtils.isBlank(passPrompt)) {
passPrompt = "Password:";
}
if (allowUserIdEntry) {
workPanel.add(new GLabel(userIdPrompt));
nameField = new JTextField(defaultUserID, 16);
nameField = new JTextField(defaultUserId, 16);
nameField.setName("NAME-ENTRY-COMPONENT");
workPanel.add(nameField);
}
else if (defaultUserID != null) {
workPanel.add(new GLabel("User ID:"));
JLabel nameLabel = new GLabel(defaultUserID);
else if (defaultUserId != null) {
workPanel.add(new GLabel(userIdPrompt));
JLabel nameLabel = new GLabel(defaultUserId);
nameLabel.setName("NAME-COMPONENT");
workPanel.add(nameLabel);
}
workPanel.add(new GLabel(passPrompt != null ? passPrompt : "Password:"));
workPanel.add(new GLabel(passPrompt));
passwordField = new JPasswordField(16);
passwordField.setName("PASSWORD-ENTRY-COMPONENT");
workPanel.add(passwordField);
@ -245,7 +289,7 @@ public class PasswordDialog extends DialogComponentProvider {
* @return the user ID / Name entered in the password field
*/
public String getUserID() {
return nameField != null ? nameField.getText().trim() : defaultUserID;
return nameField != null ? nameField.getText().trim() : defaultUserId;
}
/**

View file

@ -1,13 +1,12 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -63,7 +62,7 @@ public class PopupKeyStorePasswordProvider implements KeyStorePasswordProvider {
@Override
public void run() {
PasswordDialog pwdDialog =
new PasswordDialog("Protected PKI Certificate", "Cert File", file, null, null, null);
new PasswordDialog("Protected PKI Certificate", "Cert File", file, null);
if (passwordError) {
pwdDialog.setErrorText("Incorrect password");
}

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -139,8 +139,8 @@ public class SplashScreenTest extends AbstractDockingTest {
private DockingDialog showModalPasswordDialog(Frame parentFrame) throws Exception {
String dialogTitle = "InfoWindowTest.testSplashScreenPasswordModality() Dialog";
DialogComponentProvider passwordDialog = runSwing(() -> new PasswordDialog(dialogTitle,
"Server Type", "Server Name", "Prompt", null, null));
DialogComponentProvider passwordDialog =
runSwing(() -> new PasswordDialog(dialogTitle, "Server Type", "Server Name", "Prompt"));
if (parentFrame == null) {
// null means to share the parent

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -33,10 +33,11 @@ public interface ClientAuthenticator extends KeyStorePasswordProvider {
public Authenticator getAuthenticator();
/**
* Process Ghidra Server password authentication callbacks.
* Process password authentication callbacks.
* @param title password prompt title if GUI is used
* @param serverType type of server (label associated with serverName)
* @param serverName name of server
* @param allowUserNameEntry if true user ID entry will be supported if nameCb is not null.
* @param nameCb provides storage for user login name. A null indicates
* that the default user name will be used, @see ClientUtil#getUserName()
* @param passCb provides storage for user password, @see PasswordCallback#setPassword(char[])
@ -51,8 +52,8 @@ public interface ClientAuthenticator extends KeyStorePasswordProvider {
* @return true if password provided, false if entry cancelled
*/
public boolean processPasswordCallbacks(String title, String serverType, String serverName,
NameCallback nameCb, PasswordCallback passCb, ChoiceCallback choiceCb,
AnonymousCallback anonymousCb, String loginError);
boolean allowUserNameEntry, NameCallback nameCb, PasswordCallback passCb,
ChoiceCallback choiceCb, AnonymousCallback anonymousCb, String loginError);
/**
* Prompt user for reconnect

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -425,7 +425,8 @@ public class ClientUtil {
"Unsupported authentication callback: " + callbacks[0].getClass().getName());
}
if (!clientAuthenticator.processPasswordCallbacks("Repository Server Authentication",
"Repository Server", serverName, nameCb, passCb, choiceCb, anonymousCb, loginError)) {
"Repository Server", serverName, nameCb != null, nameCb, passCb, choiceCb, anonymousCb,
loginError)) {
return false;
}
String name = defaultUserID;

View file

@ -72,13 +72,14 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
if (pwd != null) {
// Requesting URL specified password
return new PasswordAuthentication(userName, pwd.toCharArray());
return new PasswordAuthentication(userName, pwd.toCharArray());
}
NameCallback nameCb = new NameCallback("Name: ", userName);
boolean allowUserIDEntry = true;
if (!useDefaultUser) {
// Prevent modification of user name by password prompting
nameCb.setName(userName);
allowUserIDEntry = false;
}
// Prompt for password
@ -89,10 +90,10 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
PasswordCallback passCb = new PasswordCallback(prompt, false);
try {
ServerPasswordPrompt pp = new ServerPasswordPrompt("Connection Authentication",
"Server", serverName, nameCb, passCb, null, null, null);
"Server", serverName, allowUserIDEntry, nameCb, passCb, null, null, null);
SystemUtilities.runSwingNow(pp);
if (pp.okWasPressed()) {
return new PasswordAuthentication(nameCb.getName(), passCb.getPassword());
return new PasswordAuthentication(nameCb.getName(), passCb.getPassword());
}
}
finally {
@ -135,10 +136,10 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
@Override
public boolean processPasswordCallbacks(String title, String serverType, String serverName,
NameCallback nameCb, PasswordCallback passCb, ChoiceCallback choiceCb,
AnonymousCallback anonymousCb, String loginError) {
ServerPasswordPrompt pp = new ServerPasswordPrompt(title, serverType, serverName, nameCb,
passCb, choiceCb, anonymousCb, loginError);
boolean allowUserNameEntry, NameCallback nameCb, PasswordCallback passCb,
ChoiceCallback choiceCb, AnonymousCallback anonymousCb, String loginError) {
ServerPasswordPrompt pp = new ServerPasswordPrompt(title, serverType, serverName,
allowUserNameEntry, nameCb, passCb, choiceCb, anonymousCb, loginError);
SystemUtilities.runSwingNow(pp);
return pp.okWasPressed();
}
@ -172,6 +173,7 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
private String title;
private String serverType; // label for serverName field
private String serverName;
private boolean allowUserIDEntry;
private NameCallback nameCb;
private PasswordCallback passCb;
private ChoiceCallback choiceCb;
@ -180,11 +182,12 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
private boolean okPressed = false;
ServerPasswordPrompt(String title, String serverType, String serverName,
NameCallback nameCb, PasswordCallback passCb, ChoiceCallback choiceCb,
AnonymousCallback anonymousCb, String errorMsg) {
boolean allowUserIDEntry, NameCallback nameCb, PasswordCallback passCb,
ChoiceCallback choiceCb, AnonymousCallback anonymousCb, String errorMsg) {
this.title = title;
this.serverType = serverType;
this.serverName = serverName;
this.allowUserIDEntry = allowUserIDEntry && (nameCb != null);
this.nameCb = nameCb;
this.passCb = passCb;
this.choiceCb = choiceCb;
@ -225,20 +228,20 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
String defaultUserName = null;
String namePrompt = null;
if (nameCb != null) {
namePrompt = nameCb.getPrompt();
defaultUserName = nameCb.getName();
if (defaultUserName == null) {
// Name entry only permitted with name callback where name has not be pre-set
if (StringUtils.isBlank(defaultUserName)) {
defaultUserName = nameCb.getDefaultName();
namePrompt = nameCb.getPrompt();
}
}
if (defaultUserName == null) {
if (StringUtils.isBlank(defaultUserName)) {
defaultUserName = getDefaultUserName();
}
PasswordDialog pwdDialog = new PasswordDialog(title, serverType, serverName,
passCb.getPrompt(), namePrompt, defaultUserName, choicePrompt, choices,
getDefaultChoice(), anonymousCb != null);
passCb.getPrompt(), allowUserIDEntry, namePrompt, defaultUserName, choicePrompt,
choices, getDefaultChoice(), anonymousCb != null);
if (errorMsg != null) {
pwdDialog.setErrorText(errorMsg);
@ -252,7 +255,7 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider
}
else {
passCb.setPassword(pwdDialog.getPassword());
if (nameCb != null) {
if (nameCb != null && allowUserIDEntry) {
String username = pwdDialog.getUserID();
nameCb.setName(username);
Preferences.setProperty(NAME_PREFERENCE, username);

View file

@ -39,22 +39,25 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
private final static char[] BADPASSWORD = "".toCharArray();
private static Object sshPrivateKey;
private static String defaultUserName = ClientUtil.getUserName();
private static String preferredName = null;
private static boolean passwordPromptAllowed;
/**
* Simple authentication handler using a default authenticator which may be passed to
* {@link Authenticator#setDefault(Authenticator)}. The preferred username must be set by
* invoking {@link #installHeadlessClientAuthenticator(String, String, boolean)} or
* stipulated by the requesting URL. The {@link ClientUtil#getUserName()} identity is never
* used.
*/
private Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (defaultUserName == null) {
throw new IllegalStateException("Default user name is unknown");
}
String serverName = getRequestingHost();
URL requestingURL = getRequestingURL(); // may be null
String pwd = null;
String userName = defaultUserName;
String name = preferredName;
if (requestingURL != null) {
String userInfo = requestingURL.getUserInfo();
@ -62,12 +65,12 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
// Use user info from URL
int pwdSep = userInfo.indexOf(':');
if (pwdSep < 0) {
userName = userInfo;
name = userInfo;
}
else {
pwd = userInfo.substring(pwdSep + 1);
if (pwdSep != 0) {
userName = userInfo.substring(0, pwdSep);
name = userInfo.substring(0, pwdSep);
}
}
}
@ -77,20 +80,24 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
serverName = minimalURL.toExternalForm();
}
}
Msg.debug(this, "PasswordAuthentication requested for " + serverName);
if (StringUtils.isBlank(name)) {
throw new IllegalStateException("Connection user name is unknown");
}
if (pwd != null) {
// Requesting URL specified password
return new PasswordAuthentication(userName, pwd.toCharArray());
return new PasswordAuthentication(name, pwd.toCharArray());
}
String usage = "Access password requested for " + serverName;
String prompt = getRequestingPrompt();
if (StringUtils.isBlank(prompt) || "security".equals(prompt)) {
prompt = "Password for " + userName +":";
prompt = "Password for " + name + ":";
}
return new PasswordAuthentication(userName, getPassword(usage, prompt));
return new PasswordAuthentication(name, getPassword(usage, prompt));
}
};
@ -103,7 +110,9 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
}
/**
* Install headless client authenticator for Ghidra Server
* Install headless client authenticator for Ghidra Server and when http/https
* connections require authentication and have not specified user information.
*
* @param username optional username to be used with a Ghidra Server which
* allows username to be specified. If null, {@link ClientUtil#getUserName()}
* will be used.
@ -118,7 +127,7 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
boolean allowPasswordPrompt) throws IOException {
passwordPromptAllowed = allowPasswordPrompt;
if (username != null) {
defaultUserName = username;
preferredName = username;
}
// clear existing key store settings
@ -247,45 +256,48 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
@Override
public boolean processPasswordCallbacks(String title, String serverType, String serverName,
NameCallback nameCb, PasswordCallback passCb, ChoiceCallback choiceCb,
AnonymousCallback anonymousCb, String loginError) {
boolean allowUserNameEntry, NameCallback nameCb, PasswordCallback passCb,
ChoiceCallback choiceCb, AnonymousCallback anonymousCb, String loginError) {
if (anonymousCb != null && !passwordPromptAllowed) {
// Assume that login error will not occur with anonymous login
anonymousCb.setAnonymousAccessRequested(true);
return true;
}
if (defaultUserName == null) {
throw new IllegalStateException("Default user name is unknown");
}
if (choiceCb != null) {
choiceCb.setSelectedIndex(1);
}
String userName = null;
if (nameCb != null) {
userName = nameCb.getName();
if (userName == null) {
userName = nameCb.getDefaultName();
if (allowUserNameEntry) {
// use preferred login name
userName = preferredName;
}
if (StringUtils.isBlank(userName)) {
// check for default login name in order of precedence
userName = nameCb.getName();
if (StringUtils.isBlank(userName)) {
userName = nameCb.getDefaultName();
}
}
if (allowUserNameEntry) {
nameCb.setName(userName);
}
}
if (userName == null) {
userName = defaultUserName;
}
if (nameCb != null) {
nameCb.setName(defaultUserName);
if (!StringUtils.isBlank(userName)) {
userName = ClientUtil.getUserName();
}
String usage = null;
if (serverName != null) {
usage = serverType + ": " + serverName;
}
// Ignore prompt specified by passCb
String prompt = "Password for " + userName +":";
String prompt = "Password for " + userName + ":";
char[] password = getPassword(usage, prompt);
passCb.setPassword(password);
return password != null;
@ -321,7 +333,18 @@ public class HeadlessClientAuthenticator implements ClientAuthenticator {
return false;
}
if (nameCb != null) {
nameCb.setName(defaultUserName);
// presence of NameCallback implies user is allowed to specify name
String userName = preferredName;
if (StringUtils.isBlank(userName)) {
userName = nameCb.getName();
if (StringUtils.isBlank(userName)) {
userName = nameCb.getDefaultName();
}
if (!StringUtils.isBlank(userName)) {
userName = ClientUtil.getUserName();
}
}
nameCb.setName(userName);
}
try {
sshCb.sign(sshPrivateKey);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -83,14 +83,24 @@ public class PasswordClientAuthenticator implements ClientAuthenticator {
}
@Override
public boolean processPasswordCallbacks(String title, String serverType,
String serverName, NameCallback nameCb, PasswordCallback passCb,
public boolean processPasswordCallbacks(String title, String serverType, String serverName,
boolean allowUserNameEntry, NameCallback nameCb, PasswordCallback passCb,
ChoiceCallback choiceCb, AnonymousCallback anonymousCb, String loginError) {
if (choiceCb != null) {
choiceCb.setSelectedIndex(1);
}
if (nameCb != null && username != null) {
nameCb.setName(username);
if (nameCb != null && allowUserNameEntry) {
String name = username;
if (name == null) {
name = nameCb.getName();
}
if (name == null) {
name = nameCb.getDefaultName();
}
if (name == null) {
name = ClientUtil.getUserName();
}
nameCb.setName(name);
}
passCb.setPassword(password.clone());
return true;