PYTHON-1184 - Don't require X.509 user with MongoDB 3.4
This commit is contained in:
parent
807f719405
commit
1600059015
@ -14,6 +14,8 @@ Highlights include:
|
||||
- Unicode aware string comparison using :doc:`examples/collations`.
|
||||
- Support for the new :class:`~bson.decimal128.Decimal128` BSON type.
|
||||
- A new maxStalenessSeconds read preference option.
|
||||
- A username is no longer required for the MONGODB-X509 authentication
|
||||
mechanism when connected to MongoDB >= 3.4.
|
||||
- :meth:`~pymongo.collection.Collection.parallel_scan` supports maxTimeMS.
|
||||
- :attr:`~pymongo.write_concern.WriteConcern` is automatically
|
||||
applied by all helpers for commands that write to the database when
|
||||
|
||||
@ -95,10 +95,10 @@ and newer::
|
||||
>>> import ssl
|
||||
>>> from pymongo import MongoClient
|
||||
>>> client = MongoClient('example.com',
|
||||
... ssl=True,
|
||||
... ssl_certfile='/path/to/client.pem',
|
||||
... ssl_cert_reqs=ssl.CERT_REQUIRED,
|
||||
... ssl_ca_certs='/path/to/ca.pem')
|
||||
... ssl=True,
|
||||
... ssl_certfile='/path/to/client.pem',
|
||||
... ssl_cert_reqs=ssl.CERT_REQUIRED,
|
||||
... ssl_ca_certs='/path/to/ca.pem')
|
||||
>>> client.the_database.authenticate("<X.509 derived username>",
|
||||
... mechanism='MONGODB-X509')
|
||||
True
|
||||
@ -109,12 +109,15 @@ do not have to specify a database in the URI::
|
||||
|
||||
>>> uri = "mongodb://<X.509 derived username>@example.com/?authMechanism=MONGODB-X509"
|
||||
>>> client = MongoClient(uri,
|
||||
... ssl=True,
|
||||
... ssl_certfile='/path/to/client.pem',
|
||||
... ssl_cert_reqs=ssl.CERT_REQUIRED,
|
||||
... ssl_ca_certs='/path/to/ca.pem')
|
||||
... ssl=True,
|
||||
... ssl_certfile='/path/to/client.pem',
|
||||
... ssl_cert_reqs=ssl.CERT_REQUIRED,
|
||||
... ssl_ca_certs='/path/to/ca.pem')
|
||||
>>>
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
When connected to MongoDB >= 3.4 the username is no longer required.
|
||||
|
||||
.. _use_kerberos:
|
||||
|
||||
GSSAPI (Kerberos)
|
||||
|
||||
@ -58,7 +58,7 @@ GSSAPIProperties = namedtuple('GSSAPIProperties',
|
||||
def _build_credentials_tuple(mech, source, user, passwd, extra):
|
||||
"""Build and return a mechanism specific credentials tuple.
|
||||
"""
|
||||
user = _unicode(user)
|
||||
user = _unicode(user) if user is not None else None
|
||||
password = passwd if passwd is None else _unicode(passwd)
|
||||
if mech == 'GSSAPI':
|
||||
properties = extra.get('authmechanismproperties', {})
|
||||
@ -71,6 +71,7 @@ def _build_credentials_tuple(mech, source, user, passwd, extra):
|
||||
# Source is always $external.
|
||||
return MongoCredential(mech, '$external', user, password, props)
|
||||
elif mech == 'MONGODB-X509':
|
||||
# user can be None.
|
||||
return MongoCredential(mech, '$external', user, None, None)
|
||||
else:
|
||||
if passwd is None:
|
||||
@ -415,8 +416,13 @@ def _authenticate_x509(credentials, sock_info):
|
||||
"""Authenticate using MONGODB-X509.
|
||||
"""
|
||||
query = SON([('authenticate', 1),
|
||||
('mechanism', 'MONGODB-X509'),
|
||||
('user', credentials.username)])
|
||||
('mechanism', 'MONGODB-X509')])
|
||||
if credentials.username is not None:
|
||||
query['user'] = credentials.username
|
||||
elif sock_info.max_wire_version < 5:
|
||||
raise ConfigurationError(
|
||||
"A username is required for MONGODB-X509 authentication "
|
||||
"when connected to MongoDB versions older than 3.4.")
|
||||
sock_info.command('$external', query)
|
||||
|
||||
|
||||
|
||||
@ -29,9 +29,9 @@ from pymongo.write_concern import WriteConcern
|
||||
|
||||
def _parse_credentials(username, password, database, options):
|
||||
"""Parse authentication credentials."""
|
||||
if username is None:
|
||||
return None
|
||||
mechanism = options.get('authmechanism', 'DEFAULT')
|
||||
if username is None and mechanism != 'MONGODB-X509':
|
||||
return None
|
||||
source = options.get('authsource', database or 'admin')
|
||||
return _build_credentials_tuple(
|
||||
mechanism, source, username, password, options)
|
||||
|
||||
@ -966,7 +966,7 @@ class Database(common.BaseObject):
|
||||
return
|
||||
raise
|
||||
|
||||
def authenticate(self, name, password=None,
|
||||
def authenticate(self, name=None, password=None,
|
||||
source=None, mechanism='DEFAULT', **kwargs):
|
||||
"""Authenticate to use this database.
|
||||
|
||||
@ -992,7 +992,9 @@ class Database(common.BaseObject):
|
||||
distinct client instances.
|
||||
|
||||
:Parameters:
|
||||
- `name`: the name of the user to authenticate.
|
||||
- `name`: the name of the user to authenticate. Optional when
|
||||
`mechanism` is MONGODB-X509 and the MongoDB server version is
|
||||
>= 3.4.
|
||||
- `password` (optional): the password of the user to authenticate.
|
||||
Not used with GSSAPI or MONGODB-X509 authentication.
|
||||
- `source` (optional): the database to authenticate on. If not
|
||||
@ -1017,7 +1019,7 @@ class Database(common.BaseObject):
|
||||
|
||||
.. mongodoc:: authenticate
|
||||
"""
|
||||
if not isinstance(name, string_type):
|
||||
if name is not None and not isinstance(name, string_type):
|
||||
raise TypeError("name must be an "
|
||||
"instance of %s" % (string_type.__name__,))
|
||||
if password is not None and not isinstance(password, string_type):
|
||||
|
||||
@ -518,24 +518,47 @@ class TestSSL(IntegrationTest):
|
||||
|
||||
coll = ssl_client.pymongo_test.test
|
||||
self.assertRaises(OperationFailure, coll.count)
|
||||
|
||||
if client_context.version.at_least(3, 3, 12):
|
||||
self.assertTrue(
|
||||
ssl_client.admin.authenticate(mechanism='MONGODB-X509'))
|
||||
# No error
|
||||
coll.find_one()
|
||||
# MONGODB_X509_USERNAME and None aren't the same user, so we
|
||||
# have to log out before continuing.
|
||||
ssl_client.admin.logout()
|
||||
else:
|
||||
# Should require a username
|
||||
with self.assertRaises(ConfigurationError):
|
||||
ssl_client.admin.authenticate(mechanism='MONGODB-X509')
|
||||
|
||||
self.assertTrue(ssl_client.admin.authenticate(
|
||||
MONGODB_X509_USERNAME, mechanism='MONGODB-X509'))
|
||||
coll.drop()
|
||||
# No error
|
||||
coll.find_one()
|
||||
|
||||
uri = ('mongodb://%s@%s:%d/?authMechanism='
|
||||
'MONGODB-X509' % (
|
||||
quote_plus(MONGODB_X509_USERNAME), host, port))
|
||||
# SSL options aren't supported in the URI...
|
||||
self.assertTrue(MongoClient(uri, ssl=True,
|
||||
ssl_cert_reqs=ssl.CERT_NONE,
|
||||
ssl_certfile=CLIENT_PEM))
|
||||
client = MongoClient(uri,
|
||||
ssl=True,
|
||||
ssl_cert_reqs=ssl.CERT_NONE,
|
||||
ssl_certfile=CLIENT_PEM)
|
||||
# No error
|
||||
client.pymongo_test.test.find_one()
|
||||
|
||||
# Should require a username
|
||||
uri = ('mongodb://%s:%d/?authMechanism=MONGODB-X509' % (host,
|
||||
port))
|
||||
client_bad = MongoClient(
|
||||
uri, ssl=True, ssl_cert_reqs="CERT_NONE", ssl_certfile=CLIENT_PEM)
|
||||
self.assertRaises(OperationFailure,
|
||||
client_bad.pymongo_test.test.delete_one, {})
|
||||
uri = 'mongodb://%s:%d/?authMechanism=MONGODB-X509' % (host, port)
|
||||
client = MongoClient(uri,
|
||||
ssl=True,
|
||||
ssl_cert_reqs=ssl.CERT_NONE,
|
||||
ssl_certfile=CLIENT_PEM)
|
||||
if client_context.version.at_least(3, 3, 12):
|
||||
# No error
|
||||
client.pymongo_test.test.find_one()
|
||||
else:
|
||||
# Should require a username
|
||||
with self.assertRaises(ConfigurationError):
|
||||
client.pymongo_test.test.find_one()
|
||||
|
||||
# Auth should fail if username and certificate do not match
|
||||
uri = ('mongodb://%s@%s:%d/?authMechanism='
|
||||
|
||||
Loading…
Reference in New Issue
Block a user