[X2Go-Commits] python-x2go.git - build-baikal (branch) updated: 0.0.37.0-48-g2be37b5
X2Go dev team
git-admin at x2go.org
Wed Jan 8 15:28:06 CET 2014
The branch, build-baikal has been updated
via 2be37b5636f7867e4e692d9337bd986ba8a1393e (commit)
from 88a3386e5db21c608da8dd382c268912ecc57b37 (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 | 68 ++++++++++++++++----------------------
x2go/checkhosts.py | 68 ++++++++++++++++++++++++++++++++++++--
x2go/registry.py | 15 +++++----
x2go/session.py | 5 ++-
x2go/sshproxy.py | 30 ++++++++++++++---
x2go/x2go_exceptions.py | 2 ++
6 files changed, 134 insertions(+), 54 deletions(-)
The diff of changes is:
diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py
index a07c3f5..7490809 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -34,6 +34,9 @@ import gevent
import copy
import binascii
+import string
+import random
+
# Python X2go modules
import x2go.sshproxy as sshproxy
import x2go.log as log
@@ -238,41 +241,16 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
def check_host(self, hostname, port=22):
"""\
- Perform a Paramiko/SSH host key check.
+ Wraps around a Paramiko/SSH host key check.
"""
- _hostname = hostname
- _port = port
- _fingerprint = 'NO-FINGERPRINT'
- _fingerprint_type = 'SOME-KEY-TYPE'
-
- _check_policy = checkhosts.X2goCheckHostKeyPolicy()
- self.set_missing_host_key_policy(_check_policy)
-
- try:
- paramiko.SSHClient.connect(self, hostname=hostname, port=port, username='foo', password='bar')
- except x2go_exceptions.AuthenticationException:
- host_ok = True
- self.logger('SSH host key verification for host [%s]:%s succeeded. Host is already known to the client\'s Paramiko/SSH sub-system.' % (_hostname, _port), loglevel=log.loglevel_NOTICE)
- except x2go_exceptions.SSHException, e:
- msg = str(e)
- if msg.startswith('Checked host key for X2go server '):
- host_ok = False
- _hostname = _check_policy.get_hostname().split(':')[0].lstrip('[').rstrip(']')
- _port = _check_policy.get_hostname().split(':')[1]
- _fingerprint = _check_policy.get_key_fingerprint_with_colons()
- _fingerprint_type = _check_policy.get_key_name()
- self.logger('SSH host key verification for host [%s]:%s with %s fingerprint ,,%s\'\' failed. Seeing this X2go server for the first time.' % (_hostname, _port, _fingerprint_type, _fingerprint), loglevel=log.loglevel_NOTICE)
- else:
- raise(e)
-
- self.set_missing_host_key_policy(paramiko.RejectPolicy())
- return (host_ok, _hostname, _port, _fingerprint, _fingerprint_type)
+ return checkhosts.check_ssh_host_key(self, hostname, port=port)
def connect(self, hostname, port=22, username='', password='', pkey=None,
use_sshproxy=False, sshproxy_host='', sshproxy_user='', sshproxy_password='',
sshproxy_key_filename='', sshproxy_tunnel='',
key_filename=None, timeout=None, allow_agent=False, look_for_keys=False,
+ session_instance=None,
add_to_known_hosts=False, force_password_auth=False):
"""\
Connect to an X2go server and authenticate to it. This method is directly
@@ -326,6 +304,9 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
@param force_password_auth: non-paramiko option, disable pub/priv key authentication
completely, even if the C{pkey} or the C{key_filename} parameter is given
@type force_password_auth: C{bool}
+ @param session_instance: an instance L{X2goSession} using this L{X2goControlSessionSTDOUT}
+ instance.
+ @type session_instance: C{instance}
@raise BadHostKeyException: if the server's host key could not be
verified
@@ -337,14 +318,13 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
"""
if use_sshproxy and sshproxy_host and sshproxy_user:
try:
- add_to_known_hosts = add_to_known_hosts | self.add_to_known_hosts
- self.sshproxy_session = sshproxy.X2goSSHProxy(add_to_known_hosts=add_to_known_hosts,
- known_hosts=self.known_hosts,
+ self.sshproxy_session = sshproxy.X2goSSHProxy(known_hosts=self.known_hosts,
sshproxy_host=sshproxy_host,
sshproxy_user=sshproxy_user,
sshproxy_password=sshproxy_password,
sshproxy_key_filename=sshproxy_key_filename,
sshproxy_tunnel=sshproxy_tunnel,
+ session_instance=session_instance,
logger=self.logger,
)
@@ -364,6 +344,10 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
gevent.sleep(1)
port = self.sshproxy_session.get_local_proxy_port()
+
+ if not add_to_known_hosts and session_instance:
+ self.set_missing_host_key_policy(checkhosts.X2goInteractiveAddPolicy(caller=self, session_instance=session_instance))
+
if add_to_known_hosts:
self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@@ -374,6 +358,9 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
self.logger('connecting to %s' % hostname, loglevel=log.loglevel_NOTICE)
+ if self.known_hosts is not None:
+ utils.touch_file(self.known_hosts)
+ self.load_host_keys(self.known_hosts)
if (key_filename and os.path.exists(os.path.normpath(key_filename))) or pkey:
try:
self.logger('trying SSH pub/priv key authentication with server', loglevel=log.loglevel_DEBUG)
@@ -399,8 +386,11 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
self.close()
raise(e)
- # if there is not private key, we will use the given password
- elif password:
+ # if there is not private key, we will use the given password, if any
+ else:
+ # create a random password if password is empty to trigger host key validity check
+ if not password:
+ password = "".join([random.choice(string.letters+string.digits) for x in range(1, 20)])
self.logger('performing SSH keyboard-interactive authentication with server', loglevel=log.loglevel_DEBUG)
try:
paramiko.SSHClient.connect(self, hostname, port=port, username=username, password=password,
@@ -410,13 +400,11 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
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()
+ except x2go_exceptions.X2goHostKeyException, e:
+ if self.sshproxy_session:
+ self.sshproxy_session.stop_thread()
+ self.close()
+ raise(e)
self.set_missing_host_key_policy(paramiko.RejectPolicy())
diff --git a/x2go/checkhosts.py b/x2go/checkhosts.py
index d4eda9a..2bdcc4b 100644
--- a/x2go/checkhosts.py
+++ b/x2go/checkhosts.py
@@ -28,9 +28,11 @@ import paramiko
import binascii
# Python X2go modules
+import sshproxy
+import log
import x2go_exceptions
-class X2goCheckHostKeyPolicy(paramiko.MissingHostKeyPolicy):
+class X2goInteractiveAddPolicy(paramiko.MissingHostKeyPolicy):
"""\
Policy for making host key information available to Python X2go after a
Paramiko/SSH connect has been attempted. A connect that uses this
@@ -38,13 +40,32 @@ class X2goCheckHostKeyPolicy(paramiko.MissingHostKeyPolicy):
This is used by L{X2goControlSessionSTDOUT}.
"""
+ def __init__(self, caller=None, session_instance=None):
+ self.caller = caller
+ self.session_instance = session_instance
+
def missing_host_key(self, client, hostname, key):
self.client = client
self.hostname = hostname
self.key = key
- client._log(paramiko.common.DEBUG, 'Checking %s host key for %s: %s' %
+ client._log(paramiko.common.DEBUG, 'Interactively Checking %s host key for %s: %s' %
(key.get_name(), hostname, binascii.hexlify(key.get_fingerprint())))
- raise x2go_exceptions.SSHException('Checked host key for X2go server %s' % hostname)
+ if self.session_instance:
+ self.session_instance.logger('SSH host key verification for host %s with %s fingerprint ,,%s\'\' initiated. We are seeing this X2go server for the first time.' % (hostname, self.get_key_name(), self.get_key_fingerprint_with_colons()), loglevel=log.loglevel_NOTICE)
+ _valid = self.session_instance.HOOK_check_host_dialog(self.get_hostname_name(),
+ port=self.get_hostname_port(),
+ fingerprint=self.get_key_fingerprint_with_colons(),
+ fingerprint_type=self.get_key_name(),
+ )
+ if _valid:
+ paramiko.AutoAddPolicy().missing_host_key(client, hostname, key)
+ else:
+ if type(self.caller) in (sshproxy.X2goSSHProxy, ):
+ raise x2go_exceptions.X2goSSHProxyHostKeyException('Invalid host %s is not authorized for access. Add the host to Paramiko/SSH\'s known_hosts file.' % hostname)
+ else:
+ raise x2go_exceptions.X2goHostKeyException('Invalid host %s is not authorized for access. Add the host to Paramiko/SSH\'s known_hosts file.' % hostname)
+ else:
+ raise x2go_exceptions.SSHException('Policy has collected host key information on %s for further introspection' % hostname)
def get_client(self):
return self.client
@@ -52,6 +73,12 @@ class X2goCheckHostKeyPolicy(paramiko.MissingHostKeyPolicy):
def get_hostname(self):
return self.hostname
+ def get_hostname_name(self):
+ return self.get_hostname().split(':')[0].lstrip('[').rstrip(']')
+
+ def get_hostname_port(self):
+ return self.get_hostname().split(':')[1]
+
def get_key(self):
return self.key
@@ -72,3 +99,38 @@ class X2goCheckHostKeyPolicy(paramiko.MissingHostKeyPolicy):
_colon_fingerprint += ':'
return _colon_fingerprint.rstrip(':')
+
+def check_ssh_host_key(x2go_sshclient_instance, hostname, port=22):
+ """\
+ Perform a Paramiko/SSH host key check.
+
+ """
+ _hostname = hostname
+ _port = port
+ _fingerprint = 'NO-FINGERPRINT'
+ _fingerprint_type = 'SOME-KEY-TYPE'
+
+ _check_policy = X2goInteractiveAddPolicy()
+ x2go_sshclient_instance.set_missing_host_key_policy(_check_policy)
+
+ host_ok = False
+ try:
+ paramiko.SSHClient.connect(x2go_sshclient_instance, hostname=hostname, port=port, username='foo', password='bar')
+ except x2go_exceptions.AuthenticationException:
+ host_ok = True
+ x2go_sshclient_instance.logger('SSH host key verification for host [%s]:%s succeeded. Host is already known to the client\'s Paramiko/SSH sub-system.' % (_hostname, _port), loglevel=log.loglevel_NOTICE)
+ except x2go_exceptions.SSHException, e:
+ msg = str(e)
+ if msg.startswith('Policy has collected host key information on '):
+ _hostname = _check_policy.get_hostname().split(':')[0].lstrip('[').rstrip(']')
+ _port = _check_policy.get_hostname().split(':')[1]
+ _fingerprint = _check_policy.get_key_fingerprint_with_colons()
+ _fingerprint_type = _check_policy.get_key_name()
+ else:
+ raise(e)
+ x2go_sshclient_instance.set_missing_host_key_policy(paramiko.RejectPolicy())
+ except:
+ # let any other error be handled by subsequent algorithms
+ pass
+
+ return (host_ok, _hostname, _port, _fingerprint, _fingerprint_type)
diff --git a/x2go/registry.py b/x2go/registry.py
index 7a17017..8d134e7 100644
--- a/x2go/registry.py
+++ b/x2go/registry.py
@@ -71,6 +71,9 @@ class X2goSessionRegistry(object):
self.registry = {}
self.control_sessions = {}
+ def keys(self):
+ return self.registry.keys()
+
def __repr__(self):
result = 'X2goSessionRegistry('
for p in dir(self):
@@ -118,13 +121,13 @@ class X2goSessionRegistry(object):
_session_summary['control_params'] = _r and self(session_uuid).control_params or {}
_session_summary['terminal_session'] = _r and self(session_uuid).get_terminal_session() or None
_session_summary['terminal_params'] = _r and self(session_uuid).terminal_params or {}
- _session_summary['active_threads'] = _r and self(session_uuid).get_terminal_session().active_threads or []
+ _session_summary['active_threads'] = _r and bool(self(session_uuid).get_terminal_session()) and self(session_uuid).get_terminal_session().active_threads or []
_session_summary['backends'] = {
- 'control': _r and self(session_uuid)._control_backend or None,
- 'terminal': _r and self(session_uuid)._terminal_backend or None,
- 'info': _r and self(session_uuid)._info_backend or None,
- 'list': _r and self(session_uuid)._list_backend or None,
- 'proxy': _r and self(session_uuid)._proxy_backend or None,
+ 'control': _r and self(session_uuid).control_backend or None,
+ 'terminal': _r and self(session_uuid).terminal_backend or None,
+ 'info': _r and self(session_uuid).info_backend or None,
+ 'list': _r and self(session_uuid).list_backend or None,
+ 'proxy': _r and self(session_uuid).proxy_backend or None,
}
if _r:
diff --git a/x2go/session.py b/x2go/session.py
index d65226f..c225c60 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -525,7 +525,10 @@ class X2goSession(object):
_params.update(self.control_params)
_params.update(self.sshproxy_params)
- self.connected = self.control_session.connect(self.server, use_sshproxy=self.use_sshproxy, **_params)
+ self.connected = self.control_session.connect(self.server,
+ use_sshproxy=self.use_sshproxy,
+ session_instance=self,
+ **_params)
# remove credentials immediately
self.control_params['password'] = ''
try: del self.control_params['sshproxy_user']
diff --git a/x2go/sshproxy.py b/x2go/sshproxy.py
index 69cdce7..7ef8e63 100644
--- a/x2go/sshproxy.py
+++ b/x2go/sshproxy.py
@@ -31,8 +31,12 @@ import paramiko
import threading
import socket
+import string
+import random
+
# Python X2go modules
import x2go.forward as forward
+import x2go.checkhosts as checkhosts
import x2go.log as log
import x2go.utils as utils
from x2go.x2go_exceptions import *
@@ -56,6 +60,7 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
sshproxy_password=None, sshproxy_key_filename=None,
sshproxy_tunnel=None,
ssh_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SSH_ROOTDIR),
+ session_instance=None,
logger=None, loglevel=log.loglevel_DEFAULT, ):
"""\
STILL UNDOCUMENTED
@@ -77,7 +82,7 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
self.hostname, self.port, self.username = hostname, port, username
# translate between X2goSession options and paramiko.SSHCLient.connect() options
- if sshproxy_host:
+ if sshproxy_host:
if sshproxy_host.find(':'):
self.hostname = sshproxy_host.split(':')[0]
try: self.port = int(sshproxy_host.split(':')[1])
@@ -109,6 +114,9 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
utils.touch_file(known_hosts)
self.load_host_keys(known_hosts)
+ if not add_to_known_hosts and session_instance:
+ self.set_missing_host_key_policy(checkhosts.X2goInteractiveAddPolicy(caller=self, session_instance=session_instance))
+
if add_to_known_hosts:
self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
@@ -124,7 +132,11 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
except AuthenticationException, e:
raise X2goSSHProxyAuthenticationException('pubkey auth mechanisms both failed')
- elif password:
+ # if there is not private key, we will use the given password, if any
+ else:
+ # create a random password if password is empty to trigger host key validity check
+ if not password:
+ password = "".join([random.choice(string.letters+string.digits) for x in range(1, 20)])
try:
self.connect(self.hostname, port=self.port,
username=self.username,
@@ -134,8 +146,7 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
)
except AuthenticationException:
raise X2goSSHProxyAuthenticationException('interactive auth mechanisms failed')
- else:
- raise X2goSSHProxyAuthenticationException('no auth mechanism available')
+
except paramiko.SSHException, e:
raise X2goSSHProxyException(str(e))
@@ -143,6 +154,17 @@ class X2goSSHProxy(paramiko.SSHClient, threading.Thread):
threading.Thread.__init__(self)
self.daemon = True
+ def check_host(self):
+ """\
+ Wraps around a Paramiko/SSH host key check.
+
+ """
+ _valid = False
+ (_valid, _hostname, _port, _fingerprint, _fingerprint_type) = checkhosts.check_ssh_host_key(self, self.hostname, port=self.port)
+ if not _valid and self.session_instance:
+ _valid = self.session_instance.HOOK_check_host_dialog(_hostname, _port, fingerprint=_fingerprint, fingerprint_type=_fingerprint_type)
+ return _valid
+
def run(self):
if self.get_transport() is not None and self.get_transport().is_authenticated():
diff --git a/x2go/x2go_exceptions.py b/x2go/x2go_exceptions.py
index 73faf76..22a98fb 100644
--- a/x2go/x2go_exceptions.py
+++ b/x2go/x2go_exceptions.py
@@ -43,6 +43,8 @@ class _X2goException(exceptions.BaseException): pass
class X2goClientException(_X2goException): pass
class X2goSessionException(_X2goException): pass
class X2goControlSessionException(_X2goException): pass
+class X2goHostKeyException(_X2goException): pass
+class X2goSSHProxyHostKeyException(_X2goException): pass
class X2goTerminalSessionException(_X2goException): pass
class X2goSessionCacheException(_X2goException): pass
class X2goUserException(_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