PYTHON-1282 Username/password must be URI-escaped

Not just "%", "@", and ":" must be escaped, all delimiters from RFC 3986
must be percent-encoded. Therefore, since "/" must be escaped in
username and password, we can split the URI at the first "/" instead of
the last.
This commit is contained in:
A. Jesse Jiryu Davis 2017-06-10 20:24:57 -04:00
parent 803c83d342
commit c72ee15b52
11 changed files with 618 additions and 484 deletions

View File

@ -5,19 +5,22 @@ MongoDB supports several different authentication mechanisms. These examples
cover all authentication methods currently supported by PyMongo, documenting
Python module and MongoDB version dependencies.
Support For Special Characters In Usernames And Passwords
---------------------------------------------------------
Percent-Escaping Username and Password
--------------------------------------
If your username or password contains special characters (e.g. '/', ' ',
or '@') you must ``%xx`` escape them for use in the MongoDB URI. PyMongo
uses :meth:`~urllib.unquote_plus` to decode them. For example::
Username and password must be percent-escaped with :meth:`~urllib.quote_plus`
to be used in a MongoDB URI. PyMongo uses :meth:`~urllib.unquote_plus`
internally to decode them. For example::
>>> from pymongo import MongoClient
>>> import urllib
>>> username = urllib.quote_plus('user')
>>> username
'user'
>>> password = urllib.quote_plus('pass/word')
>>> password
'pass%2Fword'
>>> MongoClient('mongodb://user:' + password + '@127.0.0.1')
>>> MongoClient('mongodb://%s:%s@127.0.0.1' % (username, password)
MongoClient('127.0.0.1', 27017)
SCRAM-SHA-1 (RFC 5802)

View File

@ -14,6 +14,7 @@
"""Tools to parse and validate a MongoDB URI."""
import re
import warnings
from bson.py3compat import PY3, iteritems, string_type
@ -68,7 +69,7 @@ def _rpartition(entity, sep):
def parse_userinfo(userinfo):
"""Validates the format of user information in a MongoDB URI.
Reserved characters like ':', '/', '+' and '@' must be escaped
following RFC 2396.
following RFC 3986.
Returns a 2-tuple containing the unescaped username followed
by the unescaped password.
@ -80,16 +81,13 @@ def parse_userinfo(userinfo):
Now uses `urllib.unquote_plus` so `+` characters must be escaped.
"""
if '@' in userinfo or userinfo.count(':') > 1:
raise InvalidURI("':' or '@' characters in a username or password "
"must be escaped according to RFC 2396.")
raise InvalidURI("Username and password must be escaped according to "
"RFC 3986, use urllib.quote_plus().")
user, _, passwd = _partition(userinfo, ":")
# No password is expected with GSSAPI authentication.
if not user:
raise InvalidURI("The empty string is not valid username.")
user = unquote_plus(user)
passwd = unquote_plus(passwd)
return user, passwd
return unquote_plus(user), unquote_plus(passwd)
def parse_ipv6_literal_host(entity, default_port):
@ -251,6 +249,11 @@ def split_hosts(hosts, default_port=DEFAULT_PORT):
return nodes
# Prohibited characters in database name. DB names also can't have ".", but for
# backward-compat we allow "db.collection" in URI.
_BAD_DB_CHARS = re.compile('[' + re.escape(r'/ "$') + ']')
def parse_uri(uri, default_port=DEFAULT_PORT, validate=True, warn=False):
"""Parse and validate a MongoDB URI.
@ -294,19 +297,10 @@ def parse_uri(uri, default_port=DEFAULT_PORT, validate=True, warn=False):
collection = None
options = {}
# Check for unix domain sockets in the uri
if '.sock' in scheme_free:
host_part, _, path_part = _rpartition(scheme_free, '/')
if not host_part:
host_part = path_part
path_part = ""
if '/' in host_part:
raise InvalidURI("Any '/' in a unix domain socket must be"
" URL encoded: %s" % host_part)
host_part = unquote_plus(host_part)
path_part = unquote_plus(path_part)
else:
host_part, _, path_part = _partition(scheme_free, '/')
host_part, _, path_part = _partition(scheme_free, '/')
if not host_part:
host_part = path_part
path_part = ""
if not path_part and '?' in host_part:
raise InvalidURI("A '/' is required between "
@ -318,17 +312,24 @@ def parse_uri(uri, default_port=DEFAULT_PORT, validate=True, warn=False):
else:
hosts = host_part
if '/' in hosts:
raise InvalidURI("Any '/' in a unix domain socket must be"
" URL encoded: %s" % host_part)
hosts = unquote_plus(hosts)
nodes = split_hosts(hosts, default_port=default_port)
if path_part:
if path_part[0] == '?':
opts = path_part[1:]
opts = unquote_plus(path_part[1:])
else:
dbase, _, opts = _partition(path_part, '?')
dbase, _, opts = map(unquote_plus, _partition(path_part, '?'))
if '.' in dbase:
dbase, collection = dbase.split('.', 1)
if _BAD_DB_CHARS.search(dbase):
raise InvalidURI('Bad database name "%s"' % dbase)
if opts:
options = split_options(opts, validate, warn)

View File

@ -189,6 +189,15 @@
"valid": false,
"warning": null
},
{
"auth": null,
"description": "Username with password containing an unescaped colon",
"hosts": null,
"options": null,
"uri": "mongodb://alice:foo:bar@127.0.0.1",
"valid": false,
"warning": null
},
{
"auth": null,
"description": "Username containing an unescaped at-sign",
@ -207,6 +216,33 @@
"valid": false,
"warning": null
},
{
"auth": null,
"description": "Username containing an unescaped slash",
"hosts": null,
"options": null,
"uri": "mongodb://alice/@localhost/db",
"valid": false,
"warning": null
},
{
"auth": null,
"description": "Username containing unescaped slash with password",
"hosts": null,
"options": null,
"uri": "mongodb://alice/bob:foo@localhost/db",
"valid": false,
"warning": null
},
{
"auth": null,
"description": "Username with password containing an unescaped slash",
"hosts": null,
"options": null,
"uri": "mongodb://alice:foo/bar@localhost/db",
"valid": false,
"warning": null
},
{
"auth": null,
"description": "Host with unescaped slash",

View File

@ -2,328 +2,309 @@
"tests": [
{
"auth": {
"db": null,
"password": "foo",
"db": null,
"password": "foo",
"username": "alice"
},
"description": "User info for single IPv4 host without database",
},
"description": "User info for single IPv4 host without database",
"hosts": [
{
"host": "127.0.0.1",
"port": null,
"host": "127.0.0.1",
"port": null,
"type": "ipv4"
}
],
"options": null,
"uri": "mongodb://alice:foo@127.0.0.1",
"valid": true,
],
"options": null,
"uri": "mongodb://alice:foo@127.0.0.1",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": "test",
"password": "foo",
"db": "test",
"password": "foo",
"username": "alice"
},
"description": "User info for single IPv4 host with database",
},
"description": "User info for single IPv4 host with database",
"hosts": [
{
"host": "127.0.0.1",
"port": null,
"host": "127.0.0.1",
"port": null,
"type": "ipv4"
}
],
"options": null,
"uri": "mongodb://alice:foo@127.0.0.1/test",
"valid": true,
],
"options": null,
"uri": "mongodb://alice:foo@127.0.0.1/test",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": "t\u0000est",
"password": "f\u0000oo",
"username": "a\u0000lice"
},
"description": "User info for single IPv4 host with database (escaped null bytes)",
"hosts": [
{
"host": "127.0.0.1",
"port": null,
"type": "ipv4"
}
],
"options": null,
"uri": "mongodb://a%00lice:f%00oo@127.0.0.1/t%00est",
"valid": true,
"warning": false
},
{
"auth": {
"db": null,
"password": "bar",
"db": null,
"password": "bar",
"username": "bob"
},
"description": "User info for single IP literal host without database",
},
"description": "User info for single IP literal host without database",
"hosts": [
{
"host": "::1",
"port": 27018,
"host": "::1",
"port": 27018,
"type": "ip_literal"
}
],
"options": null,
"uri": "mongodb://bob:bar@[::1]:27018",
"valid": true,
],
"options": null,
"uri": "mongodb://bob:bar@[::1]:27018",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": "admin",
"password": "bar",
"db": "admin",
"password": "bar",
"username": "bob"
},
"description": "User info for single IP literal host with database",
},
"description": "User info for single IP literal host with database",
"hosts": [
{
"host": "::1",
"port": 27018,
"host": "::1",
"port": 27018,
"type": "ip_literal"
}
],
"options": null,
"uri": "mongodb://bob:bar@[::1]:27018/admin",
"valid": true,
],
"options": null,
"uri": "mongodb://bob:bar@[::1]:27018/admin",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": null,
"password": "baz",
"db": null,
"password": "baz",
"username": "eve"
},
"description": "User info for single hostname without database",
},
"description": "User info for single hostname without database",
"hosts": [
{
"host": "example.com",
"port": null,
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://eve:baz@example.com",
"valid": true,
],
"options": null,
"uri": "mongodb://eve:baz@example.com",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": "db2",
"password": "baz",
"db": "db2",
"password": "baz",
"username": "eve"
},
"description": "User info for single hostname with database",
},
"description": "User info for single hostname with database",
"hosts": [
{
"host": "example.com",
"port": null,
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://eve:baz@example.com/db2",
"valid": true,
],
"options": null,
"uri": "mongodb://eve:baz@example.com/db2",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": null,
"password": "secret",
"db": null,
"password": "secret",
"username": "alice"
},
"description": "User info for multiple hosts without database",
},
"description": "User info for multiple hosts without database",
"hosts": [
{
"host": "127.0.0.1",
"port": null,
"host": "127.0.0.1",
"port": null,
"type": "ipv4"
},
},
{
"host": "example.com",
"port": 27018,
"host": "example.com",
"port": 27018,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://alice:secret@127.0.0.1,example.com:27018",
"valid": true,
],
"options": null,
"uri": "mongodb://alice:secret@127.0.0.1,example.com:27018",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": "admin",
"password": "secret",
"db": "admin",
"password": "secret",
"username": "alice"
},
"description": "User info for multiple hosts with database",
},
"description": "User info for multiple hosts with database",
"hosts": [
{
"host": "example.com",
"port": null,
"host": "example.com",
"port": null,
"type": "hostname"
},
},
{
"host": "::1",
"port": 27019,
"host": "::1",
"port": 27019,
"type": "ip_literal"
}
],
"options": null,
"uri": "mongodb://alice:secret@example.com,[::1]:27019/admin",
"valid": true,
],
"options": null,
"uri": "mongodb://alice:secret@example.com,[::1]:27019/admin",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": null,
"password": null,
"db": null,
"password": null,
"username": "alice"
},
"description": "Username without password",
},
"description": "Username without password",
"hosts": [
{
"host": "127.0.0.1",
"port": null,
"host": "127.0.0.1",
"port": null,
"type": "ipv4"
}
],
"options": null,
"uri": "mongodb://alice@127.0.0.1",
"valid": true,
],
"options": null,
"uri": "mongodb://alice@127.0.0.1",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": null,
"password": "",
"db": null,
"password": "",
"username": "alice"
},
"description": "Username with empty password",
},
"description": "Username with empty password",
"hosts": [
{
"host": "127.0.0.1",
"port": null,
"host": "127.0.0.1",
"port": null,
"type": "ipv4"
}
],
"options": null,
"uri": "mongodb://alice:@127.0.0.1",
"valid": true,
],
"options": null,
"uri": "mongodb://alice:@127.0.0.1",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": "my=db",
"password": null,
"username": "@l:ce"
},
"description": "Escaped username and database without password",
"db": "my=db",
"password": null,
"username": "@l:ce/="
},
"description": "Escaped username and database without password",
"hosts": [
{
"host": "example.com",
"port": null,
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://%40l%3Ace@example.com/my%3Ddb",
"valid": true,
],
"options": null,
"uri": "mongodb://%40l%3Ace%2F%3D@example.com/my%3Ddb",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": "admin?",
"password": "f:zzb@zz",
"db": "admin?",
"password": "f:zzb@z/z=",
"username": "$am"
},
"description": "Escaped user info and database (MONGODB-CR)",
},
"description": "Escaped user info and database (MONGODB-CR)",
"hosts": [
{
"host": "127.0.0.1",
"port": null,
"host": "127.0.0.1",
"port": null,
"type": "ipv4"
}
],
],
"options": {
"authmechanism": "MONGODB-CR"
},
"uri": "mongodb://%24am:f%3Azzb%40zz@127.0.0.1/admin%3F?authMechanism=MONGODB-CR",
"valid": true,
},
"uri": "mongodb://%24am:f%3Azzb%40z%2Fz%3D@127.0.0.1/admin%3F?authMechanism=MONGODB-CR",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": null,
"password": null,
"db": null,
"password": null,
"username": "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry"
},
"description": "Escaped username (MONGODB-X509)",
},
"description": "Escaped username (MONGODB-X509)",
"hosts": [
{
"host": "localhost",
"port": null,
"host": "localhost",
"port": null,
"type": "hostname"
}
],
],
"options": {
"authmechanism": "MONGODB-X509"
},
"uri": "mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509",
"valid": true,
},
"uri": "mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": null,
"password": "secret",
"db": null,
"password": "secret",
"username": "user@EXAMPLE.COM"
},
"description": "Escaped username (GSSAPI)",
},
"description": "Escaped username (GSSAPI)",
"hosts": [
{
"host": "localhost",
"port": null,
"host": "localhost",
"port": null,
"type": "hostname"
}
],
],
"options": {
"authmechanism": "GSSAPI",
"authmechanism": "GSSAPI",
"authmechanismproperties": {
"CANONICALIZE_HOST_NAME": true,
"CANONICALIZE_HOST_NAME": true,
"SERVICE_NAME": "other"
}
},
"uri": "mongodb://user%40EXAMPLE.COM:secret@localhost/?authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true&authMechanism=GSSAPI",
"valid": true,
},
"uri": "mongodb://user%40EXAMPLE.COM:secret@localhost/?authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true&authMechanism=GSSAPI",
"valid": true,
"warning": false
},
},
{
"auth": {
"db": "admin",
"password": "secret",
"db": "admin",
"password": "secret",
"username": "alice"
},
"description": "At-signs in options aren't part of the userinfo",
},
"description": "At-signs in options aren't part of the userinfo",
"hosts": [
{
"host": "example.com",
"port": null,
"host": "example.com",
"port": null,
"type": "hostname"
}
],
],
"options": {
"replicaset": "my@replicaset"
},
"uri": "mongodb://alice:secret@example.com/admin?replicaset=my@replicaset",
"valid": true,
},
"uri": "mongodb://alice:secret@example.com/admin?replicaset=my@replicaset",
"valid": true,
"warning": false
}
]

View File

@ -0,0 +1,100 @@
{
"tests": [
{
"auth": {
"db": "admin.sock",
"password": null,
"username": null
},
"description": "Multiple Unix domain sockets and auth DB resembling a socket (relative path)",
"hosts": [
{
"host": "rel/mongodb-27017.sock",
"port": null,
"type": "unix"
},
{
"host": "rel/mongodb-27018.sock",
"port": null,
"type": "unix"
}
],
"options": null,
"uri": "mongodb://rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock/admin.sock",
"valid": true,
"warning": false
},
{
"auth": {
"db": "admin.shoe",
"password": null,
"username": null
},
"description": "Multiple Unix domain sockets with auth DB resembling a path (relative path)",
"hosts": [
{
"host": "rel/mongodb-27017.sock",
"port": null,
"type": "unix"
},
{
"host": "rel/mongodb-27018.sock",
"port": null,
"type": "unix"
}
],
"options": null,
"uri": "mongodb://rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock/admin.shoe",
"valid": true,
"warning": false
},
{
"auth": {
"db": "admin.sock",
"password": null,
"username": null
},
"description": "Multiple Unix domain sockets and auth DB resembling a socket (absolute path)",
"hosts": [
{
"host": "/tmp/mongodb-27017.sock",
"port": null,
"type": "unix"
},
{
"host": "/tmp/mongodb-27018.sock",
"port": null,
"type": "unix"
}
],
"options": null,
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/admin.sock",
"valid": true,
"warning": false
},
{
"auth": {
"db": "admin.shoe",
"password": null,
"username": null
},
"description": "Multiple Unix domain sockets with auth DB resembling a path (absolute path)",
"hosts": [
{
"host": "/tmp/mongodb-27017.sock",
"port": null,
"type": "unix"
},
{
"host": "/tmp/mongodb-27018.sock",
"port": null,
"type": "unix"
}
],
"options": null,
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/admin.shoe",
"valid": true,
"warning": false
}
]
}

View File

@ -1,154 +1,154 @@
{
"tests": [
"tests": [
{
"description": "Single IPv4 host without port",
"uri": "mongodb://127.0.0.1",
"valid": true,
"warning": false,
"hosts": [
{
"auth": null,
"description": "Single IPv4 host without port",
"hosts": [
{
"host": "127.0.0.1",
"port": null,
"type": "ipv4"
}
],
"options": null,
"uri": "mongodb://127.0.0.1",
"valid": true,
"warning": false
},
{
"auth": null,
"description": "Single IPv4 host with port",
"hosts": [
{
"host": "127.0.0.1",
"port": 27018,
"type": "ipv4"
}
],
"options": null,
"uri": "mongodb://127.0.0.1:27018",
"valid": true,
"warning": false
},
{
"auth": null,
"description": "Single IP literal host without port",
"hosts": [
{
"host": "::1",
"port": null,
"type": "ip_literal"
}
],
"options": null,
"uri": "mongodb://[::1]",
"valid": true,
"warning": false
},
{
"auth": null,
"description": "Single IP literal host with port",
"hosts": [
{
"host": "::1",
"port": 27019,
"type": "ip_literal"
}
],
"options": null,
"uri": "mongodb://[::1]:27019",
"valid": true,
"warning": false
},
{
"auth": null,
"description": "Single hostname without port",
"hosts": [
{
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://example.com",
"valid": true,
"warning": false
},
{
"auth": null,
"description": "Single hostname with port",
"hosts": [
{
"host": "example.com",
"port": 27020,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://example.com:27020",
"valid": true,
"warning": false
},
{
"auth": null,
"description": "Single hostname (resembling IPv4) without port",
"hosts": [
{
"host": "256.0.0.1",
"port": null,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://256.0.0.1",
"valid": true,
"warning": false
},
{
"auth": null,
"description": "Multiple hosts (mixed formats)",
"hosts": [
{
"host": "127.0.0.1",
"port": null,
"type": "ipv4"
},
{
"host": "::1",
"port": 27018,
"type": "ip_literal"
},
{
"host": "example.com",
"port": 27019,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://127.0.0.1,[::1]:27018,example.com:27019",
"valid": true,
"warning": false
},
{
"auth": null,
"description": "UTF-8 hosts",
"hosts": [
{
"host": "b\u00fccher.example.com",
"port": null,
"type": "hostname"
},
{
"host": "uml\u00e4ut.example.com",
"port": null,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://b\u00fccher.example.com,uml\u00e4ut.example.com/",
"valid": true,
"warning": false
"type": "ipv4",
"host": "127.0.0.1",
"port": null
}
]
],
"auth": null,
"options": null
},
{
"description": "Single IPv4 host with port",
"uri": "mongodb://127.0.0.1:27018",
"valid": true,
"warning": false,
"hosts": [
{
"type": "ipv4",
"host": "127.0.0.1",
"port": 27018
}
],
"auth": null,
"options": null
},
{
"description": "Single IP literal host without port",
"uri": "mongodb://[::1]",
"valid": true,
"warning": false,
"hosts": [
{
"type": "ip_literal",
"host": "::1",
"port": null
}
],
"auth": null,
"options": null
},
{
"description": "Single IP literal host with port",
"uri": "mongodb://[::1]:27019",
"valid": true,
"warning": false,
"hosts": [
{
"type": "ip_literal",
"host": "::1",
"port": 27019
}
],
"auth": null,
"options": null
},
{
"description": "Single hostname without port",
"uri": "mongodb://example.com",
"valid": true,
"warning": false,
"hosts": [
{
"type": "hostname",
"host": "example.com",
"port": null
}
],
"auth": null,
"options": null
},
{
"description": "Single hostname with port",
"uri": "mongodb://example.com:27020",
"valid": true,
"warning": false,
"hosts": [
{
"type": "hostname",
"host": "example.com",
"port": 27020
}
],
"auth": null,
"options": null
},
{
"description": "Single hostname (resembling IPv4) without port",
"uri": "mongodb://256.0.0.1",
"valid": true,
"warning": false,
"hosts": [
{
"type": "hostname",
"host": "256.0.0.1",
"port": null
}
],
"auth": null,
"options": null
},
{
"description": "Multiple hosts (mixed formats)",
"uri": "mongodb://127.0.0.1,[::1]:27018,example.com:27019",
"valid": true,
"warning": false,
"hosts": [
{
"type": "ipv4",
"host": "127.0.0.1",
"port": null
},
{
"type": "ip_literal",
"host": "::1",
"port": 27018
},
{
"type": "hostname",
"host": "example.com",
"port": 27019
}
],
"auth": null,
"options": null
},
{
"description": "UTF-8 hosts",
"uri": "mongodb://b\u00fccher.example.com,uml\u00e4ut.example.com/",
"valid": true,
"warning": false,
"hosts": [
{
"type": "hostname",
"host": "b\u00fccher.example.com",
"port": null
},
{
"type": "hostname",
"host": "uml\u00e4ut.example.com",
"port": null
}
],
"auth": null,
"options": null
}
]
}

View File

@ -1,42 +1,25 @@
{
"tests": [
"tests": [
{
"description": "Option names are normalized to lowercase",
"uri": "mongodb://alice:secret@example.com/admin?AUTHMechanism=MONGODB-CR",
"valid": true,
"warning": false,
"hosts": [
{
"auth": {
"db": "admin",
"password": "secret",
"username": "alice"
},
"description": "Option names are normalized to lowercase",
"hosts": [
{
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": {
"authmechanism": "MONGODB-CR"
},
"uri": "mongodb://alice:secret@example.com/admin?AUTHMechanism=MONGODB-CR",
"valid": true,
"warning": false
},
{
"auth": null,
"description": "Option key and value (escaped null bytes)",
"hosts": [
{
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": {
"replicaset": "my\u0000rs"
},
"uri": "mongodb://example.com/?replicaSet=my%00rs",
"valid": true,
"warning": false
"type": "hostname",
"host": "example.com",
"port": null
}
]
],
"auth": {
"username": "alice",
"password": "secret",
"db": "admin"
},
"options": {
"authmechanism": "MONGODB-CR"
}
}
]
}

View File

@ -175,11 +175,11 @@
},
{
"auth": {
"db": "admin.sock",
"db": "admin",
"password": null,
"username": null
},
"description": "Multiple Unix domain sockets and auth DB resembling a socket (absolute path)",
"description": "Multiple Unix domain sockets and auth DB (absolute path)",
"hosts": [
{
"host": "/tmp/mongodb-27017.sock",
@ -193,17 +193,17 @@
}
],
"options": null,
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/admin.sock",
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/admin",
"valid": true,
"warning": false
},
{
"auth": {
"db": "admin.shoe",
"db": "admin",
"password": null,
"username": null
},
"description": "Multiple Unix domain sockets with auth DB resembling a path (absolute path)",
"description": "Multiple Unix domain sockets with auth DB (absolute path)",
"hosts": [
{
"host": "/tmp/mongodb-27017.sock",
@ -217,7 +217,7 @@
}
],
"options": null,
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/admin.shoe",
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/admin",
"valid": true,
"warning": false
},

View File

@ -195,7 +195,7 @@
},
{
"auth": {
"db": "admin.sock",
"db": "admin",
"password": null,
"username": null
},
@ -213,13 +213,13 @@
}
],
"options": null,
"uri": "mongodb://rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock/admin.sock",
"uri": "mongodb://rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock/admin",
"valid": true,
"warning": false
},
{
"auth": {
"db": "admin.shoe",
"db": "admin",
"password": null,
"username": null
},
@ -237,7 +237,7 @@
}
],
"options": null,
"uri": "mongodb://rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock/admin.shoe",
"uri": "mongodb://rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock/admin",
"valid": true,
"warning": false
},

View File

@ -1,68 +1,68 @@
{
"tests": [
"tests": [
{
"description": "Unrecognized option keys are ignored",
"uri": "mongodb://example.com/?foo=bar",
"valid": true,
"warning": true,
"hosts": [
{
"auth": null,
"description": "Unrecognized option keys are ignored",
"hosts": [
{
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://example.com/?foo=bar",
"valid": true,
"warning": true
},
{
"auth": null,
"description": "Unsupported option values are ignored",
"hosts": [
{
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": null,
"uri": "mongodb://example.com/?fsync=ifPossible",
"valid": true,
"warning": true
},
{
"auth": null,
"description": "Repeated option keys",
"hosts": [
{
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": {
"replicaset": "test"
},
"uri": "mongodb://example.com/?replicaSet=test&replicaSet=test",
"valid": true,
"warning": true
},
{
"auth": null,
"description": "Deprecated (or unknown) options are ignored if replacement exists",
"hosts": [
{
"host": "example.com",
"port": null,
"type": "hostname"
}
],
"options": {
"wtimeoutms": 10
},
"uri": "mongodb://example.com/?wtimeout=5&wtimeoutMS=10",
"valid": true,
"warning": true
"type": "hostname",
"host": "example.com",
"port": null
}
]
}
],
"auth": null,
"options": null
},
{
"description": "Unsupported option values are ignored",
"uri": "mongodb://example.com/?fsync=ifPossible",
"valid": true,
"warning": true,
"hosts": [
{
"type": "hostname",
"host": "example.com",
"port": null
}
],
"auth": null,
"options": null
},
{
"description": "Repeated option keys",
"uri": "mongodb://example.com/?replicaSet=test&replicaSet=test",
"valid": true,
"warning": true,
"hosts": [
{
"type": "hostname",
"host": "example.com",
"port": null
}
],
"auth": null,
"options": {
"replicaset": "test"
}
},
{
"description": "Deprecated (or unknown) options are ignored if replacement exists",
"uri": "mongodb://example.com/?wtimeout=5&wtimeoutMS=10",
"valid": true,
"warning": true,
"hosts": [
{
"type": "hostname",
"host": "example.com",
"port": null
}
],
"auth": null,
"options": {
"wtimeoutms": 10
}
}
]
}

View File

@ -331,6 +331,12 @@ class TestURI(unittest.TestCase):
parse_uri("mongodb://fred:foobar@localhost/"
"test.yield_historical.in"))
res = copy.deepcopy(orig)
res['database'] = 'test'
res['collection'] = 'name/with "delimiters'
self.assertEqual(
res, parse_uri("mongodb://localhost/test.name/with \"delimiters"))
res = copy.deepcopy(orig)
res['options'] = {'readpreference': ReadPreference.SECONDARY.mode}
self.assertEqual(res, parse_uri(
@ -446,6 +452,30 @@ class TestURI(unittest.TestCase):
for key in res['options']:
self.assertTrue(isinstance(key, str))
def test_parse_ssl_paths(self):
# Turn off "validate" since these paths don't exist on filesystem.
self.assertEqual(
{'collection': None,
'database': None,
'nodelist': [('/MongoDB.sock', None)],
'options': {'ssl_certfile': '/a/b'},
'password': 'foo/bar',
'username': 'jesse'},
parse_uri(
'mongodb://jesse:foo%2Fbar@%2FMongoDB.sock/?ssl_certfile=/a/b',
validate=False))
self.assertEqual(
{'collection': None,
'database': None,
'nodelist': [('/MongoDB.sock', None)],
'options': {'ssl_certfile': 'a/b'},
'password': 'foo/bar',
'username': 'jesse'},
parse_uri(
'mongodb://jesse:foo%2Fbar@%2FMongoDB.sock/?ssl_certfile=a/b',
validate=False))
if __name__ == "__main__":
unittest.main()