|
14 | 14 |
|
15 | 15 | """Authentication helpers.""" |
16 | 16 |
|
| 17 | +import hmac |
17 | 18 | try: |
18 | 19 | import hashlib |
19 | 20 | _MD5 = hashlib.md5 |
| 21 | + _DMOD = _MD5 |
20 | 22 | except ImportError: # for Python < 2.5 |
21 | 23 | import md5 |
22 | 24 | _MD5 = md5.new |
| 25 | + _DMOD = md5 |
23 | 26 |
|
24 | 27 | HAVE_KERBEROS = True |
25 | 28 | try: |
|
28 | 31 | HAVE_KERBEROS = False |
29 | 32 |
|
30 | 33 | from bson.binary import Binary |
| 34 | +from bson.py3compat import b |
31 | 35 | from bson.son import SON |
32 | 36 | from pymongo.errors import ConfigurationError, OperationFailure |
33 | 37 |
|
34 | 38 |
|
35 | | -MECHANISMS = ('GSSAPI', 'MONGODB-CR', 'MONGODB-X509', 'PLAIN') |
| 39 | +MECHANISMS = frozenset(['GSSAPI', 'MONGODB-CR', 'MONGODB-X509', 'PLAIN']) |
36 | 40 | """The authentication mechanisms supported by PyMongo.""" |
37 | 41 |
|
38 | 42 |
|
@@ -167,6 +171,29 @@ def _authenticate_plain(credentials, sock_info, cmd_func): |
167 | 171 | cmd_func(sock_info, source, cmd) |
168 | 172 |
|
169 | 173 |
|
| 174 | +def _authenticate_cram_md5(credentials, sock_info, cmd_func): |
| 175 | + """Authenticate using CRAM-MD5 (RFC 2195) |
| 176 | + """ |
| 177 | + source, username, password = credentials |
| 178 | + # The password used as the mac key is the |
| 179 | + # same as what we use for MONGODB-CR |
| 180 | + passwd = _password_digest(username, password) |
| 181 | + cmd = SON([('saslStart', 1), |
| 182 | + ('mechanism', 'CRAM-MD5'), |
| 183 | + ('payload', Binary(b(''))), |
| 184 | + ('autoAuthorize', 1)]) |
| 185 | + response, _ = cmd_func(sock_info, source, cmd) |
| 186 | + # MD5 as implicit default digest for digestmod is deprecated |
| 187 | + # in python 3.4 |
| 188 | + mac = hmac.HMAC(key=passwd.encode('utf-8'), digestmod=_DMOD) |
| 189 | + mac.update(response['payload']) |
| 190 | + challenge = username.encode('utf-8') + b(' ') + b(mac.hexdigest()) |
| 191 | + cmd = SON([('saslContinue', 1), |
| 192 | + ('conversationId', response['conversationId']), |
| 193 | + ('payload', Binary(challenge))]) |
| 194 | + cmd_func(sock_info, source, cmd) |
| 195 | + |
| 196 | + |
170 | 197 | def _authenticate_x509(credentials, sock_info, cmd_func): |
171 | 198 | """Authenticate using MONGODB-X509. |
172 | 199 | """ |
@@ -195,6 +222,7 @@ def _authenticate_mongo_cr(credentials, sock_info, cmd_func): |
195 | 222 |
|
196 | 223 |
|
197 | 224 | _AUTH_MAP = { |
| 225 | + 'CRAM-MD5': _authenticate_cram_md5, |
198 | 226 | 'GSSAPI': _authenticate_gssapi, |
199 | 227 | 'MONGODB-CR': _authenticate_mongo_cr, |
200 | 228 | 'MONGODB-X509': _authenticate_x509, |
|
0 commit comments