Don't use the ~/.ssh directory as cache key for the key provider but the configured paths of the default keys. Otherwise changes in that list of paths are not picked up. This is in particular a problem for EGit, where the user can modify this list of keys interactively in the preferences. Without this change, Eclipse needs to be restarted to pick up such changes. Bug: 542845 Change-Id: I63432fb10729a90b3c5e14f13e39bf482aef811b Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>tags/v5.3.0.201901161700-m1
identityFileCannotDecrypt=Given passphrase cannot decrypt identity {0} | identityFileCannotDecrypt=Given passphrase cannot decrypt identity {0} | ||||
identityFileNoKey=No keys found in identity {0} | identityFileNoKey=No keys found in identity {0} | ||||
identityFileMultipleKeys=Multiple key pairs found in identity {0} | identityFileMultipleKeys=Multiple key pairs found in identity {0} | ||||
identityFileNotFound=Skipping identity ''{0}'': file not found | |||||
identityFileUnsupportedFormat=Unsupported format in identity {0} | identityFileUnsupportedFormat=Unsupported format in identity {0} | ||||
kexServerKeyInvalid=Server key did not validate | kexServerKeyInvalid=Server key did not validate | ||||
keyEncryptedMsg=Key ''{0}'' is encrypted. Enter the passphrase to decrypt it. | keyEncryptedMsg=Key ''{0}'' is encrypted. Enter the passphrase to decrypt it. |
import static java.text.MessageFormat.format; | import static java.text.MessageFormat.format; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.file.Files; | |||||
import java.nio.file.Path; | import java.nio.file.Path; | ||||
import java.security.GeneralSecurityException; | import java.security.GeneralSecurityException; | ||||
import java.security.KeyPair; | import java.security.KeyPair; | ||||
@Override | @Override | ||||
protected KeyPair doLoadKey(Path resource) | protected KeyPair doLoadKey(Path resource) | ||||
throws IOException, GeneralSecurityException { | throws IOException, GeneralSecurityException { | ||||
if (!Files.exists(resource)) { | |||||
log.warn(format(SshdText.get().identityFileNotFound, resource)); | |||||
return null; | |||||
} | |||||
// By calling doLoadKey(String, Path, FilePasswordProvider) instead of | // By calling doLoadKey(String, Path, FilePasswordProvider) instead of | ||||
// super.doLoadKey(Path) we can bypass the key caching in | // super.doLoadKey(Path) we can bypass the key caching in | ||||
// AbstractResourceKeyPairProvider, over which we have no real control. | // AbstractResourceKeyPairProvider, over which we have no real control. |
/***/ public String identityFileCannotDecrypt; | /***/ public String identityFileCannotDecrypt; | ||||
/***/ public String identityFileNoKey; | /***/ public String identityFileNoKey; | ||||
/***/ public String identityFileMultipleKeys; | /***/ public String identityFileMultipleKeys; | ||||
/***/ public String identityFileNotFound; | |||||
/***/ public String identityFileUnsupportedFormat; | /***/ public String identityFileUnsupportedFormat; | ||||
/***/ public String kexServerKeyInvalid; | /***/ public String kexServerKeyInvalid; | ||||
/***/ public String keyEncryptedMsg; | /***/ public String keyEncryptedMsg; |
private static final class Tuple { | private static final class Tuple { | ||||
private Object[] objects; | private Object[] objects; | ||||
public Tuple(Object... objects) { | |||||
public Tuple(Object[] objects) { | |||||
this.objects = objects; | this.objects = objects; | ||||
} | } | ||||
private HostConfigEntryResolver getHostConfigEntryResolver( | private HostConfigEntryResolver getHostConfigEntryResolver( | ||||
@NonNull File homeDir, @NonNull File sshDir) { | @NonNull File homeDir, @NonNull File sshDir) { | ||||
return defaultHostConfigEntryResolver.computeIfAbsent( | return defaultHostConfigEntryResolver.computeIfAbsent( | ||||
new Tuple(homeDir, sshDir), | |||||
new Tuple(new Object[] { homeDir, sshDir }), | |||||
t -> new JGitSshConfig(homeDir, | t -> new JGitSshConfig(homeDir, | ||||
new File(sshDir, SshConstants.CONFIG), | new File(sshDir, SshConstants.CONFIG), | ||||
getLocalUserName())); | getLocalUserName())); | ||||
private ServerKeyVerifier getServerKeyVerifier(@NonNull File homeDir, | private ServerKeyVerifier getServerKeyVerifier(@NonNull File homeDir, | ||||
@NonNull File sshDir) { | @NonNull File sshDir) { | ||||
return defaultServerKeyVerifier.computeIfAbsent( | return defaultServerKeyVerifier.computeIfAbsent( | ||||
new Tuple(homeDir, sshDir), | |||||
new Tuple(new Object[] { homeDir, sshDir }), | |||||
t -> new OpenSshServerKeyVerifier(true, | t -> new OpenSshServerKeyVerifier(true, | ||||
getDefaultKnownHostsFiles(sshDir))); | getDefaultKnownHostsFiles(sshDir))); | ||||
} | } | ||||
*/ | */ | ||||
@NonNull | @NonNull | ||||
private KeyPairProvider getDefaultKeysProvider(@NonNull File sshDir) { | private KeyPairProvider getDefaultKeysProvider(@NonNull File sshDir) { | ||||
return defaultKeys.computeIfAbsent(new Tuple(sshDir), | |||||
t -> new CachingKeyPairProvider(getDefaultIdentities(sshDir), | |||||
List<Path> defaultIdentities = getDefaultIdentities(sshDir); | |||||
return defaultKeys.computeIfAbsent( | |||||
new Tuple(defaultIdentities.toArray(new Path[0])), | |||||
t -> new CachingKeyPairProvider(defaultIdentities, | |||||
getKeyCache())); | getKeyCache())); | ||||
} | } | ||||