You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SshdSessionFactory.java 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. /*
  2. * Copyright (C) 2018, 2020 Thomas Wolf <thomas.wolf@paranor.ch> and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.transport.sshd;
  11. import java.io.Closeable;
  12. import java.io.File;
  13. import java.io.IOException;
  14. import java.nio.file.Files;
  15. import java.nio.file.Path;
  16. import java.security.KeyPair;
  17. import java.time.Duration;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.HashSet;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.Set;
  25. import java.util.concurrent.ConcurrentHashMap;
  26. import java.util.concurrent.atomic.AtomicBoolean;
  27. import java.util.function.Supplier;
  28. import java.util.stream.Collectors;
  29. import org.apache.sshd.client.ClientBuilder;
  30. import org.apache.sshd.client.SshClient;
  31. import org.apache.sshd.client.auth.UserAuthFactory;
  32. import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory;
  33. import org.apache.sshd.client.config.hosts.HostConfigEntryResolver;
  34. import org.apache.sshd.common.NamedFactory;
  35. import org.apache.sshd.common.SshException;
  36. import org.apache.sshd.common.compression.BuiltinCompressions;
  37. import org.apache.sshd.common.config.keys.FilePasswordProvider;
  38. import org.apache.sshd.common.config.keys.loader.openssh.kdf.BCryptKdfOptions;
  39. import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
  40. import org.apache.sshd.common.signature.BuiltinSignatures;
  41. import org.apache.sshd.common.signature.Signature;
  42. import org.eclipse.jgit.annotations.NonNull;
  43. import org.eclipse.jgit.errors.TransportException;
  44. import org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile;
  45. import org.eclipse.jgit.internal.transport.sshd.AuthenticationCanceledException;
  46. import org.eclipse.jgit.internal.transport.sshd.CachingKeyPairProvider;
  47. import org.eclipse.jgit.internal.transport.sshd.GssApiWithMicAuthFactory;
  48. import org.eclipse.jgit.internal.transport.sshd.JGitKexExtensionHandler;
  49. import org.eclipse.jgit.internal.transport.sshd.JGitPasswordAuthFactory;
  50. import org.eclipse.jgit.internal.transport.sshd.JGitPublicKeyAuthFactory;
  51. import org.eclipse.jgit.internal.transport.sshd.JGitServerKeyVerifier;
  52. import org.eclipse.jgit.internal.transport.sshd.JGitSshClient;
  53. import org.eclipse.jgit.internal.transport.sshd.JGitSshConfig;
  54. import org.eclipse.jgit.internal.transport.sshd.JGitUserInteraction;
  55. import org.eclipse.jgit.internal.transport.sshd.OpenSshServerKeyDatabase;
  56. import org.eclipse.jgit.internal.transport.sshd.PasswordProviderWrapper;
  57. import org.eclipse.jgit.internal.transport.sshd.SshdText;
  58. import org.eclipse.jgit.transport.CredentialsProvider;
  59. import org.eclipse.jgit.transport.SshConfigStore;
  60. import org.eclipse.jgit.transport.SshConstants;
  61. import org.eclipse.jgit.transport.SshSessionFactory;
  62. import org.eclipse.jgit.transport.URIish;
  63. import org.eclipse.jgit.util.FS;
  64. /**
  65. * A {@link SshSessionFactory} that uses Apache MINA sshd. Classes from Apache
  66. * MINA sshd are kept private to avoid API evolution problems when Apache MINA
  67. * sshd interfaces change.
  68. *
  69. * @since 5.2
  70. */
  71. public class SshdSessionFactory extends SshSessionFactory implements Closeable {
  72. private static final String MINA_SSHD = "mina-sshd"; //$NON-NLS-1$
  73. private final AtomicBoolean closing = new AtomicBoolean();
  74. private final Set<SshdSession> sessions = new HashSet<>();
  75. private final Map<Tuple, HostConfigEntryResolver> defaultHostConfigEntryResolver = new ConcurrentHashMap<>();
  76. private final Map<Tuple, ServerKeyDatabase> defaultServerKeyDatabase = new ConcurrentHashMap<>();
  77. private final Map<Tuple, Iterable<KeyPair>> defaultKeys = new ConcurrentHashMap<>();
  78. private final KeyCache keyCache;
  79. private final ProxyDataFactory proxies;
  80. private File sshDirectory;
  81. private File homeDirectory;
  82. /**
  83. * Creates a new {@link SshdSessionFactory} without key cache and a
  84. * {@link DefaultProxyDataFactory}.
  85. */
  86. public SshdSessionFactory() {
  87. this(null, new DefaultProxyDataFactory());
  88. }
  89. /**
  90. * Creates a new {@link SshdSessionFactory} using the given {@link KeyCache}
  91. * and {@link ProxyDataFactory}. The {@code keyCache} is used for all sessions
  92. * created through this session factory; cached keys are destroyed when the
  93. * session factory is {@link #close() closed}.
  94. * <p>
  95. * Caching ssh keys in memory for an extended period of time is generally
  96. * considered bad practice, but there may be circumstances where using a
  97. * {@link KeyCache} is still the right choice, for instance to avoid that a
  98. * user gets prompted several times for the same password for the same key.
  99. * In general, however, it is preferable <em>not</em> to use a key cache but
  100. * to use a {@link #createKeyPasswordProvider(CredentialsProvider)
  101. * KeyPasswordProvider} that has access to some secure storage and can save
  102. * and retrieve passwords from there without user interaction. Another
  103. * approach is to use an ssh agent.
  104. * </p>
  105. * <p>
  106. * Note that the underlying ssh library (Apache MINA sshd) may or may not
  107. * keep ssh keys in memory for unspecified periods of time irrespective of
  108. * the use of a {@link KeyCache}.
  109. * </p>
  110. *
  111. * @param keyCache
  112. * {@link KeyCache} to use for caching ssh keys, or {@code null}
  113. * to not use a key cache
  114. * @param proxies
  115. * {@link ProxyDataFactory} to use, or {@code null} to not use a
  116. * proxy database (in which case connections through proxies will
  117. * not be possible)
  118. */
  119. public SshdSessionFactory(KeyCache keyCache, ProxyDataFactory proxies) {
  120. super();
  121. this.keyCache = keyCache;
  122. this.proxies = proxies;
  123. // sshd limits the number of BCrypt KDF rounds to 255 by default.
  124. // Decrypting such a key takes about two seconds on my machine.
  125. // I consider this limit too low. The time increases linearly with the
  126. // number of rounds.
  127. BCryptKdfOptions.setMaxAllowedRounds(16384);
  128. }
  129. @Override
  130. public String getType() {
  131. return MINA_SSHD;
  132. }
  133. /** A simple general map key. */
  134. private static final class Tuple {
  135. private Object[] objects;
  136. public Tuple(Object[] objects) {
  137. this.objects = objects;
  138. }
  139. @Override
  140. public boolean equals(Object obj) {
  141. if (obj == this) {
  142. return true;
  143. }
  144. if (obj != null && obj.getClass() == Tuple.class) {
  145. Tuple other = (Tuple) obj;
  146. return Arrays.equals(objects, other.objects);
  147. }
  148. return false;
  149. }
  150. @Override
  151. public int hashCode() {
  152. return Arrays.hashCode(objects);
  153. }
  154. }
  155. // We can't really use a single client. Clients need to be stopped
  156. // properly, and we don't really know when to do that. Instead we use
  157. // a dedicated SshClient instance per session. We need a bit of caching to
  158. // avoid re-loading the ssh config and keys repeatedly.
  159. @Override
  160. public SshdSession getSession(URIish uri,
  161. CredentialsProvider credentialsProvider, FS fs, int tms)
  162. throws TransportException {
  163. SshdSession session = null;
  164. try {
  165. session = new SshdSession(uri, () -> {
  166. File home = getHomeDirectory();
  167. if (home == null) {
  168. // Always use the detected filesystem for the user home!
  169. // It makes no sense to have different "user home"
  170. // directories depending on what file system a repository
  171. // is.
  172. home = FS.DETECTED.userHome();
  173. }
  174. File sshDir = getSshDirectory();
  175. if (sshDir == null) {
  176. sshDir = new File(home, SshConstants.SSH_DIR);
  177. }
  178. HostConfigEntryResolver configFile = getHostConfigEntryResolver(
  179. home, sshDir);
  180. KeyIdentityProvider defaultKeysProvider = toKeyIdentityProvider(
  181. getDefaultKeys(sshDir));
  182. SshClient client = ClientBuilder.builder()
  183. .factory(JGitSshClient::new)
  184. .filePasswordProvider(createFilePasswordProvider(
  185. () -> createKeyPasswordProvider(
  186. credentialsProvider)))
  187. .hostConfigEntryResolver(configFile)
  188. .serverKeyVerifier(new JGitServerKeyVerifier(
  189. getServerKeyDatabase(home, sshDir)))
  190. .signatureFactories(getSignatureFactories())
  191. .compressionFactories(
  192. new ArrayList<>(BuiltinCompressions.VALUES))
  193. .build();
  194. client.setUserInteraction(
  195. new JGitUserInteraction(credentialsProvider));
  196. client.setUserAuthFactories(getUserAuthFactories());
  197. client.setKeyIdentityProvider(defaultKeysProvider);
  198. client.setKexExtensionHandler(JGitKexExtensionHandler.INSTANCE);
  199. // JGit-specific things:
  200. JGitSshClient jgitClient = (JGitSshClient) client;
  201. jgitClient.setKeyCache(getKeyCache());
  202. jgitClient.setCredentialsProvider(credentialsProvider);
  203. jgitClient.setProxyDatabase(proxies);
  204. String defaultAuths = getDefaultPreferredAuthentications();
  205. if (defaultAuths != null) {
  206. jgitClient.setAttribute(
  207. JGitSshClient.PREFERRED_AUTHENTICATIONS,
  208. defaultAuths);
  209. }
  210. // Other things?
  211. return client;
  212. });
  213. session.addCloseListener(s -> unregister(s));
  214. register(session);
  215. session.connect(Duration.ofMillis(tms));
  216. return session;
  217. } catch (Exception e) {
  218. unregister(session);
  219. if (e instanceof TransportException) {
  220. throw (TransportException) e;
  221. }
  222. Throwable cause = e;
  223. if (e instanceof SshException && e
  224. .getCause() instanceof AuthenticationCanceledException) {
  225. // Results in a nicer error message
  226. cause = e.getCause();
  227. }
  228. throw new TransportException(uri, cause.getMessage(), cause);
  229. }
  230. }
  231. @Override
  232. public void close() {
  233. closing.set(true);
  234. boolean cleanKeys = false;
  235. synchronized (this) {
  236. cleanKeys = sessions.isEmpty();
  237. }
  238. if (cleanKeys) {
  239. KeyCache cache = getKeyCache();
  240. if (cache != null) {
  241. cache.close();
  242. }
  243. }
  244. }
  245. private void register(SshdSession newSession) throws IOException {
  246. if (newSession == null) {
  247. return;
  248. }
  249. if (closing.get()) {
  250. throw new IOException(SshdText.get().sshClosingDown);
  251. }
  252. synchronized (this) {
  253. sessions.add(newSession);
  254. }
  255. }
  256. private void unregister(SshdSession oldSession) {
  257. boolean cleanKeys = false;
  258. synchronized (this) {
  259. sessions.remove(oldSession);
  260. cleanKeys = closing.get() && sessions.isEmpty();
  261. }
  262. if (cleanKeys) {
  263. KeyCache cache = getKeyCache();
  264. if (cache != null) {
  265. cache.close();
  266. }
  267. }
  268. }
  269. /**
  270. * Set a global directory to use as the user's home directory
  271. *
  272. * @param homeDir
  273. * to use
  274. */
  275. public void setHomeDirectory(@NonNull File homeDir) {
  276. if (homeDir.isAbsolute()) {
  277. homeDirectory = homeDir;
  278. } else {
  279. homeDirectory = homeDir.getAbsoluteFile();
  280. }
  281. }
  282. /**
  283. * Retrieves the global user home directory
  284. *
  285. * @return the directory, or {@code null} if not set
  286. */
  287. public File getHomeDirectory() {
  288. return homeDirectory;
  289. }
  290. /**
  291. * Set a global directory to use as the .ssh directory
  292. *
  293. * @param sshDir
  294. * to use
  295. */
  296. public void setSshDirectory(@NonNull File sshDir) {
  297. if (sshDir.isAbsolute()) {
  298. sshDirectory = sshDir;
  299. } else {
  300. sshDirectory = sshDir.getAbsoluteFile();
  301. }
  302. }
  303. /**
  304. * Retrieves the global .ssh directory
  305. *
  306. * @return the directory, or {@code null} if not set
  307. */
  308. public File getSshDirectory() {
  309. return sshDirectory;
  310. }
  311. /**
  312. * Obtain a {@link HostConfigEntryResolver} to read the ssh config file and
  313. * to determine host entries for connections.
  314. *
  315. * @param homeDir
  316. * home directory to use for ~ replacement
  317. * @param sshDir
  318. * to use for looking for the config file
  319. * @return the resolver
  320. */
  321. @NonNull
  322. private HostConfigEntryResolver getHostConfigEntryResolver(
  323. @NonNull File homeDir, @NonNull File sshDir) {
  324. return defaultHostConfigEntryResolver.computeIfAbsent(
  325. new Tuple(new Object[] { homeDir, sshDir }),
  326. t -> new JGitSshConfig(createSshConfigStore(homeDir,
  327. getSshConfig(sshDir), getLocalUserName())));
  328. }
  329. /**
  330. * Determines the ssh config file. The default implementation returns
  331. * ~/.ssh/config. If the file does not exist and is created later it will be
  332. * picked up. To not use a config file at all, return {@code null}.
  333. *
  334. * @param sshDir
  335. * representing ~/.ssh/
  336. * @return the file (need not exist), or {@code null} if no config file
  337. * shall be used
  338. * @since 5.5
  339. */
  340. protected File getSshConfig(@NonNull File sshDir) {
  341. return new File(sshDir, SshConstants.CONFIG);
  342. }
  343. /**
  344. * Obtains a {@link SshConfigStore}, or {@code null} if not SSH config is to
  345. * be used. The default implementation returns {@code null} if
  346. * {@code configFile == null} and otherwise an OpenSSH-compatible store
  347. * reading host entries from the given file.
  348. *
  349. * @param homeDir
  350. * may be used for ~-replacements by the returned config store
  351. * @param configFile
  352. * to use, or {@code null} if none
  353. * @param localUserName
  354. * user name of the current user on the local OS
  355. * @return A {@link SshConfigStore}, or {@code null} if none is to be used
  356. *
  357. * @since 5.8
  358. */
  359. protected SshConfigStore createSshConfigStore(@NonNull File homeDir,
  360. File configFile, String localUserName) {
  361. return configFile == null ? null
  362. : new OpenSshConfigFile(homeDir, configFile, localUserName);
  363. }
  364. /**
  365. * Obtains a {@link ServerKeyDatabase} to verify server host keys. The
  366. * default implementation returns a {@link ServerKeyDatabase} that
  367. * recognizes the two openssh standard files {@code ~/.ssh/known_hosts} and
  368. * {@code ~/.ssh/known_hosts2} as well as any files configured via the
  369. * {@code UserKnownHostsFile} option in the ssh config file.
  370. *
  371. * @param homeDir
  372. * home directory to use for ~ replacement
  373. * @param sshDir
  374. * representing ~/.ssh/
  375. * @return the {@link ServerKeyDatabase}
  376. * @since 5.5
  377. */
  378. @NonNull
  379. protected ServerKeyDatabase getServerKeyDatabase(@NonNull File homeDir,
  380. @NonNull File sshDir) {
  381. return defaultServerKeyDatabase.computeIfAbsent(
  382. new Tuple(new Object[] { homeDir, sshDir }),
  383. t -> createServerKeyDatabase(homeDir, sshDir));
  384. }
  385. /**
  386. * Creates a {@link ServerKeyDatabase} to verify server host keys. The
  387. * default implementation returns a {@link ServerKeyDatabase} that
  388. * recognizes the two openssh standard files {@code ~/.ssh/known_hosts} and
  389. * {@code ~/.ssh/known_hosts2} as well as any files configured via the
  390. * {@code UserKnownHostsFile} option in the ssh config file.
  391. *
  392. * @param homeDir
  393. * home directory to use for ~ replacement
  394. * @param sshDir
  395. * representing ~/.ssh/
  396. * @return the {@link ServerKeyDatabase}
  397. * @since 5.8
  398. */
  399. @NonNull
  400. protected ServerKeyDatabase createServerKeyDatabase(@NonNull File homeDir,
  401. @NonNull File sshDir) {
  402. return new OpenSshServerKeyDatabase(true,
  403. getDefaultKnownHostsFiles(sshDir));
  404. }
  405. /**
  406. * Gets the list of default user known hosts files. The default returns
  407. * ~/.ssh/known_hosts and ~/.ssh/known_hosts2. The ssh config
  408. * {@code UserKnownHostsFile} overrides this default.
  409. *
  410. * @param sshDir
  411. * @return the possibly empty list of default known host file paths.
  412. */
  413. @NonNull
  414. protected List<Path> getDefaultKnownHostsFiles(@NonNull File sshDir) {
  415. return Arrays.asList(sshDir.toPath().resolve(SshConstants.KNOWN_HOSTS),
  416. sshDir.toPath().resolve(SshConstants.KNOWN_HOSTS + '2'));
  417. }
  418. /**
  419. * Determines the default keys. The default implementation will lazy load
  420. * the {@link #getDefaultIdentities(File) default identity files}.
  421. * <p>
  422. * Subclasses may override and return an {@link Iterable} of whatever keys
  423. * are appropriate. If the returned iterable lazily loads keys, it should be
  424. * an instance of
  425. * {@link org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider
  426. * AbstractResourceKeyPairProvider} so that the session can later pass it
  427. * the {@link #createKeyPasswordProvider(CredentialsProvider) password
  428. * provider} wrapped as a {@link FilePasswordProvider} via
  429. * {@link org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider#setPasswordFinder(FilePasswordProvider)
  430. * AbstractResourceKeyPairProvider#setPasswordFinder(FilePasswordProvider)}
  431. * so that encrypted, password-protected keys can be loaded.
  432. * </p>
  433. * <p>
  434. * The default implementation uses exactly this mechanism; class
  435. * {@link CachingKeyPairProvider} may serve as a model for a customized
  436. * lazy-loading {@link Iterable} implementation
  437. * </p>
  438. * <p>
  439. * If the {@link Iterable} returned has the keys already pre-loaded or
  440. * otherwise doesn't need to decrypt encrypted keys, it can be any
  441. * {@link Iterable}, for instance a simple {@link java.util.List List}.
  442. * </p>
  443. *
  444. * @param sshDir
  445. * to look in for keys
  446. * @return an {@link Iterable} over the default keys
  447. * @since 5.3
  448. */
  449. @NonNull
  450. protected Iterable<KeyPair> getDefaultKeys(@NonNull File sshDir) {
  451. List<Path> defaultIdentities = getDefaultIdentities(sshDir);
  452. return defaultKeys.computeIfAbsent(
  453. new Tuple(defaultIdentities.toArray(new Path[0])),
  454. t -> new CachingKeyPairProvider(defaultIdentities,
  455. getKeyCache()));
  456. }
  457. /**
  458. * Converts an {@link Iterable} of {link KeyPair}s into a
  459. * {@link KeyIdentityProvider}.
  460. *
  461. * @param keys
  462. * to provide via the returned {@link KeyIdentityProvider}
  463. * @return a {@link KeyIdentityProvider} that provides the given
  464. * {@code keys}
  465. */
  466. private KeyIdentityProvider toKeyIdentityProvider(Iterable<KeyPair> keys) {
  467. if (keys instanceof KeyIdentityProvider) {
  468. return (KeyIdentityProvider) keys;
  469. }
  470. return (session) -> keys;
  471. }
  472. /**
  473. * Gets a list of default identities, i.e., private key files that shall
  474. * always be tried for public key authentication. Typically those are
  475. * ~/.ssh/id_dsa, ~/.ssh/id_rsa, and so on. The default implementation
  476. * returns the files defined in {@link SshConstants#DEFAULT_IDENTITIES}.
  477. *
  478. * @param sshDir
  479. * the directory that represents ~/.ssh/
  480. * @return a possibly empty list of paths containing default identities
  481. * (private keys)
  482. */
  483. @NonNull
  484. protected List<Path> getDefaultIdentities(@NonNull File sshDir) {
  485. return Arrays
  486. .asList(SshConstants.DEFAULT_IDENTITIES).stream()
  487. .map(s -> new File(sshDir, s).toPath()).filter(Files::exists)
  488. .collect(Collectors.toList());
  489. }
  490. /**
  491. * Obtains the {@link KeyCache} to use to cache loaded keys.
  492. *
  493. * @return the {@link KeyCache}, or {@code null} if none.
  494. */
  495. protected final KeyCache getKeyCache() {
  496. return keyCache;
  497. }
  498. /**
  499. * Creates a {@link KeyPasswordProvider} for a new session.
  500. *
  501. * @param provider
  502. * the {@link CredentialsProvider} to delegate to for user
  503. * interactions
  504. * @return a new {@link KeyPasswordProvider}
  505. */
  506. @NonNull
  507. protected KeyPasswordProvider createKeyPasswordProvider(
  508. CredentialsProvider provider) {
  509. return new IdentityPasswordProvider(provider);
  510. }
  511. /**
  512. * Creates a {@link FilePasswordProvider} for a new session.
  513. *
  514. * @param providerFactory
  515. * providing the {@link KeyPasswordProvider} to delegate to
  516. * @return a new {@link FilePasswordProvider}
  517. */
  518. @NonNull
  519. private FilePasswordProvider createFilePasswordProvider(
  520. Supplier<KeyPasswordProvider> providerFactory) {
  521. return new PasswordProviderWrapper(providerFactory);
  522. }
  523. /**
  524. * Gets the user authentication mechanisms (or rather, factories for them).
  525. * By default this returns gssapi-with-mic, public-key, password, and
  526. * keyboard-interactive, in that order. The order is only significant if the
  527. * ssh config does <em>not</em> set {@code PreferredAuthentications}; if it
  528. * is set, the order defined there will be taken.
  529. *
  530. * @return the non-empty list of factories.
  531. */
  532. @NonNull
  533. private List<UserAuthFactory> getUserAuthFactories() {
  534. // About the order of password and keyboard-interactive, see upstream
  535. // bug https://issues.apache.org/jira/projects/SSHD/issues/SSHD-866 .
  536. // Password auth doesn't have this problem.
  537. return Collections.unmodifiableList(
  538. Arrays.asList(GssApiWithMicAuthFactory.INSTANCE,
  539. JGitPublicKeyAuthFactory.FACTORY,
  540. JGitPasswordAuthFactory.INSTANCE,
  541. UserAuthKeyboardInteractiveFactory.INSTANCE));
  542. }
  543. /**
  544. * Gets the list of default preferred authentication mechanisms. If
  545. * {@code null} is returned the openssh default list will be in effect. If
  546. * the ssh config defines {@code PreferredAuthentications} the value from
  547. * the ssh config takes precedence.
  548. *
  549. * @return a comma-separated list of mechanism names, or {@code null} if
  550. * none
  551. */
  552. protected String getDefaultPreferredAuthentications() {
  553. return null;
  554. }
  555. /**
  556. * Apache MINA sshd 2.6.0 has removed DSA, DSA_CERT and RSA_CERT. We have to
  557. * set it up explicitly to still allow users to connect with DSA keys.
  558. *
  559. * @return a list of supported signature factories
  560. */
  561. @SuppressWarnings("deprecation")
  562. private static List<NamedFactory<Signature>> getSignatureFactories() {
  563. // @formatter:off
  564. return Arrays.asList(
  565. BuiltinSignatures.nistp256_cert,
  566. BuiltinSignatures.nistp384_cert,
  567. BuiltinSignatures.nistp521_cert,
  568. BuiltinSignatures.ed25519_cert,
  569. BuiltinSignatures.rsaSHA512_cert,
  570. BuiltinSignatures.rsaSHA256_cert,
  571. BuiltinSignatures.rsa_cert,
  572. BuiltinSignatures.nistp256,
  573. BuiltinSignatures.nistp384,
  574. BuiltinSignatures.nistp521,
  575. BuiltinSignatures.ed25519,
  576. BuiltinSignatures.sk_ecdsa_sha2_nistp256,
  577. BuiltinSignatures.sk_ssh_ed25519,
  578. BuiltinSignatures.rsaSHA512,
  579. BuiltinSignatures.rsaSHA256,
  580. BuiltinSignatures.rsa,
  581. BuiltinSignatures.dsa_cert,
  582. BuiltinSignatures.dsa);
  583. // @formatter:on
  584. }
  585. }