Browse Source

Update SSHVendor, SubprocessSSHVendor and SSHGitClient for using password and key_filename ssh options

Filipp Frizzy 7 years ago
parent
commit
8395a4e84b
1 changed files with 52 additions and 11 deletions
  1. 52 11
      dulwich/client.py

+ 52 - 11
dulwich/client.py

@@ -1070,15 +1070,18 @@ default_local_git_client_cls = LocalGitClient
 class SSHVendor(object):
     """A client side SSH implementation."""
 
-    def connect_ssh(self, host, command, username=None, port=None):
+    def connect_ssh(self, host, command, username=None, port=None,
+                    password=None, key_filename=None):
         # This function was deprecated in 0.9.1
         import warnings
         warnings.warn(
             "SSHVendor.connect_ssh has been renamed to SSHVendor.run_command",
             DeprecationWarning)
-        return self.run_command(host, command, username=username, port=port)
+        return self.run_command(host, command, username=username, port=port,
+                                password=password, key_filename=key_filename)
 
-    def run_command(self, host, command, username=None, port=None):
+    def run_command(self, host, command, username=None, port=None,
+                    password=None, key_filename=None):
         """Connect to an SSH server.
 
         Run a command remotely and return a file-like object for interaction
@@ -1088,6 +1091,8 @@ class SSHVendor(object):
         :param command: Command to run (as argv array)
         :param username: Optional ame of user to log in as
         :param port: Optional SSH port to use
+        :param password: Optional ssh password for login
+        :param key_filename: Optional path to private keyfile
         """
         raise NotImplementedError(self.run_command)
 
@@ -1102,16 +1107,49 @@ class StrangeHostname(Exception):
 class SubprocessSSHVendor(SSHVendor):
     """SSH vendor that shells out to the local 'ssh' command."""
 
-    def run_command(self, host, command, username=None, port=None):
-        # FIXME: This has no way to deal with passwords..
-        args = ['ssh', '-x']
-        if port is not None:
-            args.extend(['-p', str(port)])
-        if username is not None:
+    def run_command(self, host, command, username=None, port=None,
+                    password=None, key_filename=None):
+        if password and key_filename:
+            raise NotImplementedError(
+                "You can't set passphrase for ssh key with SubprocessSSHVendor, " \
+                "use ParamikoSSHVendor instead"
+            )
+
+        if sys.platform == 'win32':
+            args = ['putty.exe', '-ssh']
+            if password:
+                args.extend(['-pw', str(password)])
+        else:
+            if password:
+                try:
+                    subprocess.call(["sshpass"])
+                except OSError as e:
+                    import warnings
+                    warnings.warn(
+                        "You need sshpass for using password option, " \
+                        "you can use ssh-add or private key without password " \
+                        "or ParamikoSSHVendor"
+                    )
+                    raise e
+                args = ['sshpass', '-p', str(password)]
+            else:
+                args = ['ssh', '-x']
+
+        if port:
+            if sys.platform == 'win32':
+                args.extend(['-P', str(port)])
+            else:
+                args.extend(['-p', str(port)])
+
+        if key_filename:
+            args.extend(['-i', str(key_filename)])
+
+        if username:
             host = '%s@%s' % (username, host)
         if host.startswith('-'):
             raise StrangeHostname(hostname=host)
         args.append(host)
+
         proc = subprocess.Popen(args + [command], bufsize=0,
                                 stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE)
@@ -1134,10 +1172,12 @@ get_ssh_vendor = SubprocessSSHVendor
 class SSHGitClient(TraditionalGitClient):
 
     def __init__(self, host, port=None, username=None, vendor=None,
-                 config=None, **kwargs):
+                 config=None, password=None, key_filename=None, **kwargs):
         self.host = host
         self.port = port
         self.username = username
+        self.password = password
+        self.key_filename = key_filename
         super(SSHGitClient, self).__init__(**kwargs)
         self.alternative_paths = {}
         if vendor is not None:
@@ -1175,7 +1215,8 @@ class SSHGitClient(TraditionalGitClient):
         argv = (self._get_cmd_path(cmd).decode(self._remote_path_encoding) +
                 " '" + path + "'")
         con = self.ssh_vendor.run_command(
-            self.host, argv, port=self.port, username=self.username)
+            self.host, argv, port=self.port, username=self.username,
+            password=self.password, key_filename=self.key_filename)
         return (Protocol(con.read, con.write, con.close,
                          report_activity=self._report_activity),
                 con.can_read)