Skip to content

Commit 6a5de82

Browse files
committed
Validate jumphost configuration on connect.
1 parent 07ee299 commit 6a5de82

File tree

4 files changed

+39
-22
lines changed

4 files changed

+39
-22
lines changed

core/src/main/java/ch/cyberduck/core/Host.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public class Host implements Serializable, Comparable<Host>, PreferencesReader {
3838
* The credentials to authenticate with for the CDN
3939
*/
4040
private final Credentials cloudfront = new Credentials();
41+
/**
42+
* Proxy configuration
43+
*/
44+
private Host jumphost;
4145
/**
4246
* The protocol identifier.
4347
*/
@@ -357,6 +361,14 @@ public Host withCredentials(final Credentials credentials) {
357361
return this;
358362
}
359363

364+
public Host getJumphost() {
365+
return jumphost;
366+
}
367+
368+
public void setJumphost(final Host jumphost) {
369+
this.jumphost = jumphost;
370+
}
371+
360372
/**
361373
* @return Credentials to modify CDN configuration
362374
*/

core/src/main/java/ch/cyberduck/core/KeychainLoginService.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public KeychainLoginService(final HostPasswordStore keychain) {
4343
@Override
4444
public void validate(final Host host, final X509KeyManager keys, final LoginCallback prompt, final LoginOptions options) throws ConnectionCanceledException, LoginFailureException {
4545
log.debug("Validate login credentials for {}", host);
46+
final Host jumphost = host.getJumphost();
47+
if(null != jumphost) {
48+
this.validate(jumphost, keys, prompt, new LoginOptions(jumphost.getProtocol()));
49+
}
4650
final Credentials credentials = host.getCredentials();
4751
if(credentials.isPublicKeyAuthentication()) {
4852
if(!credentials.getIdentity().attributes().getPermission().isReadable()) {
@@ -213,9 +217,12 @@ public boolean authenticate(final Session<?> session, final ProgressListener lis
213217
public void save(final Host bookmark) {
214218
final Credentials credentials = bookmark.getCredentials();
215219
if(credentials.isSaved()) {
216-
// Write credentials to keychain
220+
// Write credentials to the password store
217221
try {
218222
keychain.save(bookmark);
223+
if(bookmark.getJumphost() != null) {
224+
keychain.save(bookmark.getJumphost());
225+
}
219226
}
220227
catch(LocalAccessDeniedException e) {
221228
log.error("Failure saving credentials for {} in keychain. {}", bookmark, e);

core/src/main/java/ch/cyberduck/core/LoginConnectionService.java

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,15 @@ public boolean check(final Session<?> session, final CancelCallback callback) th
8989
}
9090
if(session.isConnected()) {
9191
log.debug("Skip opening connection for session {}", session);
92-
// Connection already open
92+
// Connection is already open
9393
return false;
9494
}
95-
// Obtain password from keychain or prompt
95+
final Host jumphost = JumpHostConfiguratorFactory.get(bookmark.getProtocol()).getJumphost(bookmark.getHostname());
96+
if(null != jumphost) {
97+
log.debug("Configure with jump host {}", jumphost);
98+
bookmark.setJumphost(jumphost);
99+
}
100+
// Get password from the password store or prompt
96101
synchronized(login) {
97102
login.validate(bookmark, session.getFeature(X509KeyManager.class), prompt, new LoginOptions(bookmark.getProtocol()));
98103
}
@@ -103,7 +108,7 @@ public boolean check(final Session<?> session, final CancelCallback callback) th
103108
@Override
104109
public void close(final Session<?> session) throws BackgroundException {
105110
listener.message(MessageFormat.format(LocaleFactory.localizedString("Disconnecting {0}", "Status"),
106-
session.getHost().getHostname()));
111+
session.getHost().getHostname()));
107112
// Close the underlying socket first
108113
session.interrupt();
109114
}
@@ -131,24 +136,24 @@ public void connect(final Session<?> session, final CancelCallback cancel) throw
131136
}
132137
}
133138
listener.message(MessageFormat.format(LocaleFactory.localizedString("Opening {0} connection to {1}", "Status"),
134-
bookmark.getProtocol().getName(), hostname));
139+
bookmark.getProtocol().getName(), hostname));
135140
// The IP address could successfully be determined
136141
session.open(proxy, key, prompt, cancel);
137142
listener.message(MessageFormat.format(LocaleFactory.localizedString("{0} connection opened", "Status"),
138-
bookmark.getProtocol().getName()));
143+
bookmark.getProtocol().getName()));
139144
// Update last accessed timestamp
140145
bookmark.setTimestamp(new Date());
141146
// Warning about insecure connection prior authenticating
142147
if(session.alert(prompt)) {
143148
// Warning if credentials are sent plaintext.
144149
prompt.warn(bookmark, MessageFormat.format(LocaleFactory.localizedString("Unsecured {0} connection", "Credentials"),
145-
bookmark.getProtocol().getName()),
146-
MessageFormat.format("{0} {1}.", MessageFormat.format(LocaleFactory.localizedString("{0} will be sent in plaintext.", "Credentials"),
147-
bookmark.getProtocol().getPasswordPlaceholder()),
148-
LocaleFactory.localizedString("Please contact your web hosting service provider for assistance", "Support")),
149-
LocaleFactory.localizedString("Continue", "Credentials"),
150-
LocaleFactory.localizedString("Disconnect", "Credentials"),
151-
String.format("connection.unsecure.%s", bookmark.getHostname()));
150+
bookmark.getProtocol().getName()),
151+
MessageFormat.format("{0} {1}.", MessageFormat.format(LocaleFactory.localizedString("{0} will be sent in plaintext.", "Credentials"),
152+
bookmark.getProtocol().getPasswordPlaceholder()),
153+
LocaleFactory.localizedString("Please contact your web hosting service provider for assistance", "Support")),
154+
LocaleFactory.localizedString("Continue", "Credentials"),
155+
LocaleFactory.localizedString("Disconnect", "Credentials"),
156+
String.format("connection.unsecure.%s", bookmark.getHostname()));
152157
}
153158
// Login
154159
try {
@@ -163,7 +168,7 @@ public void connect(final Session<?> session, final CancelCallback cancel) throw
163168
private void authenticate(final Session<?> session, final CancelCallback callback) throws BackgroundException {
164169
if(!login.authenticate(session, listener, prompt, callback)) {
165170
if(session.isConnected()) {
166-
// Next attempt with updated credentials but cancel when prompt is dismissed
171+
// Next attempt with updated credentials but cancel when the prompt is dismissed
167172
this.authenticate(session, callback);
168173
}
169174
else {

ssh/src/main/java/ch/cyberduck/core/sftp/SFTPSession.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,8 @@
3939
import ch.cyberduck.core.sftp.compression.JcraftDelayedZlibCompression;
4040
import ch.cyberduck.core.sftp.compression.JcraftZlibCompression;
4141
import ch.cyberduck.core.sftp.openssh.OpenSSHAgentAuthenticator;
42-
import ch.cyberduck.core.sftp.openssh.OpenSSHCredentialsConfigurator;
4342
import ch.cyberduck.core.sftp.openssh.OpenSSHHostnameConfigurator;
4443
import ch.cyberduck.core.sftp.openssh.OpenSSHIdentityAgentConfigurator;
45-
import ch.cyberduck.core.sftp.openssh.OpenSSHJumpHostConfigurator;
4644
import ch.cyberduck.core.sftp.openssh.OpenSSHPreferredAuthenticationsConfigurator;
4745
import ch.cyberduck.core.sftp.openssh.WindowsOpenSSHAgentAuthenticator;
4846
import ch.cyberduck.core.sftp.putty.PageantAuthenticator;
@@ -144,19 +142,14 @@ protected SSHClient connect(final HostKeyCallback key, final LoginCallback promp
144142
final SSHClient connection = this.toClient(key, configuration);
145143
try {
146144
// Look for jump host configuration
147-
final Host proxy = new OpenSSHJumpHostConfigurator().getJumphost(host.getHostname());
145+
final Host proxy = host.getJumphost();
148146
if(null != proxy) {
149147
log.info("Connect using jump host configuration {}", proxy);
150148
final SSHClient hop = this.toClient(key, configuration);
151149
hop.connect(proxy.getHostname(), proxy.getPort());
152-
proxy.setCredentials(new OpenSSHCredentialsConfigurator().configure(proxy));
153-
final KeychainLoginService service = new KeychainLoginService();
154-
service.validate(proxy, prompt, new LoginOptions(proxy.getProtocol()));
155150
// Authenticate with jump host
156151
this.authenticate(hop, proxy, prompt, new DisabledCancelCallback());
157152
log.debug("Authenticated with jump host {}", proxy);
158-
// Write credentials to keychain
159-
service.save(proxy);
160153
final DirectConnection tunnel = hop.newDirectConnection(
161154
new OpenSSHHostnameConfigurator().getHostname(host.getHostname()), host.getPort());
162155
// Connect to internal host

0 commit comments

Comments
 (0)