Skip to content

Commit

Permalink
Skip reading keys from SSH agent with IdentitiesOnly configuration di…
Browse files Browse the repository at this point in the history
…rective is found in ~/.ssh/config
  • Loading branch information
dkocher committed May 4, 2021
1 parent 3fcf41f commit 6120054
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 28 deletions.
20 changes: 13 additions & 7 deletions ssh/src/main/java/ch/cyberduck/core/sftp/SFTPSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import ch.cyberduck.core.sftp.openssh.OpenSSHAgentAuthenticator;
import ch.cyberduck.core.sftp.openssh.OpenSSHCredentialsConfigurator;
import ch.cyberduck.core.sftp.openssh.OpenSSHHostnameConfigurator;
import ch.cyberduck.core.sftp.openssh.OpenSSHIdentitiesOnlyConfigurator;
import ch.cyberduck.core.sftp.openssh.OpenSSHJumpHostConfigurator;
import ch.cyberduck.core.sftp.openssh.OpenSSHPreferredAuthenticationsConfigurator;
import ch.cyberduck.core.sftp.putty.PageantAuthenticator;
Expand Down Expand Up @@ -272,13 +273,18 @@ private void authenticate(final SSHClient client, final Host host, final LoginCa
// Ordered list of preferred authentication methods
final List<AuthenticationProvider<Boolean>> defaultMethods = new ArrayList<>();
if(preferences.getBoolean("ssh.authentication.agent.enable")) {
switch(Factory.Platform.getDefault()) {
case windows:
defaultMethods.add(new SFTPAgentAuthentication(client, new PageantAuthenticator()));
break;
default:
defaultMethods.add(new SFTPAgentAuthentication(client, new OpenSSHAgentAuthenticator()));
break;
if(new OpenSSHIdentitiesOnlyConfigurator().isIdentitiesOnly(host.getHostname())) {
log.warn("Skip reading keys from SSH agent with IdentitiesOnly configuration");
}
else {
switch(Factory.Platform.getDefault()) {
case windows:
defaultMethods.add(new SFTPAgentAuthentication(client, new PageantAuthenticator()));
break;
default:
defaultMethods.add(new SFTPAgentAuthentication(client, new OpenSSHAgentAuthenticator()));
break;
}
}
}
defaultMethods.add(new SFTPPublicKeyAuthentication(client));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package ch.cyberduck.core.sftp.openssh;

/*
* Copyright (c) 2012 David Kocher. All rights reserved.
* http://cyberduck.ch/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Bug fixes, suggestions and comments should be sent to:
* dkocher@cyberduck.ch
*/

import ch.cyberduck.core.LocalFactory;
import ch.cyberduck.core.sftp.openssh.config.transport.OpenSshConfig;

public class OpenSSHIdentitiesOnlyConfigurator {
private final OpenSshConfig configuration;

public OpenSSHIdentitiesOnlyConfigurator() {
this(new OpenSshConfig(LocalFactory.get(LocalFactory.get(LocalFactory.get(), ".ssh"), "config")));
}

public OpenSSHIdentitiesOnlyConfigurator(final OpenSshConfig configuration) {
this.configuration = configuration;
}

public boolean isIdentitiesOnly(final String alias) {
final Boolean identitiesOnly = configuration.lookup(alias).isIdentitiesOnly();
if(null == identitiesOnly) {
return false;
}
return identitiesOnly;
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder("OpenSSHHostnameConfigurator{");
sb.append("configuration=").append(configuration);
sb.append('}');
return sb.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,14 @@ public class OpenSshConfig {
* Cached entries read out of the configuration file.
*/
private Map<String, Host> hosts
= Collections.emptyMap();
= Collections.emptyMap();

/**
* Obtain the user's configuration data.
* <p/>
* The configuration file is always returned to the caller, even if no file
* exists in the user's home directory at the time the call was made. Lookup
* requests are cached and are automatically updated if the user modifies
* the configuration file since the last time it was cached.
* The configuration file is always returned to the caller, even if no file exists in the user's home directory at
* the time the call was made. Lookup requests are cached and are automatically updated if the user modifies the
* configuration file since the last time it was cached.
*/
public OpenSshConfig(final Local configuration) {
this.configuration = configuration;
Expand All @@ -95,9 +94,8 @@ public OpenSshConfig(final Local configuration) {
/**
* Locate the configuration for a specific host request.
*
* @param hostName the name the user has supplied to the SSH tool. This may be a
* real host name, or it may just be a "Host" block in the
* configuration file.
* @param hostName the name the user has supplied to the SSH tool. This may be a real host name, or it may just be a
* "Host" block in the configuration file.
* @return r configuration for the requested name. Never null.
*/
public Host lookup(final String hostName) {
Expand Down Expand Up @@ -235,6 +233,13 @@ else if("PreferredAuthentications".equalsIgnoreCase(keyword)) {
}
}
}
else if("IdentitiesOnly".equalsIgnoreCase(keyword)) {
for(final Host c : current) {
if(c.identitiesOnly == null) {
c.identitiesOnly = yesno(dequote(argValue));
}
}
}
else if("BatchMode".equalsIgnoreCase(keyword)) {
for(final Host c : current) {
if(c.batchMode == null) {
Expand Down Expand Up @@ -290,13 +295,11 @@ private static Boolean yesno(final String value) {
/**
* Configuration of one "Host" block in the configuration file.
* <p/>
* If returned from {@link OpenSshConfig#lookup(String)} some or all of the
* properties may not be populated. The properties which are not populated
* should be defaulted by the caller.
* If returned from {@link OpenSshConfig#lookup(String)} some or all of the properties may not be populated. The
* properties which are not populated should be defaulted by the caller.
* <p/>
* When returned from {@link OpenSshConfig#lookup(String)} any wildcard
* entries which appear later in the configuration file will have been
* already merged into this block.
* When returned from {@link OpenSshConfig#lookup(String)} any wildcard entries which appear later in the
* configuration file will have been already merged into this block.
*/
public static class Host {
boolean patternsApplied;
Expand All @@ -307,6 +310,7 @@ public static class Host {
Local identityFile;
String user;
String preferredAuthentications;
Boolean identitiesOnly;
Boolean batchMode;

void copyFrom(final Host src) {
Expand All @@ -331,6 +335,9 @@ void copyFrom(final Host src) {
if(batchMode == null) {
batchMode = src.batchMode;
}
if(identitiesOnly == null) {
identitiesOnly = src.identitiesOnly;
}
}

/**
Expand All @@ -352,8 +359,8 @@ public int getPort() {
}

/**
* @return path of the private key file to use for authentication; null
* if the caller should use default authentication strategies.
* @return path of the private key file to use for authentication; null if the caller should use default
* authentication strategies.
*/
public Local getIdentityFile() {
return identityFile;
Expand All @@ -367,16 +374,22 @@ public String getUser() {
}

/**
* @return the preferred authentication methods, separated by commas if
* more than one authentication method is preferred.
* @return the preferred authentication methods, separated by commas if more than one authentication method is
* preferred.
*/
public String getPreferredAuthentications() {
return preferredAuthentications;
}

/**
* @return true if batch (non-interactive) mode is preferred for this
* host connection.
* @return only use the configured authentication identity and certificate files
*/
public Boolean isIdentitiesOnly() {
return identitiesOnly;
}

/**
* @return true if batch (non-interactive) mode is preferred for this host connection.
*/
public boolean isBatchMode() {
return batchMode != null && batchMode;
Expand All @@ -385,12 +398,14 @@ public boolean isBatchMode() {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Host{");
sb.append("hostName='").append(hostName).append('\'');
sb.append("patternsApplied=").append(patternsApplied);
sb.append(", hostName='").append(hostName).append('\'');
sb.append(", proxyJump='").append(proxyJump).append('\'');
sb.append(", port=").append(port);
sb.append(", identityFile=").append(identityFile);
sb.append(", user='").append(user).append('\'');
sb.append(", preferredAuthentications='").append(preferredAuthentications).append('\'');
sb.append(", identitiesOnly=").append(identitiesOnly);
sb.append(", batchMode=").append(batchMode);
sb.append('}');
return sb.toString();
Expand Down

0 comments on commit 6120054

Please sign in to comment.