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

Source Code for Module x2go.checkhosts

  1  # -*- coding: utf-8 -*- 
  2   
  3  # Copyright (C) 2010-2012 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 Affero 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 Affero General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU Affero 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   
 30  # Python X2Go modules 
 31  import sshproxy 
 32  import log 
 33  import x2go_exceptions 
 34  import random 
 35  import string 
 36   
37 -class X2goInteractiveAddPolicy(paramiko.MissingHostKeyPolicy):
38 """\ 39 Policy for making host key information available to Python X2Go after a 40 Paramiko/SSH connect has been attempted. This class needs information 41 about the associated L{X2goSession} instance. 42 43 Once called, the L{missing_host_key} method of this class will try to call 44 L{X2goSession.HOOK_check_host_dialog()}. This hook method---if not re-defined 45 in your application---will then try to call the L{X2goClient.HOOK_check_host_dialog()}, 46 which then will return C{True} by default if not customized in your application. 47 48 To accept host key checks, make sure to either customize the 49 L{X2goClient.HOOK_check_host_dialog()} method or the L{X2goSession.HOOK_check_host_dialog()} 50 method and hook some interactive user dialog to either of them. 51 52 """
53 - def __init__(self, caller=None, session_instance=None):
54 """\ 55 @param caller: calling instance 56 @type caller: C{class} 57 @param session_instance: an X2Go session instance 58 @type session_instance: L{X2goSession} instance 59 60 """ 61 self.caller = caller 62 self.session_instance = session_instance
63
64 - def missing_host_key(self, client, hostname, key):
65 """\ 66 Handle a missing host key situation. This method calls 67 68 Once called, the L{missing_host_key} method will try to call 69 L{X2goSession.HOOK_check_host_dialog()}. This hook method---if not re-defined 70 in your application---will then try to call the L{X2goClient.HOOK_check_host_dialog()}, 71 which then will return C{True} by default if not customized in your application. 72 73 To accept host key checks, make sure to either customize the 74 L{X2goClient.HOOK_check_host_dialog()} method or the L{X2goSession.HOOK_check_host_dialog()} 75 method and hook some interactive user dialog to either of them. 76 77 @param client: SSH client (C{X2goControlSession*}) instance 78 @type client: C{X2goControlSession*} instance 79 @param hostname: remote hostname 80 @type hostname: C{str} 81 @param key: host key to validate 82 @type key: Paramiko/SSH key instance 83 84 @raise X2goHostKeyException: if the X2Go server host key is not in the C{known_hosts} file 85 @raise X2goSSHProxyHostKeyException: if the SSH proxy host key is not in the C{known_hosts} file 86 @raise SSHException: if this instance does not know its {self.session_instance} 87 88 """ 89 self.client = client 90 self.hostname = hostname 91 if (self.hostname.find(']') == -1) and (self.hostname.find(':') == -1): 92 # if hostname is an IPv4 quadruple with standard SSH port... 93 self.hostname = '[%s]:22' % self.hostname 94 self.key = key 95 client._log(paramiko.common.DEBUG, 'Interactively Checking %s host key for %s: %s' % 96 (self.key.get_name(), self.hostname, binascii.hexlify(self.key.get_fingerprint()))) 97 if self.session_instance: 98 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) 99 _valid = self.session_instance.HOOK_check_host_dialog(self.get_hostname_name(), 100 port=self.get_hostname_port(), 101 fingerprint=self.get_key_fingerprint_with_colons(), 102 fingerprint_type=self.get_key_name(), 103 ) 104 if _valid: 105 paramiko.AutoAddPolicy().missing_host_key(client, self.hostname, key) 106 else: 107 if type(self.caller) in (sshproxy.X2goSSHProxy, ): 108 raise x2go_exceptions.X2goSSHProxyHostKeyException('Invalid host %s is not authorized for access. Add the host to Paramiko/SSH\'s known_hosts file.' % hostname) 109 else: 110 raise x2go_exceptions.X2goHostKeyException('Invalid host %s is not authorized for access. Add the host to Paramiko/SSH\'s known_hosts file.' % hostname) 111 else: 112 raise x2go_exceptions.SSHException('Policy has collected host key information on %s for further introspection' % hostname)
113
114 - def get_client(self):
115 """\ 116 Retrieve the Paramiko SSH/Client. 117 118 @return: the associated X2Go control session instance. 119 @rtype: C{X2goControlSession*} instance 120 121 """ 122 return self.client
123
124 - def get_hostname(self):
125 """\ 126 Retrieve the server hostname:port expression of the server to be validated. 127 128 @return: hostname:port 129 @rtype: C{str} 130 131 """ 132 return self.hostname
133
134 - def get_hostname_name(self):
135 """\ 136 Retrieve the server hostname string of the server to be validated. 137 138 @return: hostname 139 @rtype: C{str} 140 141 """ 142 return self.get_hostname().split(':')[0].lstrip('[').rstrip(']')
143
144 - def get_hostname_port(self):
145 """\ 146 Retrieve the server port of the server to be validated. 147 148 @return: port 149 @rtype: C{str} 150 151 """ 152 return self.get_hostname().split(':')[1]
153
154 - def get_key(self):
155 """\ 156 Retrieve the host key of the server to be validated. 157 158 @return: host key 159 @rtype: Paramiko/SSH key instance 160 161 """ 162 return self.key
163
164 - def get_key_name(self):
165 """\ 166 Retrieve the host key name of the server to be validated. 167 168 @return: host key name (RSA, DSA, ...) 169 @rtype: C{str} 170 171 """ 172 return self.key.get_name().upper()
173
174 - def get_key_fingerprint(self):
175 """\ 176 Retrieve the host key fingerprint of the server to be validated. 177 178 @return: host key fingerprint 179 @rtype: C{str} 180 181 """ 182 return binascii.hexlify(self.key.get_fingerprint())
183
185 """\ 186 Retrieve the (colonized) host key fingerprint of the server 187 to be validated. 188 189 @return: host key fingerprint (with colons) 190 @rtype: C{str} 191 192 """ 193 _fingerprint = self.get_key_fingerprint() 194 _colon_fingerprint = '' 195 idx = 0 196 for char in _fingerprint: 197 idx += 1 198 _colon_fingerprint += char 199 if idx % 2 == 0: 200 _colon_fingerprint += ':' 201 return _colon_fingerprint.rstrip(':')
202 203
204 -def check_ssh_host_key(x2go_sshclient_instance, hostname, port=22):
205 """\ 206 Perform a Paramiko/SSH host key check by connecting to the host and 207 validating the results (i.e. by validating raised exceptions during the 208 connect process). 209 210 @param x2go_sshclient_instance: a Paramiko/SSH client instance to be used for testing host key validity. 211 @type x2go_sshclient_instance: C{X2goControlSession*} instance 212 @param hostname: hostname of server to validate 213 @type hostname: C{str} 214 @param port: port of server to validate 215 @type port: C{int} 216 217 @return: returns a tuple with the following components (<host_ok>, <hostname>, <port>, <fingerprint>, <fingerprint_type>) 218 @rtype: C{tuple} 219 220 @raise SSHException: if an SSH exception occurred, that we did not provocate in L{X2goInteractiveAddPolicy.missing_host_key()} 221 222 """ 223 _hostname = hostname 224 _port = port 225 _fingerprint = 'NO-FINGERPRINT' 226 _fingerprint_type = 'SOME-KEY-TYPE' 227 228 _check_policy = X2goInteractiveAddPolicy() 229 x2go_sshclient_instance.set_missing_host_key_policy(_check_policy) 230 231 host_ok = False 232 try: 233 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)])) 234 except x2go_exceptions.AuthenticationException: 235 host_ok = True 236 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) 237 except x2go_exceptions.SSHException, e: 238 msg = str(e) 239 if msg.startswith('Policy has collected host key information on '): 240 _hostname = _check_policy.get_hostname().split(':')[0].lstrip('[').rstrip(']') 241 _port = _check_policy.get_hostname().split(':')[1] 242 _fingerprint = _check_policy.get_key_fingerprint_with_colons() 243 _fingerprint_type = _check_policy.get_key_name() 244 else: 245 raise(e) 246 x2go_sshclient_instance.set_missing_host_key_policy(paramiko.RejectPolicy()) 247 except: 248 # let any other error be handled by subsequent algorithms 249 pass 250 251 return (host_ok, _hostname, _port, _fingerprint, _fingerprint_type)
252