[X2Go-Commits] python-x2go.git - release/0.4.0.x (branch) updated: fff4c5d721f7bb447a5da8f108730bdfc1627a91

X2Go dev team git-admin at x2go.org
Tue Jan 7 16:16:08 CET 2014


The branch, release/0.4.0.x has been updated
       via  fff4c5d721f7bb447a5da8f108730bdfc1627a91 (commit)
      from  cb16e37cf3e96c52e5ab361945c8a9d1343e9df2 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
-----------------------------------------------------------------------

Summary of changes:
 x2go/backends/control/_stdout.py |   66 +++++++++++++++++++++++++++++++-------
 x2go/backends/proxy/base.py      |    1 -
 x2go/client.py                   |    9 +++++-
 x2go/forward.py                  |   44 ++++++++++++++++---------
 x2go/session.py                  |   22 ++++++++++---
 x2go/sshproxy.py                 |   51 +++++++++++++++++++++--------
 x2go/x2go_exceptions.py          |    4 ++-
 7 files changed, 149 insertions(+), 48 deletions(-)

The diff of changes is:
diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py
index fb18793..471b55e 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -223,8 +223,9 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
             self._session_auth_rsakey = paramiko.RSAKey.generate(defaults.RSAKEY_STRENGTH)
         return self._session_auth_rsakey
 
-    def connect(self, hostname, port=22, username=None, password=None, pkey=None,
-                key_filename=None, timeout=None, allow_agent=False, look_for_keys=True,
+    def connect(self, hostname, port=22, username='', password='', pkey=None,
+                sshproxy_user='', sshproxy_password='',
+                key_filename=None, timeout=None, allow_agent=False, look_for_keys=False,
                 add_to_known_hosts=False, force_password_auth=False):
         """\
         Connect to an X2go server and authenticate to it. This method is directly
@@ -288,11 +289,33 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
 
         """
         if self.use_sshproxy and self.sshproxy_params:
-            self.sshproxy_session = sshproxy.X2goSSHProxy(add_to_known_hosts=add_to_known_hosts, 
-                                                          known_hosts=self.known_hosts,
-                                                          logger=self.logger, **self.sshproxy_params
-                                                         )
-            self.sshproxy_session.start()
+            if sshproxy_user:
+                self.sshproxy_params['sshproxy_user'] = sshproxy_user
+            if sshproxy_password:
+                self.sshproxy_params['sshproxy_password'] = sshproxy_password
+
+            try:
+                self.sshproxy_session = sshproxy.X2goSSHProxy(add_to_known_hosts=add_to_known_hosts, 
+                                                              known_hosts=self.known_hosts,
+                                                              logger=self.logger, **self.sshproxy_params
+                                                             )
+                self.sshproxy_session.start()
+
+                # divert port to sshproxy_session's local forwarding port (it might have changed due to 
+                # SSH connection errors
+                port = self.sshproxy_session.get_local_proxy_port()
+
+                # forget sshproxy password immediately
+                try: del sshproxy_params['sshproxy_password']
+                except: KeyError
+
+            except x2go_exceptions.X2goSSHProxyAuthenticationException, e:
+                self.sshproxy_session = None
+                raise(e)
+
+            except x2go_exceptions.X2goSSHProxyException, e:
+                self.sshproxy_session = None
+                raise(e)
 
         if add_to_known_hosts:
             self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@@ -310,23 +333,42 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
                 paramiko.SSHClient.connect(self, hostname, port=port, username=username, pkey=pkey,
                                            key_filename=key_filename, timeout=timeout, allow_agent=allow_agent, 
                                            look_for_keys=look_for_keys)
+
             except paramiko.AuthenticationException, e:
                 if password:
                     self.logger('next auth mechanism we\'ll try is keyboard-interactive authentication', loglevel=log.loglevel_DEBUG)
-                    paramiko.SSHClient.connect(self, hostname, port=port, username=username, password=password,
-                                               timeout=timeout, allow_agent=allow_agent, 
-                                               look_for_keys=look_for_keys)
+                    try:
+                        paramiko.SSHClient.connect(self, hostname, port=port, username=username, password=password,
+                                                   timeout=timeout, allow_agent=allow_agent, 
+                                                   look_for_keys=look_for_keys)
+                    except paramiko.AuthenticationException, e:
+                        if self.sshproxy_session:
+                            self.sshproxy_session.stop_thread()
+                        self.close()
+                        raise(e)
                 else:
+                    if self.sshproxy_session:
+                        self.sshproxy_session.stop_thread()
+                    self.close()
                     raise(e)
 
         # if there is not private key, we will use the given password
         elif password:
             self.logger('performing SSH keyboard-interactive authentication with server', loglevel=log.loglevel_DEBUG)
-            paramiko.SSHClient.connect(self, hostname, port=port, username=username, password=password, 
-                                       timeout=timeout, allow_agent=allow_agent, look_for_keys=look_for_keys)
+            try:
+                paramiko.SSHClient.connect(self, hostname, port=port, username=username, password=password, 
+                                           timeout=timeout, allow_agent=allow_agent, look_for_keys=look_for_keys)
+            except paramiko.AuthenticationException, e:
+                if self.sshproxy_session:
+                    self.sshproxy_session.stop_thread()
+                self.close()
+                raise(e)
 
         # authentication failed
         else:
+            if self.sshproxy_session:
+                self.sshproxy_session.stop_thread()
+            self.close()
             raise paramiko.AuthenticationException()
 
         self.hostname = hostname
diff --git a/x2go/backends/proxy/base.py b/x2go/backends/proxy/base.py
index c1b597b..6173571 100644
--- a/x2go/backends/proxy/base.py
+++ b/x2go/backends/proxy/base.py
@@ -163,7 +163,6 @@ class X2goProxyBASE(threading.Thread):
             if self.fw_tunnel is None:
                 self.logger('socket [localhost]:%s is in use, trying local TCP/IP socket port: [localhost]:%s' % (local_graphics_port, local_graphics_port+1), loglevel=log.loglevel_INFO)
                 local_graphics_port += 1
-                gevent.sleep(.1)
 
         # update the proxy port in PROXY_ARGS
         self._update_local_proxy_socket(local_graphics_port)
diff --git a/x2go/client.py b/x2go/client.py
index a959342..ef3e1e5 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -636,7 +636,13 @@ class X2goClient(object):
         """
         return self.session_registry(session_uuid).set_username(username=username)
 
-    def connect_session(self, session_uuid, username=None, password=None, add_to_known_hosts=None, force_password_auth=None):
+    def connect_session(self, session_uuid,
+                        username='',
+                        password='',
+                        sshproxy_user='',
+                        sshproxy_password='',
+                        add_to_known_hosts=None,
+                        force_password_auth=None):
         """\
         Connect to a registered X2go session with registry hash C{<session_uuid>}. 
         This method basically wraps around paramiko.SSHClient.connect() for the 
@@ -660,6 +666,7 @@ class X2goClient(object):
 
         """
         return self.session_registry(session_uuid).connect(username=username, password=password,
+                                                           sshproxy_user=sshproxy_user, sshproxy_password=sshproxy_password,
                                                            add_to_known_hosts=add_to_known_hosts,
                                                            force_password_auth=force_password_auth,
                                                           )
diff --git a/x2go/forward.py b/x2go/forward.py
index a291924..4be7e37 100644
--- a/x2go/forward.py
+++ b/x2go/forward.py
@@ -21,7 +21,7 @@
 Python Gevent based X2go port forwarding server (openssh -L option) for the X2go proxy.
 
 """
-__NAME__ = "x2goproxytunnel-pylib"
+__NAME__ = "x2gofwtunnel-pylib"
 
 # modules
 import os, sys, copy
@@ -66,6 +66,9 @@ class X2goFwServer(StreamServer):
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
+        self.chan = None
+        self.is_active = False
+        self.keepalive = False
         self.chain_host = remote_host
         self.chain_port = remote_port
         self.ssh_transport = ssh_transport
@@ -83,17 +86,17 @@ class X2goFwServer(StreamServer):
 
         """
         try:
-            chan = self.ssh_transport.open_channel('direct-tcpip',
-                                                   (self.chain_host, self.chain_port),
-                                                   fw_socket.getpeername())
-            chan_peername = chan.getpeername()
+            self.chan = self.ssh_transport.open_channel('direct-tcpip',
+                                                        (self.chain_host, self.chain_port),
+                                                        fw_socket.getpeername())
+            chan_peername = self.chan.getpeername()
         except Exception, e:
             self.logger('incoming request to %s:%d failed: %s' % (self.chain_host,
                                                                   self.chain_port,
                                                                   repr(e)), loglevel=log.loglevel_ERROR)
             raise x2go_exceptions.X2goFwTunnelException('proxy tunnel setup failed')
 
-        if chan is None:
+        if self.chan is None:
             self.logger('incoming request to %s:%d was rejected by the SSH server.' %
                         (self.chain_host, self.chain_port), loglevel=log.loglevel_ERROR)
             return
@@ -101,29 +104,37 @@ class X2goFwServer(StreamServer):
                                                                 chan_peername, (self.chain_host, self.chain_port)),
                                                                 loglevel=log.loglevel_INFO)
         try:
-            while True:
-                r, w, x = select.select([fw_socket, chan], [], [])
+            self.is_active = True
+            self.keepalive = True
+            while self.keepalive:
+                r, w, x = select.select([fw_socket, self.chan], [], [])
                 if fw_socket in r:
                     data = fw_socket.recv(1024)
                     if len(data) == 0:
                         break
-                    chan.send(data)
-                if chan in r:
-                    data = chan.recv(1024)
+                    self.chan.send(data)
+                if self.chan in r:
+                    data = self.chan.recv(1024)
                     if len(data) == 0:
                         break
                     fw_socket.send(data)
-            chan.close()
+            self.chan.close()
             fw_socket.close()
         except socket.error:
             pass
 
+        self.is_active = False
         self.logger('Tunnel closed from %r' % (chan_peername,),
                     loglevel=log.loglevel_INFO)
 
+    def close_channel(self):
 
-def start_forward_tunnel(local_host='localhost', local_port=22022, 
-                         remote_host='localhost', remote_port=22, 
+        if self.chan is not None:
+            self.chan.close()
+
+
+def start_forward_tunnel(local_host='localhost', local_port=22022,
+                         remote_host='localhost', remote_port=22,
                          ssh_transport=None, logger=None, ):
     """\
     Setup up a Paramiko/SSH port forwarding tunnel (like openssh -L option).
@@ -160,7 +171,10 @@ def stop_forward_tunnel(fw_server):
     @type fw_server: C{instance}
 
     """
-    fw_server.stop()
+    if fw_server is not None:
+        fw_server.keepalive = False
+        fw_server.close_channel()
+        fw_server.stop()
 
 if __name__ == '__main__':
     pass
diff --git a/x2go/session.py b/x2go/session.py
index 386a5db..8967ef4 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -158,8 +158,8 @@ class X2goSession(object):
         for p in self.terminal_params:
             self.logger('    %s: %s' % (p,self.terminal_params[p]), log.loglevel_DEBUG)
 
-        self.logger('starting X2goSession', loglevel=log.loglevel_DEBUG)
         if control_session is None:
+            self.logger('initializing X2goControlSession', loglevel=log.loglevel_DEBUG)
             self.control_session = control_backend(profile_name=self.profile_name,
                                                    known_hosts=known_hosts,
                                                    terminal_backend=terminal_backend,
@@ -176,7 +176,6 @@ class X2goSession(object):
             self.control_session = control_session
 
         self.terminal_session = None
-        self.logger('starting X2goSession', loglevel=log.loglevel_DEBUG)
 
     def __str__(self):
         return self.__get_uuid()
@@ -377,7 +376,8 @@ class X2goSession(object):
         return self.terminal_session is not None
     __has_terminal_session = has_terminal_session
 
-    def connect(self, username='', password='', add_to_known_hosts=None, force_password_auth=None):
+    def connect(self, username='', password='', add_to_known_hosts=None, force_password_auth=None,
+                sshproxy_user='', sshproxy_password=''):
         """\
         Connect to a registered X2go session with registry hash C{<session_uuid>}.
         This method basically wraps around paramiko.SSHClient.connect() for the
@@ -408,11 +408,25 @@ class X2goSession(object):
                 self.control_params['add_to_known_hosts'] = add_to_known_hosts
             if force_password_auth is not None:
                 self.control_params['force_password_auth'] = force_password_auth
+            if sshproxy_user:
+                self.control_params['sshproxy_password'] = sshproxy_password
+            if sshproxy_user:
+                self.control_params['sshproxy_user'] = sshproxy_user
             self.control_params['password'] = password
-            print self.control_params
             self.connected = self.control_session.connect(self.server,
                                                           **self.control_params
                                                          )
+            # remove credentials immediately
+            self.control_params['password'] = ''
+            try: del self.control_params['sshproxy_user']
+            except KeyError: pass
+            try: del self.control_params['sshproxy_password']
+            except KeyError: pass
+
+            if not self.connected:
+                # then tidy up...
+                self.disconnect()
+
         return self.connected
     __connect = connect
 
diff --git a/x2go/sshproxy.py b/x2go/sshproxy.py
index c775476..2bbcc55 100644
--- a/x2go/sshproxy.py
+++ b/x2go/sshproxy.py
@@ -33,6 +33,7 @@ import threading
 # Python X2go modules
 import x2go.forward as forward
 import x2go.log as log
+from x2go.x2go_exceptions import *
 
 from x2go.defaults import CURRENT_LOCAL_USER as _CURRENT_LOCAL_USER
 from x2go.defaults import LOCAL_HOME as _LOCAL_HOME
@@ -71,14 +72,16 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
             self.logger = copy.deepcopy(logger)
         self.logger.tag = __NAME__
 
+        self.hostname, self.port, self.username = hostname, port, username
+
         # translate between X2goSession options and paramiko.SSHCLient.connect() options
         if sshproxy_host: 
             if sshproxy_host.find(':'):
-                hostname = sshproxy_host.split(':')[0]
-                port = int(sshproxy_host.split(':')[1])
+                self.hostname = sshproxy_host.split(':')[0]
+                self.port = int(sshproxy_host.split(':')[1])
             else:
-                hostname = sshproxy_host
-        if sshproxy_user: username = sshproxy_user
+                self.hostname = sshproxy_host
+        if sshproxy_user: self.username = sshproxy_user
         if sshproxy_password: password = sshproxy_password
         if sshproxy_key_filename: key_filename = sshproxy_key_filename
         if sshproxy_tunnel:
@@ -105,21 +108,33 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
         if add_to_known_hosts:
             self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
 
-        self.connect(hostname, port=port, 
-                     username=username, 
-                     password=password, 
-                     key_filename=key_filename,
-                    )
-
-        self.hostname, self.port, self.username = hostname, port, username
+        if key_filename:
+            try:
+                self.connect(self.hostname, port=self.port, 
+                             username=self.username, 
+                             key_filename=key_filename,
+                             look_for_keys=False,
+                            )
+            except AuthenticationException, e:
+                raise X2goSSHProxyAuthenticationException('pubkey auth mechanisms both failed')
+
+        elif password:
+            try:
+                self.connect(self.hostname, port=self.port,
+                             username=self.username,
+                             password=password,
+                             look_for_keys=False,
+                            )
+            except AuthenticationException:
+                    raise X2goSSHProxyAuthenticationException('interactive auth mechanisms failed')
+        else:
+            raise X2goSSHProxyAuthenticationException('no auth mechanism available')
 
         threading.Thread.__init__(self)
         self.daemon = True
 
-
     def run(self):
 
-        self.fw_tunnel = None
         while self.fw_tunnel is None:
             self.fw_tunnel = forward.start_forward_tunnel(local_host=self.local_host, 
                                                           local_port=self.local_port, 
@@ -127,10 +142,10 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
                                                           remote_port=self.remote_port, 
                                                           ssh_transport=self.get_transport(), 
                                                           logger=self.logger, )
+
             if self.fw_tunnel is None:
                 self.logger('socket [%s]:%s is in use, trying local TCP/IP socket port: [%s]:%s' % (self.local_host, self.local_port, self.local_host, self.local_port+1), loglevel=log.loglevel_INFO)
                 self.local_port += 1
-                #gevent.sleep(.1)
 
         self.logger('SSH proxy tunnel via [%s]:%s has been set up' % (self.hostname, self.port), loglevel=log.loglevel_NOTICE)
         self.logger('SSH proxy tunnel startpoint is [%s]:%s, endpoint is [%s]:%s' % (self.local_host, self.local_port, self.remote_host, self.remote_port), loglevel=log.loglevel_NOTICE)
@@ -138,9 +153,17 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
         while self._keepalive:
             gevent.sleep(.1)
 
+    def get_local_proxy_port(self):
+        return self.local_port
+
     def stop_thread(self):
+        if self.fw_tunnel is not None and self.fw_tunnel.is_active:
+            self.logger('taking down SSH proxy tunnel via [%s]:%s' % (self.hostname, self.port), loglevel=log.loglevel_NOTICE)
         forward.stop_forward_tunnel(self.fw_tunnel)
+        self.fw_tunnel = None
         self._keepalive = False
+        if self.get_transport() is not None:
+            self.logger('closing SSH proxy connection to [%s]:%s' % (self.hostname, self.port), loglevel=log.loglevel_NOTICE)
         self.close()
 
     def __del__(self):
diff --git a/x2go/x2go_exceptions.py b/x2go/x2go_exceptions.py
index e969875..9fa8dbd 100644
--- a/x2go/x2go_exceptions.py
+++ b/x2go/x2go_exceptions.py
@@ -51,4 +51,6 @@ class X2goFwTunnelException(_X2goException): pass
 class X2goRevFwTunnelException(_X2goException): pass
 class X2goPrintException(_X2goException): pass
 class X2goPrintQueueException(_X2goException): pass
-class X2goPrintActionException(_X2goException): pass
\ No newline at end of file
+class X2goPrintActionException(_X2goException): pass
+class X2goSSHProxyException(_X2goException): pass
+class X2goSSHProxyAuthenticationException(_X2goException): pass


hooks/post-receive
-- 
python-x2go.git (Python X2Go Client API)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-x2go.git" (Python X2Go Client API).




More information about the x2go-commits mailing list