1 /*
2 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2008, 2022 Shawn O. Pearce <spearce@spearce.org> and others
4 *
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Distribution License v. 1.0 which is available at
7 * https://www.eclipse.org/org/documents/edl-v10.php.
8 *
9 * SPDX-License-Identifier: BSD-3-Clause
10 */
11
12 package org.eclipse.jgit.transport;
13
14 import java.security.AccessController;
15 import java.security.PrivilegedAction;
16 import java.util.Iterator;
17 import java.util.ServiceLoader;
18
19 import org.eclipse.jgit.errors.TransportException;
20 import org.eclipse.jgit.lib.Constants;
21 import org.eclipse.jgit.util.FS;
22 import org.eclipse.jgit.util.SystemReader;
23
24 /**
25 * Creates and destroys SSH connections to a remote system.
26 * <p>
27 * Different implementations of the session factory may be used to control
28 * communicating with the end-user as well as reading their personal SSH
29 * configuration settings, such as known hosts and private keys.
30 * </p>
31 * <p>
32 * A {@link RemoteSession} must be returned to the factory that created it.
33 * Callers are encouraged to retain the SshSessionFactory for the duration of
34 * the period they are using the session.
35 * </p>
36 */
37 public abstract class SshSessionFactory {
38
39 private static class DefaultFactory {
40
41 private static volatile SshSessionFactory INSTANCE = loadSshSessionFactory();
42
43 private static SshSessionFactory loadSshSessionFactory() {
44 ServiceLoader<SshSessionFactory> loader = ServiceLoader
45 .load(SshSessionFactory.class);
46 Iterator<SshSessionFactory> iter = loader.iterator();
47 if (iter.hasNext()) {
48 return iter.next();
49 }
50 return null;
51 }
52
53 private DefaultFactory() {
54 // No instantiation
55 }
56
57 public static SshSessionFactory getInstance() {
58 return INSTANCE;
59 }
60
61 public static void setInstance(SshSessionFactory newFactory) {
62 if (newFactory != null) {
63 INSTANCE = newFactory;
64 } else {
65 INSTANCE = loadSshSessionFactory();
66 }
67 }
68 }
69
70 /**
71 * Gets the currently configured JVM-wide factory.
72 * <p>
73 * By default the factory will read from the user's {@code $HOME/.ssh} and
74 * assume OpenSSH compatibility.
75 * </p>
76 *
77 * @return factory the current factory for this JVM.
78 */
79 public static SshSessionFactory getInstance() {
80 return DefaultFactory.getInstance();
81 }
82
83 /**
84 * Changes the JVM-wide factory to a different implementation.
85 *
86 * @param newFactory
87 * factory for future sessions to be created through; if
88 * {@code null} the default factory will be restored.
89 */
90 public static void setInstance(SshSessionFactory newFactory) {
91 DefaultFactory.setInstance(newFactory);
92 }
93
94 /**
95 * Retrieves the local user name as defined by the system property
96 * "user.name".
97 *
98 * @return the user name
99 * @since 5.2
100 */
101 public static String getLocalUserName() {
102 return AccessController
103 .doPrivileged((PrivilegedAction<String>) () -> SystemReader
104 .getInstance().getProperty(Constants.OS_USER_NAME_KEY));
105 }
106
107 /**
108 * Opens (or reuses) a session to a host. The returned session is connected
109 * and authenticated and is ready for further use.
110 *
111 * @param uri
112 * URI of the remote host to connect to
113 * @param credentialsProvider
114 * provider to support authentication, may be {@code null} if no
115 * user input for authentication is needed
116 * @param fs
117 * the file system abstraction to use for certain file
118 * operations, such as reading configuration files
119 * @param tms
120 * connection timeout for creating the session, in milliseconds
121 * @return a connected and authenticated session for communicating with the
122 * remote host given by the {@code uri}
123 * @throws org.eclipse.jgit.errors.TransportException
124 * if the session could not be created
125 */
126 public abstract RemoteSession getSession(URIish uri,
127 CredentialsProvider credentialsProvider, FS fs, int tms)
128 throws TransportException;
129
130 /**
131 * The name of the type of session factory.
132 *
133 * @return the name of the type of session factory.
134 *
135 * @since 5.8
136 */
137 public abstract String getType();
138
139 /**
140 * Closes (or recycles) a session to a host.
141 *
142 * @param session
143 * a session previously obtained from this factory's
144 * {@link #getSession(URIish, CredentialsProvider, FS, int)}
145 * method.
146 */
147 public void releaseSession(RemoteSession session) {
148 session.disconnect();
149 }
150 }