[X2Go-Commits] python-x2go.git - brokerclient (branch) updated: fff4c5d721f7bb447a5da8f108730bdfc1627a91

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


The branch, brokerclient 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