From e42897e79e2c84733f81a893cec61960f83595b5 Mon Sep 17 00:00:00 2001 From: Bernie Hackett Date: Wed, 29 Nov 2017 10:52:05 -0800 Subject: [PATCH] PYTHON-1418 - More spec updates --- pymongo/mongo_client.py | 6 +++-- pymongo/uri_parser.py | 10 ++++++++ test/dns/longer-parent-in-return.json | 4 +++ test/dns/misformatted-option.json | 7 ++++++ test/dns/one-result-default-port.json | 6 ++++- test/dns/one-txt-record-multiple-strings.json | 5 ++-- test/dns/one-txt-record.json | 6 ++--- test/dns/parent-part-mismatch5.json | 7 ++++++ test/dns/returned-parent-wrong.json | 7 ++++++ test/dns/two-results-default-port.json | 6 ++++- test/dns/two-results-nonstandard-port.json | 6 ++++- test/dns/two-txt-records.json | 19 ++++---------- ...-record-with-listable-option-override.json | 25 ------------------- ...xt-record-with-overridden-uri-option.json} | 6 ++--- .../dns/txt-record-with-unallowed-option.json | 7 ++++++ test/dns/txt-record-wrong-value-type.json | 7 ------ test/test_dns.py | 7 ++++-- 17 files changed, 79 insertions(+), 62 deletions(-) create mode 100644 test/dns/misformatted-option.json create mode 100644 test/dns/parent-part-mismatch5.json create mode 100644 test/dns/returned-parent-wrong.json delete mode 100644 test/dns/txt-record-with-listable-option-override.json rename test/dns/{two-txt-records-with-override.json => txt-record-with-overridden-uri-option.json} (55%) create mode 100644 test/dns/txt-record-with-unallowed-option.json delete mode 100644 test/dns/txt-record-wrong-value-type.json diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index 75b308393..e21129e7e 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -133,12 +133,14 @@ class MongoClient(common.BaseObject): resolved to one or more DNS `SRV records `_ which will be used as the seed list for connecting to the MongoDB deployment. When using - SRV support configuration options can be specified using `TXT records + SRV URIs, the `authSource` and `replicaSet` configuration options can + be specified using `TXT records `_. See the `Initial DNS Seedlist Discovery spec `_ - for more details. + for more details. Note that the use of SRV URIs implicitly enables + TLS support. Pass ssl=false in the URI to override. .. note:: MongoClient creation will block waiting for answers from DNS when mongodb+srv:// URIs are used. diff --git a/pymongo/uri_parser.py b/pymongo/uri_parser.py index b3f7b0ff6..df8c8d58e 100644 --- a/pymongo/uri_parser.py +++ b/pymongo/uri_parser.py @@ -278,6 +278,10 @@ else: return text +_ALLOWED_TXT_OPTS = frozenset( + ['authsource', 'authSource', 'replicaset', 'replicaSet']) + + def _get_dns_srv_hosts(hostname): try: results = resolver.query('_mongodb._tcp.' + hostname, 'SRV') @@ -295,6 +299,8 @@ def _get_dns_txt_options(hostname): return None except Exception as exc: raise ConfigurationError(str(exc)) + if len(results) > 1: + raise ConfigurationError('Only one TXT record is supported') return ( b'&'.join([b''.join(res.strings) for res in results])).decode('utf-8') @@ -410,6 +416,10 @@ def parse_uri(uri, default_port=DEFAULT_PORT, validate=True, warn=False): dns_options = _get_dns_txt_options(fqdn) if dns_options: options = split_options(dns_options, validate, warn) + if set(options) - _ALLOWED_TXT_OPTS: + raise ConfigurationError( + "Only authSource and replicaSet are supported from DNS") + options["ssl"] = True if validate else 'true' else: nodes = split_hosts(hosts, default_port=default_port) diff --git a/test/dns/longer-parent-in-return.json b/test/dns/longer-parent-in-return.json index c0979a825..9a8267eae 100644 --- a/test/dns/longer-parent-in-return.json +++ b/test/dns/longer-parent-in-return.json @@ -8,5 +8,9 @@ "localhost:27018", "localhost:27019" ], + "options": { + "replicaSet": "repl0", + "ssl": true + }, "comment": "Is correct, as returned host name shared the URI root \"test.build.10gen.cc\"." } diff --git a/test/dns/misformatted-option.json b/test/dns/misformatted-option.json new file mode 100644 index 000000000..3c8c29ace --- /dev/null +++ b/test/dns/misformatted-option.json @@ -0,0 +1,7 @@ +{ + "uri": "mongodb+srv://test8.test.build.10gen.cc/", + "seeds": [], + "hosts": [], + "error": true, + "comment": "Should fail because the options in the TXT record are incorrectly formatted (misses value)." +} diff --git a/test/dns/one-result-default-port.json b/test/dns/one-result-default-port.json index 7946daa4b..cebb3b1ec 100644 --- a/test/dns/one-result-default-port.json +++ b/test/dns/one-result-default-port.json @@ -7,5 +7,9 @@ "localhost:27017", "localhost:27018", "localhost:27019" - ] + ], + "options": { + "replicaSet": "repl0", + "ssl": true + } } diff --git a/test/dns/one-txt-record-multiple-strings.json b/test/dns/one-txt-record-multiple-strings.json index 78017687e..622668c35 100644 --- a/test/dns/one-txt-record-multiple-strings.json +++ b/test/dns/one-txt-record-multiple-strings.json @@ -1,5 +1,5 @@ { - "uri": "mongodb+srv://test11.test.build.10gen.cc/?replicaSet=repl0", + "uri": "mongodb+srv://test11.test.build.10gen.cc/", "seeds": [ "localhost.test.build.10gen.cc:27017" ], @@ -9,8 +9,7 @@ "localhost:27019" ], "options": { - "connectTimeoutMS": 150000, "replicaSet": "repl0", - "socketTimeoutMS": 250000 + "ssl": true } } diff --git a/test/dns/one-txt-record.json b/test/dns/one-txt-record.json index 0833cb4ec..2385021ad 100644 --- a/test/dns/one-txt-record.json +++ b/test/dns/one-txt-record.json @@ -1,5 +1,5 @@ { - "uri": "mongodb+srv://test5.test.build.10gen.cc/?replicaSet=repl0", + "uri": "mongodb+srv://test5.test.build.10gen.cc/", "seeds": [ "localhost.test.build.10gen.cc:27017" ], @@ -9,8 +9,8 @@ "localhost:27019" ], "options": { - "connectTimeoutMS": 300000, "replicaSet": "repl0", - "socketTimeoutMS": 300000 + "authSource": "thisDB", + "ssl": true } } diff --git a/test/dns/parent-part-mismatch5.json b/test/dns/parent-part-mismatch5.json new file mode 100644 index 000000000..92c024b4f --- /dev/null +++ b/test/dns/parent-part-mismatch5.json @@ -0,0 +1,7 @@ +{ + "uri": "mongodb+srv://test19.test.build.10gen.cc/", + "seeds": [], + "hosts": [], + "error": true, + "comment": "Should fail because one of the returned host names' domain name parts \"evil\" mismatches \"test\"." +} diff --git a/test/dns/returned-parent-wrong.json b/test/dns/returned-parent-wrong.json new file mode 100644 index 000000000..3aabfd819 --- /dev/null +++ b/test/dns/returned-parent-wrong.json @@ -0,0 +1,7 @@ +{ + "uri": "mongodb+srv://test12.test.build.10gen.cc/", + "seeds": [], + "hosts": [], + "error": true, + "comment": "Should fail because returned host name is too short and mismatches a parent." +} diff --git a/test/dns/two-results-default-port.json b/test/dns/two-results-default-port.json index b31800f7e..66028310a 100644 --- a/test/dns/two-results-default-port.json +++ b/test/dns/two-results-default-port.json @@ -8,5 +8,9 @@ "localhost:27017", "localhost:27018", "localhost:27019" - ] + ], + "options": { + "replicaSet": "repl0", + "ssl": true + } } diff --git a/test/dns/two-results-nonstandard-port.json b/test/dns/two-results-nonstandard-port.json index 2ccaa5b20..4900f7cff 100644 --- a/test/dns/two-results-nonstandard-port.json +++ b/test/dns/two-results-nonstandard-port.json @@ -8,5 +8,9 @@ "localhost:27017", "localhost:27018", "localhost:27019" - ] + ], + "options": { + "replicaSet": "repl0", + "ssl": true + } } diff --git a/test/dns/two-txt-records.json b/test/dns/two-txt-records.json index 21d1b395f..f0654ef6c 100644 --- a/test/dns/two-txt-records.json +++ b/test/dns/two-txt-records.json @@ -1,16 +1,7 @@ { - "uri": "mongodb+srv://test6.test.build.10gen.cc/?replicaSet=repl0", - "seeds": [ - "localhost.test.build.10gen.cc:27017" - ], - "hosts": [ - "localhost:27017", - "localhost:27018", - "localhost:27019" - ], - "options": { - "connectTimeoutMS": 200000, - "replicaSet": "repl0", - "socketTimeoutMS": 200000 - } + "uri": "mongodb+srv://test6.test.build.10gen.cc/", + "seeds": [], + "hosts": [], + "error": true, + "comment": "Should fail because there are two TXT records." } diff --git a/test/dns/txt-record-with-listable-option-override.json b/test/dns/txt-record-with-listable-option-override.json deleted file mode 100644 index d3b106240..000000000 --- a/test/dns/txt-record-with-listable-option-override.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "uri": "mongodb+srv://test7.test.build.10gen.cc/?replicaSet=repl0&readPreferenceTags=dc:fr,item:cheese&readPreferenceTags=dc:de,item:hotdog", - "seeds": [ - "localhost.test.build.10gen.cc:27017" - ], - "hosts": [ - "localhost:27017", - "localhost:27018", - "localhost:27019" - ], - "options": { - "replicaSet": "repl0", - "readPreference": "secondaryPreferred", - "readPreferenceTags": [ - { - "dc": "fr", - "item": "cheese" - }, - { - "dc": "de", - "item": "hotdog" - } - ] - } -} diff --git a/test/dns/two-txt-records-with-override.json b/test/dns/txt-record-with-overridden-uri-option.json similarity index 55% rename from test/dns/two-txt-records-with-override.json rename to test/dns/txt-record-with-overridden-uri-option.json index a02168db0..2626ba608 100644 --- a/test/dns/two-txt-records-with-override.json +++ b/test/dns/txt-record-with-overridden-uri-option.json @@ -1,5 +1,5 @@ { - "uri": "mongodb+srv://test6.test.build.10gen.cc/?replicaSet=repl0&connectTimeoutMS=250000", + "uri": "mongodb+srv://test5.test.build.10gen.cc/?authSource=otherDB", "seeds": [ "localhost.test.build.10gen.cc:27017" ], @@ -9,8 +9,8 @@ "localhost:27019" ], "options": { - "connectTimeoutMS": 250000, "replicaSet": "repl0", - "socketTimeoutMS": 200000 + "authSource": "otherDB", + "ssl": true } } diff --git a/test/dns/txt-record-with-unallowed-option.json b/test/dns/txt-record-with-unallowed-option.json new file mode 100644 index 000000000..0d333a459 --- /dev/null +++ b/test/dns/txt-record-with-unallowed-option.json @@ -0,0 +1,7 @@ +{ + "uri": "mongodb+srv://test7.test.build.10gen.cc/", + "seeds": [], + "hosts": [], + "error": true, + "comment": "Should fail because \"ssl\" is not an allowed option." +} diff --git a/test/dns/txt-record-wrong-value-type.json b/test/dns/txt-record-wrong-value-type.json deleted file mode 100644 index 897054f10..000000000 --- a/test/dns/txt-record-wrong-value-type.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "uri": "mongodb+srv://test10.test.build.10gen.cc/?replicaSet=repl0", - "seeds": [], - "hosts": [], - "error": true, - "comment": "Should fail because the value of socketTimeoutMS is not an integer." -} diff --git a/test/test_dns.py b/test/test_dns.py index 5721b6e5d..fa15fcbc8 100644 --- a/test/test_dns.py +++ b/test/test_dns.py @@ -44,6 +44,7 @@ class TestDNS(unittest.TestCase): def create_test(test_case): @client_context.require_replica_set + @client_context.require_ssl def run_test(self): if not _HAVE_DNSPYTHON: raise unittest.SkipTest("DNS tests require the dnspython module") @@ -57,8 +58,10 @@ def create_test(test_case): hosts = frozenset(split_hosts(','.join(hosts))) if options: for key, value in options.items(): - # Convert numbers to strings for comparison - if isinstance(value, (int, float)): + # Convert numbers / booleans to strings for comparison + if isinstance(value, bool): + options[key] = 'true' if value else 'false' + elif isinstance(value, (int, float)): options[key] = str(value) if seeds: