Package paramiko :: Module auth_handler
[frames] | no frames]

Source Code for Module paramiko.auth_handler

  1  # Copyright (C) 2003-2007  Robey Pointer <robey@lag.net> 
  2  # 
  3  # This file is part of paramiko. 
  4  # 
  5  # Paramiko is free software; you can redistribute it and/or modify it under the 
  6  # terms of the GNU Lesser General Public License as published by the Free 
  7  # Software Foundation; either version 2.1 of the License, or (at your option) 
  8  # any later version. 
  9  # 
 10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
 11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
 13  # details. 
 14  # 
 15  # You should have received a copy of the GNU Lesser General Public License 
 16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
 17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
 18   
 19  """ 
 20  L{AuthHandler} 
 21  """ 
 22   
 23  import threading 
 24  import weakref 
 25   
 26  # this helps freezing utils 
 27  import encodings.utf_8 
 28   
 29  from paramiko.common import * 
 30  from paramiko import util 
 31  from paramiko.message import Message 
 32  from paramiko.ssh_exception import SSHException, AuthenticationException, \ 
 33      BadAuthenticationType, PartialAuthentication 
 34  from paramiko.server import InteractiveQuery 
 35   
 36   
37 -class AuthHandler (object):
38 """ 39 Internal class to handle the mechanics of authentication. 40 """ 41
42 - def __init__(self, transport):
43 self.transport = weakref.proxy(transport) 44 self.username = None 45 self.authenticated = False 46 self.auth_event = None 47 self.auth_method = '' 48 self.password = None 49 self.private_key = None 50 self.interactive_handler = None 51 self.submethods = None 52 # for server mode: 53 self.auth_username = None 54 self.auth_fail_count = 0
55
56 - def is_authenticated(self):
57 return self.authenticated
58
59 - def get_username(self):
60 if self.transport.server_mode: 61 return self.auth_username 62 else: 63 return self.username
64
65 - def auth_none(self, username, event):
66 self.transport.lock.acquire() 67 try: 68 self.auth_event = event 69 self.auth_method = 'none' 70 self.username = username 71 self._request_auth() 72 finally: 73 self.transport.lock.release()
74
75 - def auth_publickey(self, username, key, event):
76 self.transport.lock.acquire() 77 try: 78 self.auth_event = event 79 self.auth_method = 'publickey' 80 self.username = username 81 self.private_key = key 82 self._request_auth() 83 finally: 84 self.transport.lock.release()
85
86 - def auth_password(self, username, password, event):
87 self.transport.lock.acquire() 88 try: 89 self.auth_event = event 90 self.auth_method = 'password' 91 self.username = username 92 self.password = password 93 self._request_auth() 94 finally: 95 self.transport.lock.release()
96
97 - def auth_interactive(self, username, handler, event, submethods=''):
98 """ 99 response_list = handler(title, instructions, prompt_list) 100 """ 101 self.transport.lock.acquire() 102 try: 103 self.auth_event = event 104 self.auth_method = 'keyboard-interactive' 105 self.username = username 106 self.interactive_handler = handler 107 self.submethods = submethods 108 self._request_auth() 109 finally: 110 self.transport.lock.release()
111
112 - def abort(self):
113 if self.auth_event is not None: 114 self.auth_event.set()
115 116 117 ### internals... 118 119
120 - def _request_auth(self):
121 m = Message() 122 m.add_byte(chr(MSG_SERVICE_REQUEST)) 123 m.add_string('ssh-userauth') 124 self.transport._send_message(m)
125
127 m = Message() 128 m.add_byte(chr(MSG_DISCONNECT)) 129 m.add_int(DISCONNECT_SERVICE_NOT_AVAILABLE) 130 m.add_string('Service not available') 131 m.add_string('en') 132 self.transport._send_message(m) 133 self.transport.close()
134
135 - def _disconnect_no_more_auth(self):
136 m = Message() 137 m.add_byte(chr(MSG_DISCONNECT)) 138 m.add_int(DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE) 139 m.add_string('No more auth methods available') 140 m.add_string('en') 141 self.transport._send_message(m) 142 self.transport.close()
143
144 - def _get_session_blob(self, key, service, username):
145 m = Message() 146 m.add_string(self.transport.session_id) 147 m.add_byte(chr(MSG_USERAUTH_REQUEST)) 148 m.add_string(username) 149 m.add_string(service) 150 m.add_string('publickey') 151 m.add_boolean(1) 152 m.add_string(key.get_name()) 153 m.add_string(str(key)) 154 return str(m)
155
156 - def wait_for_response(self, event):
157 while True: 158 event.wait(0.1) 159 if not self.transport.is_active(): 160 e = self.transport.get_exception() 161 if (e is None) or issubclass(e.__class__, EOFError): 162 e = AuthenticationException('Authentication failed.') 163 raise e 164 if event.isSet(): 165 break 166 if not self.is_authenticated(): 167 e = self.transport.get_exception() 168 if e is None: 169 e = AuthenticationException('Authentication failed.') 170 # this is horrible. python Exception isn't yet descended from 171 # object, so type(e) won't work. :( 172 if issubclass(e.__class__, PartialAuthentication): 173 return e.allowed_types 174 raise e 175 return []
176
177 - def _parse_service_request(self, m):
178 service = m.get_string() 179 if self.transport.server_mode and (service == 'ssh-userauth'): 180 # accepted 181 m = Message() 182 m.add_byte(chr(MSG_SERVICE_ACCEPT)) 183 m.add_string(service) 184 self.transport._send_message(m) 185 return 186 # dunno this one 187 self._disconnect_service_not_available()
188
189 - def _parse_service_accept(self, m):
190 service = m.get_string() 191 if service == 'ssh-userauth': 192 self.transport._log(DEBUG, 'userauth is OK') 193 m = Message() 194 m.add_byte(chr(MSG_USERAUTH_REQUEST)) 195 m.add_string(self.username) 196 m.add_string('ssh-connection') 197 m.add_string(self.auth_method) 198 if self.auth_method == 'password': 199 m.add_boolean(False) 200 password = self.password 201 if isinstance(password, unicode): 202 password = password.encode('UTF-8') 203 m.add_string(password) 204 elif self.auth_method == 'publickey': 205 m.add_boolean(True) 206 m.add_string(self.private_key.get_name()) 207 m.add_string(str(self.private_key)) 208 blob = self._get_session_blob(self.private_key, 'ssh-connection', self.username) 209 sig = self.private_key.sign_ssh_data(self.transport.randpool, blob) 210 m.add_string(str(sig)) 211 elif self.auth_method == 'keyboard-interactive': 212 m.add_string('') 213 m.add_string(self.submethods) 214 elif self.auth_method == 'none': 215 pass 216 else: 217 raise SSHException('Unknown auth method "%s"' % self.auth_method) 218 self.transport._send_message(m) 219 else: 220 self.transport._log(DEBUG, 'Service request "%s" accepted (?)' % service)
221
222 - def _send_auth_result(self, username, method, result):
223 # okay, send result 224 m = Message() 225 if result == AUTH_SUCCESSFUL: 226 self.transport._log(INFO, 'Auth granted (%s).' % method) 227 m.add_byte(chr(MSG_USERAUTH_SUCCESS)) 228 self.authenticated = True 229 else: 230 self.transport._log(INFO, 'Auth rejected (%s).' % method) 231 m.add_byte(chr(MSG_USERAUTH_FAILURE)) 232 m.add_string(self.transport.server_object.get_allowed_auths(username)) 233 if result == AUTH_PARTIALLY_SUCCESSFUL: 234 m.add_boolean(1) 235 else: 236 m.add_boolean(0) 237 self.auth_fail_count += 1 238 self.transport._send_message(m) 239 if self.auth_fail_count >= 10: 240 self._disconnect_no_more_auth() 241 if result == AUTH_SUCCESSFUL: 242 self.transport._auth_trigger()
243
244 - def _interactive_query(self, q):
245 # make interactive query instead of response 246 m = Message() 247