Package x2go :: Module checkhosts
[frames] | no frames]

Source Code for Module x2go.checkhosts

  1  # -*- coding: utf-8 -*- 
  2   
  3  # Copyright (C) 2010-2011 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> 
  4  # 
  5  # Python X2go is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 3 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # Python X2go is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License 
 16  # along with this program; if not, write to the 
 17  # Free Software Foundation, Inc., 
 18  # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 
 19   
 20  """\ 
 21  Providing mechanisms to C{X2goControlSession*} backends for checking host validity. 
 22   
 23  """ 
 24  __NAME__ = 'x2gocheckhosts-pylib' 
 25   
 26  # modules 
 27  import paramiko 
 28  import binascii 
 29  import uuid 
 30   
 31  # Python X2go modules 
 32  import sshproxy 
 33  import log 
 34  import x2go_exceptions 
 35   
36 -class X2goInteractiveAddPolicy(paramiko.MissingHostKeyPolicy):
37 """\ 38 Policy for making host key information available to Python X2go after a 39 Paramiko/SSH connect has been attempted. This class needs information 40 about the associated L{X2goSession} instance. 41 42 Once called, the L{missing_host_key} method of this class will try to call 43 L{X2goSession.HOOK_check_host_dialog()}. This hook method---if not re-defined 44 in your application---will then try to call the L{X2goClient.HOOK_check_host_dialog()}, 45 which then will return C{True} by default if not customized in your application. 46 47 To accept host key checks, make sure to either customize the 48 L{X2goClient.HOOK_check_host_dialog()} method or the L{X2goSession.HOOK_check_host_dialog()} 49 method and hook some interactive user dialog to either of them. 50 51 """
52 - def __init__(self, caller=None, session_instance=None):
53 """\ 54 @param caller: calling instance 55 @type caller: C{class} 56 @param session_instance: an X2go session instance 57 @type session_instance: L{X2goSession} instance 58 59 """ 60 self.caller = caller 61 self.session_instance = session_instance
62
63 - def missing_host_key(self, client, hostname, key):
64 """\ 65 Handle a missing host key situation. This method calls 66 67 Once called, the L{missing_host_key} method will try to call 68 L{X2goSession.HOOK_check_host_dialog()}. This hook method---if not re-defined 69 in your application---will then try to call the L{X2goClient.HOOK_check_host_dialog()}, 70 which then will return C{True} by default if not customized in your application. 71 72 To accept host key checks, make sure to either customize the 73 L{X2goClient.HOOK_check_host_dialog()} method or the L{X2goSession.HOOK_check_host_dialog()} 74 method and hook some interactive user dialog to either of them. 75 76 @param client: SSH client (C{X2goControlSession*}) instance 77 @type client: C{X2goControlSession*} instance 78 @param hostname: remote hostname 79 @type hostname: C{str} 80 @param key: host key to validate 81 @type key: Paramiko/SSH key instance 82 83 """ 84 self.client = client 85 self.hostname = hostname 86 if (self.hostname.find(']') == -1) and (self.hostname.find(':') == -1): 87 # if hostname is an IPv4 quadruple with standard SSH port... 88 self.hostname = '[%s]:22' % self.hostname 89 self.key = key 90 client._log(paramiko.common.DEBUG, 'Interactively Checking %s host key for %s: %s' % 91 (self.key.get_name(), self.hostname, binascii.hexlify(self.key.get_fingerprint()))) 92 if self.session_instance: 93 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.' % (self.get_hostname(), self.get_key_name(), self.get_key_fingerprint_with_colons()), loglevel=log.loglevel_NOTICE) 94 _valid = self.session_instance.HOOK_check_host_dialog(self.get_hostname_name(), 95 port=self.get_hostname_port(), 96 fingerprint=self.get_key_fingerprint_with_colons(), 97 fingerprint_type=self.get_key_name(), 98 ) 99 if _valid: 100 paramiko.AutoAddPolicy().missing_host_key(client, self.hostname, key) 101 else: 102 if type(self.caller) in (sshproxy.X2goSSHProxy, ): 103 raise x2go_exceptions.X2goSSHProxyHostKeyException('Invalid host %s is not authorized for access. Add the host to Paramiko/SSH\'s known_hosts file.' % hostname) 104 else: 105 raise x2go_exceptions.X2goHostKeyException('Invalid host %s is not authorized for access. Add the host to Paramiko/SSH\'s known_hosts file.' % hostname) 106 else: 107 raise x2go_exceptions.SSHException('Policy has collected host key information on %s for further introspection' % hostname)
108
109 - def get_client(self):
110 """\ 111 Retrieve the Paramiko SSH/Client. 112 113 @return: the associated X2go control session instance. 114 @rtype: C{X2goControlSession*} instance 115 116 """ 117 return self.client
118
119 - def get_hostname(self):
120 """\ 121 Retrieve the server hostname:port expression of the server to be validated. 122 123 @return: hostname:port 124 @rtype: C{str} 125 126 """ 127 return self.hostname
128
129 - def get_hostname_name(self):
130 """\ 131 Retrieve the server hostname string of the server to be validated. 132 133 @return: hostname 134 @rtype: C{str} 135 136 """ 137 return self.get_hostname().split(':')[0].lstrip('[').rstrip(']')
138
139 - def get_hostname_port(self):
140 """\ 141 Retrieve the server port of the server to be validated. 142 143 @return: port 144 @rtype: C{str} 145 146 """ 147 return self.get_hostname().split(':')[1]
148
149 - def get_key(self):
150 """\ 151 Retrieve the host key of the server to be validated. 152 153 @return: host key 154 @rtype: Paramiko/SSH key instance 155 156 """ 157 return self.key
158
159 - def get_key_name(self):
160 """\ 161 Retrieve the host key name of the server to be validated. 162 163 @return: host key name (RSA, DSA, ...) 164 @rtype: C{str} 165 166 """ 167 return self.key.get_name().upper()
168
169 - def get_key_fingerprint(self):
170 """\ 171 Retrieve the host key fingerprint of the server to be validated. 172 173 @return: host key fingerprint 174 @rtype: C{str} 175 176 """ 177 return binascii.hexlify(self.key.get_fingerprint())
178
180 """\ 181 Retrieve the (colonized) host key fingerprint of the server 182 to be validated. 183 184 @return: host key fingerprint (with colons) 185 @rtype: C{str} 186 187 """ 188 _fingerprint = self.get_key_fingerprint() 189 _colon_fingerprint = '' 190 idx = 0 191 for char in _fingerprint: 192 idx += 1 193 _colon_fingerprint += char 194 if idx % 2 == 0: 195 _colon_fingerprint += ':' 196 return _colon_fingerprint.rstrip(':')
197 198
199 -def check_ssh_host_key(x2go_sshclient_instance, hostname, port=22):
200 """\ 201 Perform a Paramiko/SSH host key check by connecting to the host and 202 validating the results (i.e. by validating raised exceptions during the 203 connect process). 204 205 @param x2go_sshclient_instance: a Paramiko/SSH client instance to be used for testing host key validity. 206 @type x2go_sshclient_instance: C{X2goControlSession*} instance 207 @param hostname: hostname of server to validate 208 @type hostname: C{str} 209 @param port: port of server to validate 210 @type port: C{int} 211 @return: returns a tuple with the following components (<host_ok>, <hostname>, <port>, <fingerprint>, <fingerprint_type>) 212 @rtype: C{tuple} 213 214 """ 215 _hostname = hostname 216 _port = port 217 _fingerprint = 'NO-FINGERPRINT' 218 _fingerprint_type = 'SOME-KEY-TYPE' 219 220 _check_policy = X2goInteractiveAddPolicy() 221 x2go_sshclient_instance.set_missing_host_key_policy(_check_policy) 222 223 host_ok = False 224 try: 225 paramiko.SSHClient.connect(x2go_sshclient_instance, hostname=hostname, port=port, username='foo', password="".join([random.choice(string.letters+string.digits) for x in range(1, 20)])) 226 except x2go_exceptions.AuthenticationException: 227 host_ok = True 228 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) 229 except x2go_exceptions.SSHException, e: 230 msg = str(e) 231 if msg.startswith('Policy has collected host key information on '): 232 _hostname = _check_policy.get_hostname().split(':')[0].lstrip('[').rstrip(']') 233 _port = _check_policy.get_hostname().split(':')[1] 234 _fingerprint = _check_policy.get_key_fingerprint_with_colons() 235 _fingerprint_type = _check_policy.get_key_name() 236 else: 237 raise(e) 238 x2go_sshclient_instance.set_missing_host_key_policy(paramiko.RejectPolicy()) 239 except: 240 # let any other error be handled by subsequent algorithms 241 pass 242 243 return (host_ok, _hostname, _port, _fingerprint, _fingerprint_type)
244