| Home | Trees | Indices | Help |
|---|
|
|
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
38 """
39 Internal class to handle the mechanics of authentication.
40 """
41
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
58
64
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
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
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
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
115
116
117 ### internals...
118
119
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
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
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
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
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
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
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