Skip to content

Commit 5b55f14

Browse files
committed
CRAM-MD5 - for server testing only.
Undocumented, unsupported, could be removed at any time. Don't use this. Consider yourself warned.
1 parent b4eff6b commit 5b55f14

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

pymongo/auth.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@
1414

1515
"""Authentication helpers."""
1616

17+
import hmac
1718
try:
1819
import hashlib
1920
_MD5 = hashlib.md5
21+
_DMOD = _MD5
2022
except ImportError: # for Python < 2.5
2123
import md5
2224
_MD5 = md5.new
25+
_DMOD = md5
2326

2427
HAVE_KERBEROS = True
2528
try:
@@ -28,11 +31,12 @@
2831
HAVE_KERBEROS = False
2932

3033
from bson.binary import Binary
34+
from bson.py3compat import b
3135
from bson.son import SON
3236
from pymongo.errors import ConfigurationError, OperationFailure
3337

3438

35-
MECHANISMS = ('GSSAPI', 'MONGODB-CR', 'MONGODB-X509', 'PLAIN')
39+
MECHANISMS = frozenset(['GSSAPI', 'MONGODB-CR', 'MONGODB-X509', 'PLAIN'])
3640
"""The authentication mechanisms supported by PyMongo."""
3741

3842

@@ -167,6 +171,29 @@ def _authenticate_plain(credentials, sock_info, cmd_func):
167171
cmd_func(sock_info, source, cmd)
168172

169173

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+
170197
def _authenticate_x509(credentials, sock_info, cmd_func):
171198
"""Authenticate using MONGODB-X509.
172199
"""
@@ -195,6 +222,7 @@ def _authenticate_mongo_cr(credentials, sock_info, cmd_func):
195222

196223

197224
_AUTH_MAP = {
225+
'CRAM-MD5': _authenticate_cram_md5,
198226
'GSSAPI': _authenticate_gssapi,
199227
'MONGODB-CR': _authenticate_mongo_cr,
200228
'MONGODB-X509': _authenticate_x509,

pymongo/common.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,10 @@ def validate_tag_sets(dummy, value):
219219
def validate_auth_mechanism(option, value):
220220
"""Validate the authMechanism URI option.
221221
"""
222-
if value not in MECHANISMS:
222+
# CRAM-MD5 is for server testing only. Undocumented,
223+
# unsupported, may be removed at any time. You have
224+
# been warned.
225+
if value not in MECHANISMS and value != 'CRAM-MD5':
223226
raise ConfigurationError("%s must be in "
224227
"%s" % (option, MECHANISMS))
225228
return value

0 commit comments

Comments
 (0)