1
# -*- encoding: utf-8 -*-
2
##############################################################################
4
# OpenERP, Open Source Management Solution
5
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
8
# This program is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation, either version 3 of the License, or
11
# (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21
##############################################################################
24
class AuthHandler (paramiko.AuthHandler):
26
Internal class to handle the mechanics of authentication.
28
def _parse_userauth_request(self, m):
29
if not self.transport.server_mode:
32
m.add_byte(chr(MSG_USERAUTH_FAILURE))
35
self.transport._send_message(m)
37
if self.authenticated:
40
username = m.get_string()
41
service = m.get_string()
42
method = m.get_string()
43
self.transport._log(DEBUG, 'Auth request (type=%s) service=%s, username=%s' % (method, service, username))
44
if service != 'ssh-connection':
45
self._disconnect_service_not_available()
47
if (self.auth_username is not None) and (self.auth_username != username):
48
self.transport._log(WARNING, 'Auth rejected because the client attempted to change username in mid-flight')
49
self._disconnect_no_more_auth()
51
self.auth_username = username
54
result = self.transport.server_object.check_auth_none(username)
55
elif method == 'password':
56
changereq = m.get_boolean()
57
password = m.get_string()
59
password = password.decode('UTF-8')
61
# some clients/servers expect non-utf-8 passwords!
62
# in this case, just return the raw byte string.
65
# always treated as failure, since we don't support changing passwords, but collect
66
# the list of valid auth types from the callback anyway
67
self.transport._log(DEBUG, 'Auth request to change passwords (rejected)')
68
newpassword = m.get_string()
70
newpassword = newpassword.decode('UTF-8', 'replace')
75
result = self.transport.server_object.check_auth_password(username, password)
76
elif method == 'publickey':
77
sig_attached = m.get_boolean()
78
keytype = m.get_string()
79
keyblob = m.get_string()
81
key = self.transport._key_info[keytype](Message(keyblob))
82
except SSHException, e:
83
self.transport._log(INFO, 'Auth rejected: public key: %s' % str(e))
86
self.transport._log(INFO, 'Auth rejected: unsupported or mangled public key')
89
self._disconnect_no_more_auth()
91
# first check if this key is okay... if not, we can skip the verify
92
result = self.transport.server_object.check_auth_publickey(username, key)
93
if result != AUTH_FAILED:
94
# key is okay, verify it
96
# client wants to know if this key is acceptable, before it
97
# signs anything... send special "ok" message
99
m.add_byte(chr(MSG_USERAUTH_PK_OK))
100
m.add_string(keytype)
101
m.add_string(keyblob)
102
self.transport._send_message(m)
104
sig = Message(m.get_string())
105
blob = self._get_session_blob(key, service, username)
106
if not key.verify_ssh_sig(blob, sig):
107
self.transport._log(INFO, 'Auth rejected: invalid signature')
109
elif method == 'keyboard-interactive':
110
lang = m.get_string()
111
submethods = m.get_string()
112
result = self.transport.server_object.check_auth_interactive(username, submethods)
113
if isinstance(result, InteractiveQuery):
114
# make interactive query instead of response
115
self._interactive_query(result)
118
result = self.transport.server_object.check_auth_none(username)
120
self._send_auth_result(username, method, result)