View Javadoc
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 }