PYTHON-751 Move all auth tests to the test_auth module.

This commit is contained in:
Luke Lovett 2014-08-18 18:18:28 +00:00
parent 33d0c702a5
commit 7decdd8a40
25 changed files with 950 additions and 806 deletions

View File

@ -19,7 +19,8 @@ import os
import warnings
import pymongo
from pymongo.errors import ConnectionFailure
from nose.plugins.skip import SkipTest
from pymongo.errors import OperationFailure
# hostnames retrieved by MongoReplicaSetClient from isMaster will be of unicode
# type in Python 2, so ensure these hostnames are unicodes, too. It makes tests
@ -34,6 +35,66 @@ port2 = int(os.environ.get("DB_PORT2", 27018))
host3 = unicode(os.environ.get("DB_IP3", 'localhost'))
port3 = int(os.environ.get("DB_PORT3", 27019))
db_user = unicode(os.environ.get("DB_USER", "administrator"))
db_pwd = unicode(os.environ.get("DB_PWD", "password"))
class AuthContext(object):
def __init__(self):
self.client = pymongo.MongoClient(host, port)
self.auth_enabled = False
self.restricted_localhost = False
try:
command_line = self.client.admin.command('getCmdLineOpts')
if self._server_started_with_auth(command_line):
self.auth_enabled = True
except OperationFailure, e:
if e.code == 13:
self.auth_enabled = True
self.restricted_localhost = True
else:
raise
def _server_started_with_auth(self, command_line):
# MongoDB >= 2.0
if 'parsed' in command_line:
parsed = command_line['parsed']
# MongoDB >= 2.6
if 'security' in parsed:
security = parsed['security']
if 'authorization' in security:
return security['authorization'] == 'enabled'
return security.get('auth', bool(security.get('keyFile')))
return parsed.get('auth', bool(parsed.get('keyFile')))
# Legacy
argv = command_line['argv']
return '--auth' in argv or '--keyFile' in argv
def add_user_and_log_in(self):
self.client.admin.add_user(db_user, db_pwd,
roles=('userAdminAnyDatabase',
'readWriteAnyDatabase',
'dbAdminAnyDatabase',
'clusterAdmin'))
self.client.admin.authenticate(db_user, db_pwd)
def remove_user_and_log_out(self):
self.client.admin.remove_user(db_user)
self.client.admin.logout()
self.client.disconnect()
auth_context = AuthContext()
def skip_restricted_localhost():
"""Skip tests when the localhost exception is restricted (SERVER-12621)."""
if auth_context.restricted_localhost:
raise SkipTest("Cannot test with restricted localhost exception "
"(SERVER-12621).")
# Make sure warnings are always raised, regardless of
# python version.
def setup():
@ -42,16 +103,16 @@ def setup():
def teardown():
try:
c = pymongo.MongoClient(host, port)
except ConnectionFailure:
# Tests where ssl=True can cause connection failures here.
# Ignore and continue.
return
client = auth_context.client
if auth_context.auth_enabled:
auth_context.add_user_and_log_in()
c.drop_database("pymongo-pooling-tests")
c.drop_database("pymongo_test")
c.drop_database("pymongo_test1")
c.drop_database("pymongo_test2")
c.drop_database("pymongo_test_mike")
c.drop_database("pymongo_test_bernie")
client.drop_database("pymongo-pooling-tests")
client.drop_database("pymongo_test")
client.drop_database("pymongo_test1")
client.drop_database("pymongo_test2")
client.drop_database("pymongo_test_mike")
client.drop_database("pymongo_test_bernie")
if auth_context.auth_enabled:
auth_context.remove_user_and_log_out()

View File

@ -15,9 +15,11 @@
"""Authentication Tests."""
import os
import socket
import sys
import threading
import unittest
import warnings
from urllib import quote_plus
@ -25,12 +27,28 @@ sys.path[0:0] = [""]
from nose.plugins.skip import SkipTest
from pymongo import MongoClient, MongoReplicaSetClient
from pymongo import (MongoClient,
MongoReplicaSetClient,
auth)
from pymongo.auth import HAVE_KERBEROS
from pymongo.errors import OperationFailure, ConfigurationError
from pymongo.errors import (OperationFailure,
ConfigurationError,
ConnectionFailure,
AutoReconnect)
from pymongo.read_preferences import ReadPreference
from test import version, host, port
from test.utils import is_mongos, server_started_with_auth
from test import version, host, port, pair, auth_context
from test.test_bulk import BulkTestBase
from test.test_client import get_client
from test.test_pooling_base import get_pool
from test.test_replica_set_client import TestReplicaSetClientBase
from test.test_threads import AutoAuthenticateThreads
from test.utils import (is_mongos,
remove_all_users,
assertRaisesExactly,
one,
catch_warnings,
TestRequestMixin,
joinall)
# YOU MUST RUN KINIT BEFORE RUNNING GSSAPI TESTS.
GSSAPI_HOST = os.environ.get('GSSAPI_HOST')
@ -44,6 +62,20 @@ SASL_PASS = os.environ.get('SASL_PASS')
SASL_DB = os.environ.get('SASL_DB', '$external')
def setUpModule():
if not auth_context.auth_enabled:
raise SkipTest("Server not started with --auth.")
if (is_mongos(auth_context.client) and
not version.at_least(auth_context.client, (2, 0, 0))):
raise SkipTest("Auth with sharding requires MongoDB >= 2.0.0")
auth_context.add_user_and_log_in()
def tearDownModule():
if auth_context.auth_enabled:
auth_context.remove_user_and_log_out()
class AutoAuthenticateThread(threading.Thread):
"""Used in testing threaded authentication.
"""
@ -230,17 +262,13 @@ class TestAuthURIOptions(unittest.TestCase):
def setUp(self):
client = MongoClient(host, port)
# Sharded auth not supported before MongoDB 2.0
if is_mongos(client) and not version.at_least(client, (2, 0, 0)):
raise SkipTest("Auth with sharding requires MongoDB >= 2.0.0")
if not server_started_with_auth(client):
raise SkipTest('Authentication is not enabled on server')
response = client.admin.command('ismaster')
self.set_name = str(response.get('setName', ''))
client.admin.add_user('admin', 'pass', roles=['userAdminAnyDatabase',
'dbAdminAnyDatabase',
'readWriteAnyDatabase',
'clusterAdmin'])
auth_context.client.admin.add_user('admin', 'pass',
roles=['userAdminAnyDatabase',
'dbAdminAnyDatabase',
'readWriteAnyDatabase',
'clusterAdmin'])
client.admin.authenticate('admin', 'pass')
client.pymongo_test.add_user('user', 'pass',
roles=['userAdmin', 'readWrite'])
@ -314,19 +342,18 @@ class TestDelegatedAuth(unittest.TestCase):
def setUp(self):
self.client = MongoClient(host, port)
if not version.at_least(self.client, (2, 4, 0)):
authed_client = auth_context.client
if not version.at_least(authed_client, (2, 4, 0)):
raise SkipTest('Delegated authentication requires MongoDB >= 2.4.0')
if not server_started_with_auth(self.client):
raise SkipTest('Authentication is not enabled on server')
if version.at_least(self.client, (2, 5, 3, -1)):
if version.at_least(authed_client, (2, 5, 3, -1)):
raise SkipTest('Delegated auth does not exist in MongoDB >= 2.5.3')
# Give admin all privileges.
self.client.admin.add_user('admin', 'pass',
roles=['readAnyDatabase',
'readWriteAnyDatabase',
'userAdminAnyDatabase',
'dbAdminAnyDatabase',
'clusterAdmin'])
authed_client.admin.add_user('admin', 'pass',
roles=['readAnyDatabase',
'readWriteAnyDatabase',
'userAdminAnyDatabase',
'dbAdminAnyDatabase',
'clusterAdmin'])
def tearDown(self):
self.client.admin.authenticate('admin', 'pass')
@ -370,5 +397,730 @@ class TestDelegatedAuth(unittest.TestCase):
self.client.pymongo_test2.foo.find_one)
class TestClientAuth(unittest.TestCase):
def test_copy_db(self):
authed_client = auth_context.client
if is_mongos(authed_client):
raise SkipTest("SERVER-6427")
c = MongoClient(host, port)
authed_client.admin.add_user("admin", "password")
c.admin.authenticate("admin", "password")
c.drop_database("pymongo_test1")
c.pymongo_test.test.insert({"foo": "bar"})
try:
c.pymongo_test.add_user("mike", "password")
self.assertRaises(OperationFailure, c.copy_database,
"pymongo_test", "pymongo_test1",
username="foo", password="bar")
self.assertFalse("pymongo_test1" in c.database_names())
self.assertRaises(OperationFailure, c.copy_database,
"pymongo_test", "pymongo_test1",
username="mike", password="bar")
self.assertFalse("pymongo_test1" in c.database_names())
c.copy_database("pymongo_test", "pymongo_test1",
username="mike", password="password")
self.assertTrue("pymongo_test1" in c.database_names())
self.assertEqual("bar", c.pymongo_test1.test.find_one()["foo"])
finally:
# Cleanup
remove_all_users(c.pymongo_test)
c.admin.remove_user("admin")
c.disconnect()
def test_auth_from_uri(self):
c = MongoClient(host, port)
auth_context.client.admin.add_user("admin", "pass")
c.admin.authenticate("admin", "pass")
try:
c.pymongo_test.add_user("user", "pass",
roles=['userAdmin', 'readWrite'])
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://foo:bar@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://admin:bar@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://user:pass@%s:%d" % (host, port))
MongoClient("mongodb://admin:pass@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://admin:pass@%s:%d/pymongo_test" %
(host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://user:foo@%s:%d/pymongo_test" %
(host, port))
MongoClient("mongodb://user:pass@%s:%d/pymongo_test" %
(host, port))
# Auth with lazy connection.
MongoClient(
"mongodb://user:pass@%s:%d/pymongo_test" % (host, port),
_connect=False).pymongo_test.test.find_one()
# Wrong password.
bad_client = MongoClient(
"mongodb://user:wrong@%s:%d/pymongo_test" % (host, port),
_connect=False)
self.assertRaises(OperationFailure,
bad_client.pymongo_test.test.find_one)
finally:
# Clean up.
remove_all_users(c.pymongo_test)
c.admin.remove_user('admin')
def test_lazy_auth_raises_operation_failure(self):
lazy_client = MongoClient(
"mongodb://user:wrong@%s:%d/pymongo_test" % (host, port),
_connect=False)
assertRaisesExactly(
OperationFailure, lazy_client.test.collection.find_one)
def test_unix_socket(self):
authed_client = auth_context.client
if not hasattr(socket, "AF_UNIX"):
raise SkipTest("UNIX-sockets are not supported on this system")
if (sys.platform == 'darwin' and
not version.at_least(authed_client, (2, 7, 1))):
raise SkipTest("SERVER-8492")
mongodb_socket = '/tmp/mongodb-27017.sock'
if not os.access(mongodb_socket, os.R_OK):
raise SkipTest("Socket file is not accessable")
self.assertTrue(MongoClient("mongodb://%s" % mongodb_socket))
authed_client.admin.add_user('admin', 'pass')
try:
client = MongoClient("mongodb://%s" % mongodb_socket)
client.admin.authenticate('admin', 'pass')
client.pymongo_test.test.save({"dummy": "object"})
# Confirm we can read via the socket
dbs = client.database_names()
self.assertTrue("pymongo_test" in dbs)
# Confirm it fails with a missing socket
self.assertRaises(ConnectionFailure, MongoClient,
"mongodb:///tmp/none-existent.sock")
finally:
authed_client.admin.remove_user('admin')
def test_auth_network_error(self):
# Make sure there's no semaphore leak if we get a network error
# when authenticating a new socket with cached credentials.
auth_client = get_client()
auth_context.client.admin.add_user('admin', 'password')
auth_client.admin.authenticate('admin', 'password')
try:
# Get a client with one socket so we detect if it's leaked.
c = get_client(max_pool_size=1, waitQueueTimeoutMS=1)
# Simulate an authenticate() call on a different socket.
credentials = auth._build_credentials_tuple(
'MONGODB-CR', 'admin',
unicode('admin'), unicode('password'),
{})
c._cache_credentials('test', credentials, connect=False)
# Cause a network error on the actual socket.
pool = get_pool(c)
socket_info = one(pool.sockets)
socket_info.sock.close()
# In __check_auth, the client authenticates its socket with the
# new credential, but gets a socket.error. Should be reraised as
# AutoReconnect.
self.assertRaises(AutoReconnect, c.test.collection.find_one)
# No semaphore leak, the pool is allowed to make a new socket.
c.test.collection.find_one()
finally:
auth_client.admin.remove_user('admin')
class TestDatabaseAuth(unittest.TestCase):
def setUp(self):
self.client = MongoClient(host, port)
def test_authenticate_add_remove_user(self):
authed_client = auth_context.client
db = authed_client.pymongo_test
# Configuration errors
self.assertRaises(ValueError, db.add_user, "user", '')
self.assertRaises(TypeError, db.add_user, "user", 'password', 15)
self.assertRaises(ConfigurationError, db.add_user,
"user", 'password', 'True')
self.assertRaises(ConfigurationError, db.add_user,
"user", 'password', True, roles=['read'])
if version.at_least(authed_client, (2, 5, 3, -1)):
ctx = catch_warnings()
try:
warnings.simplefilter("error", DeprecationWarning)
self.assertRaises(DeprecationWarning, db.add_user,
"user", "password")
self.assertRaises(DeprecationWarning, db.add_user,
"user", "password", True)
finally:
ctx.exit()
self.assertRaises(ConfigurationError, db.add_user,
"user", "password", digestPassword=True)
authed_client.admin.add_user("admin", "password")
self.client.admin.authenticate("admin", "password")
db = self.client.pymongo_test
try:
# Add / authenticate / remove
db.add_user("mike", "password")
self.assertRaises(TypeError, db.authenticate, 5, "password")
self.assertRaises(TypeError, db.authenticate, "mike", 5)
self.assertRaises(OperationFailure,
db.authenticate, "mike", "not a real password")
self.assertRaises(OperationFailure,
db.authenticate, "faker", "password")
self.assertTrue(db.authenticate("mike", "password"))
db.logout()
self.assertTrue(db.authenticate(u"mike", u"password"))
db.remove_user("mike")
db.logout()
self.assertRaises(OperationFailure,
db.authenticate, "mike", "password")
# Add / authenticate / change password
self.assertRaises(OperationFailure,
db.authenticate, "Gustave", u"Dor\xe9")
db.add_user("Gustave", u"Dor\xe9")
self.assertTrue(db.authenticate("Gustave", u"Dor\xe9"))
db.add_user("Gustave", "password")
db.logout()
self.assertRaises(OperationFailure,
db.authenticate, "Gustave", u"Dor\xe9")
self.assertTrue(db.authenticate("Gustave", u"password"))
if not version.at_least(authed_client, (2, 5, 3, -1)):
# Add a readOnly user
db.add_user("Ross", "password", read_only=True)
db.logout()
self.assertTrue(db.authenticate("Ross", u"password"))
self.assertTrue(
db.system.users.find({"readOnly": True}).count())
db.logout()
# Cleanup
finally:
remove_all_users(db)
self.client.admin.remove_user("admin")
self.client.admin.logout()
def test_make_user_readonly(self):
admin = self.client.admin
auth_context.client.admin.add_user('admin', 'pw')
admin.authenticate('admin', 'pw')
db = self.client.pymongo_test
try:
# Make a read-write user.
db.add_user('jesse', 'pw')
admin.logout()
# Check that we're read-write by default.
db.authenticate('jesse', 'pw')
db.collection.insert({})
db.logout()
# Make the user read-only.
admin.authenticate('admin', 'pw')
db.add_user('jesse', 'pw', read_only=True)
admin.logout()
db.authenticate('jesse', 'pw')
self.assertRaises(OperationFailure, db.collection.insert, {})
finally:
# Cleanup
admin.authenticate('admin', 'pw')
remove_all_users(db)
admin.remove_user("admin")
admin.logout()
def test_default_roles(self):
authed_client = auth_context.client
if not version.at_least(authed_client, (2, 5, 3, -1)):
raise SkipTest("Default roles only exist in MongoDB >= 2.5.3")
# "Admin" user
db = self.client.admin
authed_client.admin.add_user('admin', 'pass')
try:
db.authenticate('admin', 'pass')
info = db.command('usersInfo', 'admin')['users'][0]
self.assertEqual("root", info['roles'][0]['role'])
# Read only "admin" user
db.add_user('ro-admin', 'pass', read_only=True)
db.logout()
db.authenticate('ro-admin', 'pass')
info = db.command('usersInfo', 'ro-admin')['users'][0]
self.assertEqual("readAnyDatabase", info['roles'][0]['role'])
db.logout()
# Cleanup
finally:
db.authenticate('admin', 'pass')
db.remove_user('ro-admin')
db.remove_user('admin')
db.logout()
db.connection.disconnect()
# "Non-admin" user
db = self.client.pymongo_test
authed_client.pymongo_test.add_user('user', 'pass')
try:
db.authenticate('user', 'pass')
info = db.command('usersInfo', 'user')['users'][0]
self.assertEqual("dbOwner", info['roles'][0]['role'])
# Read only "Non-admin" user
db.add_user('ro-user', 'pass', read_only=True)
db.logout()
db.authenticate('ro-user', 'pass')
info = db.command('usersInfo', 'ro-user')['users'][0]
self.assertEqual("read", info['roles'][0]['role'])
db.logout()
# Cleanup
finally:
db.authenticate('user', 'pass')
remove_all_users(db)
db.logout()
def test_new_user_cmds(self):
authed_client = auth_context.client
if not version.at_least(authed_client, (2, 5, 3, -1)):
raise SkipTest("User manipulation through commands "
"requires MongoDB >= 2.5.3")
db = self.client.pymongo_test
authed_client.pymongo_test.add_user("amalia", "password",
roles=["userAdmin"])
db.authenticate("amalia", "password")
try:
# This tests the ability to update user attributes.
db.add_user("amalia", "new_password",
customData={"secret": "koalas"})
user_info = db.command("usersInfo", "amalia")
self.assertTrue(user_info["users"])
amalia_user = user_info["users"][0]
self.assertEqual(amalia_user["user"], "amalia")
self.assertEqual(amalia_user["customData"], {"secret": "koalas"})
finally:
db.remove_user("amalia")
db.logout()
def test_authenticate_and_safe(self):
db = auth_context.client.auth_test
db.add_user("bernie", "password",
roles=["userAdmin", "dbAdmin", "readWrite"])
db.authenticate("bernie", "password")
try:
db.test.remove({})
self.assertTrue(db.test.insert({"bim": "baz"}))
self.assertEqual(1, db.test.count())
self.assertEqual(1,
db.test.update({"bim": "baz"},
{"$set": {"bim": "bar"}}).get('n'))
self.assertEqual(1,
db.test.remove({}).get('n'))
self.assertEqual(0, db.test.count())
finally:
db.remove_user("bernie")
db.logout()
def test_authenticate_and_request(self):
# Database.authenticate() needs to be in a request - check that it
# always runs in a request, and that it restores the request state
# (in or not in a request) properly when it's finished.
self.assertFalse(self.client.auto_start_request)
db = self.client.pymongo_test
auth_context.client.pymongo_test.add_user(
"mike", "password",
roles=["userAdmin", "dbAdmin", "readWrite"])
try:
self.assertFalse(self.client.in_request())
self.assertTrue(db.authenticate("mike", "password"))
self.assertFalse(self.client.in_request())
request_cx = get_client(auto_start_request=True)
request_db = request_cx.pymongo_test
self.assertTrue(request_db.authenticate("mike", "password"))
self.assertTrue(request_cx.in_request())
finally:
db.authenticate("mike", "password")
db.remove_user("mike")
db.logout()
request_db.logout()
def test_authenticate_multiple(self):
client = get_client()
authed_client = auth_context.client
if (is_mongos(authed_client) and not
version.at_least(authed_client, (2, 2, 0))):
raise SkipTest("Need mongos >= 2.2.0")
# Setup
authed_client.pymongo_test.test.drop()
authed_client.pymongo_test1.test.drop()
users_db = client.pymongo_test
admin_db = client.admin
other_db = client.pymongo_test1
authed_client.admin.add_user('admin', 'pass',
roles=["userAdminAnyDatabase", "dbAdmin",
"clusterAdmin", "readWrite"])
try:
self.assertTrue(admin_db.authenticate('admin', 'pass'))
if version.at_least(self.client, (2, 5, 3, -1)):
admin_db.add_user('ro-admin', 'pass',
roles=["userAdmin", "readAnyDatabase"])
else:
admin_db.add_user('ro-admin', 'pass', read_only=True)
users_db.add_user('user', 'pass',
roles=["userAdmin", "readWrite"])
admin_db.logout()
self.assertRaises(OperationFailure, users_db.test.find_one)
# Regular user should be able to query its own db, but
# no other.
users_db.authenticate('user', 'pass')
self.assertEqual(0, users_db.test.count())
self.assertRaises(OperationFailure, other_db.test.find_one)
# Admin read-only user should be able to query any db,
# but not write.
admin_db.authenticate('ro-admin', 'pass')
self.assertEqual(0, other_db.test.count())
self.assertRaises(OperationFailure,
other_db.test.insert, {})
# Force close all sockets
client.disconnect()
# We should still be able to write to the regular user's db
self.assertTrue(users_db.test.remove())
# And read from other dbs...
self.assertEqual(0, other_db.test.count())
# But still not write to other dbs...
self.assertRaises(OperationFailure,
other_db.test.insert, {})
# Cleanup
finally:
admin_db.logout()
users_db.logout()
admin_db.authenticate('admin', 'pass')
remove_all_users(users_db)
admin_db.remove_user('ro-admin')
admin_db.remove_user('admin')
class TestReplicaSetClientAuth(TestReplicaSetClientBase, TestRequestMixin):
def test_init_disconnected_with_auth_failure(self):
c = MongoReplicaSetClient(
"mongodb://user:pass@somedomainthatdoesntexist", replicaSet="rs",
connectTimeoutMS=1, _connect=False)
self.assertRaises(ConnectionFailure, c.pymongo_test.test.find_one)
def test_init_disconnected_with_auth(self):
c = self._get_client()
auth_context.client.admin.add_user("admin", "pass")
c.admin.authenticate("admin", "pass")
try:
c.pymongo_test.add_user("user", "pass",
roles=['readWrite', 'userAdmin'])
# Auth with lazy connection.
host = one(self.hosts)
uri = "mongodb://user:pass@%s:%d/pymongo_test?replicaSet=%s" % (
host[0], host[1], self.name)
authenticated_client = MongoReplicaSetClient(uri, _connect=False)
authenticated_client.pymongo_test.test.find_one()
# Wrong password.
bad_uri = ("mongodb://user:wrong@%s:%d/pymongo_test?replicaSet=%s"
% (host[0], host[1], self.name))
bad_client = MongoReplicaSetClient(bad_uri, _connect=False)
self.assertRaises(
OperationFailure, bad_client.pymongo_test.test.find_one)
finally:
# Clean up.
remove_all_users(c.pymongo_test)
c.admin.remove_user('admin')
def test_lazy_auth_raises_operation_failure(self):
lazy_client = MongoReplicaSetClient(
"mongodb://user:wrong@%s/pymongo_test" % pair,
replicaSet=self.name,
_connect=False)
assertRaisesExactly(
OperationFailure, lazy_client.test.collection.find_one)
def test_copy_db(self):
c = self._get_client()
auth_context.client.admin.add_user("admin", "password")
c.admin.authenticate("admin", "password")
c.drop_database("pymongo_test1")
c.pymongo_test.test.insert({"foo": "bar"})
try:
c.pymongo_test.add_user("mike", "password")
self.assertRaises(OperationFailure, c.copy_database,
"pymongo_test", "pymongo_test1",
username="foo", password="bar")
self.assertFalse("pymongo_test1" in c.database_names())
self.assertRaises(OperationFailure, c.copy_database,
"pymongo_test", "pymongo_test1",
username="mike", password="bar")
self.assertFalse("pymongo_test1" in c.database_names())
c.copy_database("pymongo_test", "pymongo_test1",
username="mike", password="password")
self.assertTrue("pymongo_test1" in c.database_names())
res = c.pymongo_test1.test.find_one(_must_use_master=True)
self.assertEqual("bar", res["foo"])
finally:
# Cleanup
remove_all_users(c.pymongo_test)
c.admin.remove_user("admin")
c.close()
def test_auth_network_error(self):
# Make sure there's no semaphore leak if we get a network error
# when authenticating a new socket with cached credentials.
auth_client = self._get_client()
auth_context.client.admin.add_user('admin', 'password')
auth_client.admin.authenticate('admin', 'password')
try:
# Get a client with one socket so we detect if it's leaked.
c = self._get_client(max_pool_size=1, waitQueueTimeoutMS=1)
# Simulate an authenticate() call on a different socket.
credentials = auth._build_credentials_tuple(
'MONGODB-CR', 'admin',
unicode('admin'), unicode('password'),
{})
c._cache_credentials('test', credentials, connect=False)
# Cause a network error on the actual socket.
pool = get_pool(c)
socket_info = one(pool.sockets)
socket_info.sock.close()
# In __check_auth, the client authenticates its socket with the
# new credential, but gets a socket.error. Should be reraised as
# AutoReconnect.
self.assertRaises(AutoReconnect, c.test.collection.find_one)
# No semaphore leak, the pool is allowed to make a new socket.
c.test.collection.find_one()
finally:
auth_client.admin.remove_user('admin')
class TestBulkAuthorization(BulkTestBase):
def setUp(self):
super(TestBulkAuthorization, self).setUp()
self.client = client = get_client()
authed_client = auth_context.client
if not version.at_least(authed_client, (2, 5, 3)):
raise SkipTest('Need at least MongoDB 2.5.3 with auth')
db = client.pymongo_test
self.coll = db.test
authed_client.pymongo_test.test.drop()
authed_client.pymongo_test.add_user('dbOwner', 'pw', roles=['dbOwner'])
db.authenticate('dbOwner', 'pw')
db.add_user('readonly', 'pw', roles=['read'])
db.command(
'createRole', 'noremove',
privileges=[{
'actions': ['insert', 'update', 'find'],
'resource': {'db': 'pymongo_test', 'collection': 'test'}
}],
roles=[])
db.add_user('noremove', 'pw', roles=['noremove'])
db.logout()
def test_readonly(self):
# We test that an authorization failure aborts the batch and is raised
# as OperationFailure.
db = self.client.pymongo_test
db.authenticate('readonly', 'pw')
bulk = self.coll.initialize_ordered_bulk_op()
bulk.insert({'x': 1})
self.assertRaises(OperationFailure, bulk.execute)
def test_no_remove(self):
# We test that an authorization failure aborts the batch and is raised
# as OperationFailure.
db = self.client.pymongo_test
db.authenticate('noremove', 'pw')
bulk = self.coll.initialize_ordered_bulk_op()
bulk.insert({'x': 1})
bulk.find({'x': 2}).upsert().replace_one({'x': 2})
bulk.find({}).remove() # Prohibited.
bulk.insert({'x': 3}) # Never attempted.
self.assertRaises(OperationFailure, bulk.execute)
self.assertEqual(set([1, 2]), set(self.coll.distinct('x')))
def tearDown(self):
db = self.client.pymongo_test
db.logout()
db.authenticate('dbOwner', 'pw')
db.command('dropRole', 'noremove')
remove_all_users(db)
db.logout()
class BaseTestThreadsAuth(object):
"""
Base test class for TestThreadsAuth and TestThreadsAuthReplicaSet. (This is
not itself a unittest.TestCase, otherwise it'd be run twice -- once when
nose imports this module, and once when nose imports
test_threads_replica_set_connection.py, which imports this module.)
"""
def _get_client(self):
"""
Intended for overriding in TestThreadsAuthReplicaSet. This method
returns a MongoClient here, and a MongoReplicaSetClient in
test_threads_replica_set_connection.py.
"""
# Regular test client
return get_client()
def setUp(self):
client = self._get_client()
self.client = client
auth_context.client.admin.add_user('admin-user', 'password',
roles=['clusterAdmin',
'dbAdminAnyDatabase',
'readWriteAnyDatabase',
'userAdminAnyDatabase'])
self.client.admin.authenticate("admin-user", "password")
self.client.auth_test.add_user("test-user", "password",
roles=['readWrite'])
def tearDown(self):
# Remove auth users from databases
self.client.admin.authenticate("admin-user", "password")
self.client.drop_database('auth_test')
remove_all_users(self.client.auth_test)
self.client.admin.remove_user('admin-user')
# Clear client reference so that RSC's monitor thread
# dies.
self.client = None
def test_auto_auth_login(self):
client = self._get_client()
self.assertRaises(OperationFailure, client.auth_test.test.find_one)
# Admin auth
client = self._get_client()
client.admin.authenticate("admin-user", "password")
nthreads = 10
threads = []
for _ in xrange(nthreads):
t = AutoAuthenticateThreads(client.auth_test.test, 100)
t.start()
threads.append(t)
joinall(threads)
for t in threads:
self.assertTrue(t.success)
# Database-specific auth
client = self._get_client()
client.auth_test.authenticate("test-user", "password")
threads = []
for _ in xrange(nthreads):
t = AutoAuthenticateThreads(client.auth_test.test, 100)
t.start()
threads.append(t)
joinall(threads)
for t in threads:
self.assertTrue(t.success)
class TestThreadsAuth(BaseTestThreadsAuth, unittest.TestCase):
pass
class TestThreadsAuthReplicaSet(TestReplicaSetClientBase, BaseTestThreadsAuth):
def setUp(self):
"""
Prepare to test all the same things that TestThreads tests, but do it
with a replica-set client
"""
TestReplicaSetClientBase.setUp(self)
BaseTestThreadsAuth.setUp(self)
def tearDown(self):
TestReplicaSetClientBase.tearDown(self)
BaseTestThreadsAuth.tearDown(self)
def _get_client(self):
"""
Override TestThreadsAuth, so its tests run on a MongoReplicaSetClient
instead of a regular MongoClient.
"""
return MongoReplicaSetClient(pair, replicaSet=self.name)
if __name__ == "__main__":
unittest.main()

View File

@ -33,9 +33,14 @@ from bson.binary import *
from bson.py3compat import b, binary_type
from bson.son import SON
from nose.plugins.skip import SkipTest
from test import skip_restricted_localhost
from test.test_client import get_client
from pymongo.mongo_client import MongoClient
setUpModule = skip_restricted_localhost
class TestBinary(unittest.TestCase):
def test_binary(self):
a_string = "hello world"

View File

@ -23,12 +23,13 @@ sys.path[0:0] = [""]
from bson import InvalidDocument, SON
from pymongo.errors import BulkWriteError, InvalidOperation, OperationFailure
from test import version
from test import version, skip_restricted_localhost
from test.test_client import get_client
from test.utils import (oid_generated_on_client,
remove_all_users,
server_started_with_auth,
server_started_with_nojournal)
from test.utils import oid_generated_on_client
setUpModule = skip_restricted_localhost
class BulkTestBase(unittest.TestCase):
@ -1135,63 +1136,5 @@ class TestBulkNoResults(BulkTestBase):
self.assertTrue(self.coll.find_one({'_id': 1}) is None)
class TestBulkAuthorization(BulkTestBase):
def setUp(self):
super(TestBulkAuthorization, self).setUp()
self.client = client = get_client()
if (not server_started_with_auth(client)
or not version.at_least(client, (2, 5, 3))):
raise SkipTest('Need at least MongoDB 2.5.3 with auth')
db = client.pymongo_test
self.coll = db.test
self.coll.remove()
db.add_user('dbOwner', 'pw', roles=['dbOwner'])
db.authenticate('dbOwner', 'pw')
db.add_user('readonly', 'pw', roles=['read'])
db.command(
'createRole', 'noremove',
privileges=[{
'actions': ['insert', 'update', 'find'],
'resource': {'db': 'pymongo_test', 'collection': 'test'}
}],
roles=[])
db.add_user('noremove', 'pw', roles=['noremove'])
db.logout()
def test_readonly(self):
# We test that an authorization failure aborts the batch and is raised
# as OperationFailure.
db = self.client.pymongo_test
db.authenticate('readonly', 'pw')
bulk = self.coll.initialize_ordered_bulk_op()
bulk.insert({'x': 1})
self.assertRaises(OperationFailure, bulk.execute)
def test_no_remove(self):
# We test that an authorization failure aborts the batch and is raised
# as OperationFailure.
db = self.client.pymongo_test
db.authenticate('noremove', 'pw')
bulk = self.coll.initialize_ordered_bulk_op()
bulk.insert({'x': 1})
bulk.find({'x': 2}).upsert().replace_one({'x': 2})
bulk.find({}).remove() # Prohibited.
bulk.insert({'x': 3}) # Never attempted.
self.assertRaises(OperationFailure, bulk.execute)
self.assertEqual(set([1, 2]), set(self.coll.distinct('x')))
def tearDown(self):
db = self.client.pymongo_test
db.logout()
db.authenticate('dbOwner', 'pw')
db.command('dropRole', 'noremove')
remove_all_users(db)
db.logout()
if __name__ == "__main__":
unittest.main()

View File

@ -34,20 +34,18 @@ from bson.tz_util import utc
from pymongo.mongo_client import MongoClient
from pymongo.database import Database
from pymongo.pool import SocketInfo
from pymongo import auth, thread_util, common
from pymongo import thread_util
from pymongo.errors import (AutoReconnect,
ConfigurationError,
ConnectionFailure,
InvalidName,
OperationFailure,
PyMongoError)
from test import version, host, port, pair
OperationFailure)
from test import version, host, port, pair, skip_restricted_localhost
from test.pymongo_mocks import MockClient
from test.utils import (assertRaisesExactly,
catch_warnings,
delay,
is_mongos,
remove_all_users,
server_is_master_with_slave,
server_started_with_auth,
TestRequestMixin,
@ -55,8 +53,9 @@ from test.utils import (assertRaisesExactly,
_TestExhaustCursorMixin,
lazy_client_trial,
NTHREADS,
get_pool,
one)
get_pool)
setUpModule = skip_restricted_localhost
def get_client(*args, **kwargs):
@ -266,36 +265,6 @@ class TestClient(unittest.TestCase, TestRequestMixin):
self.assertTrue("pymongo_test2" in c.database_names())
self.assertEqual("bar", c.pymongo_test2.test.find_one()["foo"])
# See SERVER-6427 for mongos
if not is_mongos(c) and server_started_with_auth(c):
c.drop_database("pymongo_test1")
c.admin.add_user("admin", "password")
c.admin.authenticate("admin", "password")
try:
c.pymongo_test.add_user("mike", "password")
self.assertRaises(OperationFailure, c.copy_database,
"pymongo_test", "pymongo_test1",
username="foo", password="bar")
self.assertFalse("pymongo_test1" in c.database_names())
self.assertRaises(OperationFailure, c.copy_database,
"pymongo_test", "pymongo_test1",
username="mike", password="bar")
self.assertFalse("pymongo_test1" in c.database_names())
c.copy_database("pymongo_test", "pymongo_test1",
username="mike", password="password")
self.assertTrue("pymongo_test1" in c.database_names())
self.assertEqual("bar", c.pymongo_test1.test.find_one()["foo"])
finally:
# Cleanup
remove_all_users(c.pymongo_test)
c.admin.remove_user("admin")
c.disconnect()
def test_iteration(self):
client = MongoClient(host, port)
@ -347,75 +316,13 @@ class TestClient(unittest.TestCase, TestRequestMixin):
c = MongoClient(uri, _connect=False)
self.assertEqual(Database(c, 'foo'), c.get_default_database())
def test_auth_from_uri(self):
c = MongoClient(host, port)
# Sharded auth not supported before MongoDB 2.0
if is_mongos(c) and not version.at_least(c, (2, 0, 0)):
raise SkipTest("Auth with sharding requires MongoDB >= 2.0.0")
if not server_started_with_auth(c):
raise SkipTest('Authentication is not enabled on server')
c.admin.add_user("admin", "pass")
c.admin.authenticate("admin", "pass")
try:
c.pymongo_test.add_user("user", "pass", roles=['userAdmin', 'readWrite'])
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://foo:bar@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://admin:bar@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://user:pass@%s:%d" % (host, port))
MongoClient("mongodb://admin:pass@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://admin:pass@%s:%d/pymongo_test" %
(host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://user:foo@%s:%d/pymongo_test" %
(host, port))
MongoClient("mongodb://user:pass@%s:%d/pymongo_test" %
(host, port))
# Auth with lazy connection.
MongoClient(
"mongodb://user:pass@%s:%d/pymongo_test" % (host, port),
_connect=False).pymongo_test.test.find_one()
# Wrong password.
bad_client = MongoClient(
"mongodb://user:wrong@%s:%d/pymongo_test" % (host, port),
_connect=False)
self.assertRaises(OperationFailure,
bad_client.pymongo_test.test.find_one)
finally:
# Clean up.
remove_all_users(c.pymongo_test)
remove_all_users(c.admin)
def test_lazy_auth_raises_operation_failure(self):
# Check if we have the prerequisites to run this test.
c = MongoClient(host, port)
if not server_started_with_auth(c):
raise SkipTest('Authentication is not enabled on server')
if is_mongos(c) and not version.at_least(c, (2, 0, 0)):
raise SkipTest("Auth with sharding requires MongoDB >= 2.0.0")
lazy_client = MongoClient(
"mongodb://user:wrong@%s:%d/pymongo_test" % (host, port),
_connect=False)
assertRaisesExactly(
OperationFailure, lazy_client.test.collection.find_one)
def test_unix_socket(self):
if not hasattr(socket, "AF_UNIX"):
raise SkipTest("UNIX-sockets are not supported on this system")
client = MongoClient(host, port)
if (sys.platform == 'darwin' and
server_started_with_auth(MongoClient(host, port))):
server_started_with_auth(client) and
not version.at_least(client, (2, 7, 1))):
raise SkipTest("SERVER-8492")
mongodb_socket = '/tmp/mongodb-27017.sock'
@ -1001,42 +908,6 @@ with client.start_request() as request:
client = get_client(_connect=False)
client.pymongo_test.test.remove(w=0)
def test_auth_network_error(self):
# Make sure there's no semaphore leak if we get a network error
# when authenticating a new socket with cached credentials.
auth_client = get_client()
if not server_started_with_auth(auth_client):
raise SkipTest('Authentication is not enabled on server')
auth_client.admin.add_user('admin', 'password')
auth_client.admin.authenticate('admin', 'password')
try:
# Get a client with one socket so we detect if it's leaked.
c = get_client(max_pool_size=1, waitQueueTimeoutMS=1)
# Simulate an authenticate() call on a different socket.
credentials = auth._build_credentials_tuple(
'MONGODB-CR', 'admin',
unicode('admin'), unicode('password'),
{})
c._cache_credentials('test', credentials, connect=False)
# Cause a network error on the actual socket.
pool = get_pool(c)
socket_info = one(pool.sockets)
socket_info.sock.close()
# In __check_auth, the client authenticates its socket with the
# new credential, but gets a socket.error. Should be reraised as
# AutoReconnect.
self.assertRaises(AutoReconnect, c.test.collection.find_one)
# No semaphore leak, the pool is allowed to make a new socket.
c.test.collection.find_one()
finally:
remove_all_users(auth_client.admin)
class TestClientLazyConnect(unittest.TestCase, _TestLazyConnectMixin):
def _get_client(self, **kwargs):

View File

@ -53,8 +53,7 @@ from pymongo.errors import (DocumentTooLarge,
from test.test_client import get_client
from test.utils import (catch_warnings, enable_text_search,
get_pool, is_mongos, joinall, oid_generated_on_client)
from test import (qcheck,
version)
from test import qcheck, version, skip_restricted_localhost
have_uuid = True
try:
@ -63,6 +62,9 @@ except ImportError:
have_uuid = False
setUpModule = skip_restricted_localhost
class TestCollection(unittest.TestCase):
def setUp(self):

View File

@ -30,7 +30,7 @@ from pymongo.connection import Connection
from pymongo.mongo_client import MongoClient
from pymongo.mongo_replica_set_client import MongoReplicaSetClient
from pymongo.errors import ConfigurationError, OperationFailure
from test import host, port, pair, version
from test import host, port, pair, version, skip_restricted_localhost
from test.utils import catch_warnings, drop_collections
have_uuid = True
@ -40,6 +40,9 @@ except ImportError:
have_uuid = False
setUpModule = skip_restricted_localhost
class TestCommon(unittest.TestCase):
def test_baseobject(self):

View File

@ -37,12 +37,15 @@ from pymongo.database import Database
from pymongo.errors import (InvalidOperation,
OperationFailure,
ExecutionTimeout)
from test import version
from test import version, skip_restricted_localhost
from test.test_client import get_client
from test.utils import (catch_warnings, is_mongos,
get_command_line, server_started_with_auth)
setUpModule = skip_restricted_localhost
class TestCursor(unittest.TestCase):
def setUp(self):

View File

@ -15,7 +15,6 @@
"""Test the database module."""
import datetime
import os
import re
import sys
import warnings
@ -39,7 +38,6 @@ from pymongo import (ALL,
from pymongo.collection import Collection
from pymongo.database import Database
from pymongo.errors import (CollectionInvalid,
ConfigurationError,
ExecutionTimeout,
InvalidName,
OperationFailure)
@ -47,12 +45,15 @@ from pymongo.son_manipulator import (AutoReference,
NamespaceInjector,
SONManipulator,
ObjectIdShuffler)
from test import version
from test import version, skip_restricted_localhost
from test.utils import (catch_warnings, get_command_line,
is_mongos, remove_all_users, server_started_with_auth)
is_mongos, server_started_with_auth)
from test.test_client import get_client
setUpModule = skip_restricted_localhost
class TestDatabase(unittest.TestCase):
def setUp(self):
@ -358,319 +359,6 @@ class TestDatabase(unittest.TestCase):
self.assertEqual(auth._password_digest("Gustave", u"Dor\xe9"),
u"81e0e2364499209f466e75926a162d73")
def test_authenticate_add_remove_user(self):
if (is_mongos(self.client) and not
version.at_least(self.client, (2, 0, 0))):
raise SkipTest("Auth with sharding requires MongoDB >= 2.0.0")
if not server_started_with_auth(self.client):
raise SkipTest('Authentication is not enabled on server')
db = self.client.pymongo_test
# Configuration errors
self.assertRaises(ValueError, db.add_user, "user", '')
self.assertRaises(TypeError, db.add_user, "user", 'password', 15)
self.assertRaises(ConfigurationError, db.add_user,
"user", 'password', 'True')
self.assertRaises(ConfigurationError, db.add_user,
"user", 'password', True, roles=['read'])
if version.at_least(self.client, (2, 5, 3, -1)):
ctx = catch_warnings()
try:
warnings.simplefilter("error", DeprecationWarning)
self.assertRaises(DeprecationWarning, db.add_user,
"user", "password")
self.assertRaises(DeprecationWarning, db.add_user,
"user", "password", True)
finally:
ctx.exit()
self.assertRaises(ConfigurationError, db.add_user,
"user", "password", digestPassword=True)
self.client.admin.add_user("admin", "password")
self.client.admin.authenticate("admin", "password")
try:
# Add / authenticate / remove
db.add_user("mike", "password")
self.assertRaises(TypeError, db.authenticate, 5, "password")
self.assertRaises(TypeError, db.authenticate, "mike", 5)
self.assertRaises(OperationFailure,
db.authenticate, "mike", "not a real password")
self.assertRaises(OperationFailure,
db.authenticate, "faker", "password")
self.assertTrue(db.authenticate("mike", "password"))
db.logout()
self.assertTrue(db.authenticate(u"mike", u"password"))
db.remove_user("mike")
db.logout()
self.assertRaises(OperationFailure,
db.authenticate, "mike", "password")
# Add / authenticate / change password
self.assertRaises(OperationFailure,
db.authenticate, "Gustave", u"Dor\xe9")
db.add_user("Gustave", u"Dor\xe9")
self.assertTrue(db.authenticate("Gustave", u"Dor\xe9"))
db.add_user("Gustave", "password")
db.logout()
self.assertRaises(OperationFailure,
db.authenticate, "Gustave", u"Dor\xe9")
self.assertTrue(db.authenticate("Gustave", u"password"))
if not version.at_least(self.client, (2, 5, 3, -1)):
# Add a readOnly user
db.add_user("Ross", "password", read_only=True)
db.logout()
self.assertTrue(db.authenticate("Ross", u"password"))
self.assertTrue(db.system.users.find({"readOnly": True}).count())
db.logout()
# Cleanup
finally:
remove_all_users(db)
self.client.admin.remove_user("admin")
self.client.admin.logout()
def test_make_user_readonly(self):
if (is_mongos(self.client)
and not version.at_least(self.client, (2, 0, 0))):
raise SkipTest('Auth with sharding requires MongoDB >= 2.0.0')
if not server_started_with_auth(self.client):
raise SkipTest('Authentication is not enabled on server')
admin = self.client.admin
admin.add_user('admin', 'pw')
admin.authenticate('admin', 'pw')
db = self.client.pymongo_test
try:
# Make a read-write user.
db.add_user('jesse', 'pw')
admin.logout()
# Check that we're read-write by default.
db.authenticate('jesse', 'pw')
db.collection.insert({})
db.logout()
# Make the user read-only.
admin.authenticate('admin', 'pw')
db.add_user('jesse', 'pw', read_only=True)
admin.logout()
db.authenticate('jesse', 'pw')
self.assertRaises(OperationFailure, db.collection.insert, {})
finally:
# Cleanup
admin.authenticate('admin', 'pw')
remove_all_users(db)
admin.remove_user("admin")
admin.logout()
def test_default_roles(self):
if not version.at_least(self.client, (2, 5, 3, -1)):
raise SkipTest("Default roles only exist in MongoDB >= 2.5.3")
if not server_started_with_auth(self.client):
raise SkipTest('Authentication is not enabled on server')
# "Admin" user
db = self.client.admin
db.add_user('admin', 'pass')
try:
db.authenticate('admin', 'pass')
info = db.command('usersInfo', 'admin')['users'][0]
self.assertEqual("root", info['roles'][0]['role'])
# Read only "admin" user
db.add_user('ro-admin', 'pass', read_only=True)
db.logout()
db.authenticate('ro-admin', 'pass')
info = db.command('usersInfo', 'ro-admin')['users'][0]
self.assertEqual("readAnyDatabase", info['roles'][0]['role'])
db.logout()
# Cleanup
finally:
db.authenticate('admin', 'pass')
remove_all_users(db)
db.logout()
db.connection.disconnect()
# "Non-admin" user
db = self.client.pymongo_test
db.add_user('user', 'pass')
try:
db.authenticate('user', 'pass')
info = db.command('usersInfo', 'user')['users'][0]
self.assertEqual("dbOwner", info['roles'][0]['role'])
# Read only "Non-admin" user
db.add_user('ro-user', 'pass', read_only=True)
db.logout()
db.authenticate('ro-user', 'pass')
info = db.command('usersInfo', 'ro-user')['users'][0]
self.assertEqual("read", info['roles'][0]['role'])
db.logout()
# Cleanup
finally:
db.authenticate('user', 'pass')
remove_all_users(db)
db.logout()
def test_new_user_cmds(self):
if not version.at_least(self.client, (2, 5, 3, -1)):
raise SkipTest("User manipulation through commands "
"requires MongoDB >= 2.5.3")
if not server_started_with_auth(self.client):
raise SkipTest('Authentication is not enabled on server')
db = self.client.pymongo_test
db.add_user("amalia", "password", roles=["userAdmin"])
db.authenticate("amalia", "password")
try:
# This tests the ability to update user attributes.
db.add_user("amalia", "new_password",
customData={"secret": "koalas"})
user_info = db.command("usersInfo", "amalia")
self.assertTrue(user_info["users"])
amalia_user = user_info["users"][0]
self.assertEqual(amalia_user["user"], "amalia")
self.assertEqual(amalia_user["customData"], {"secret": "koalas"})
finally:
db.remove_user("amalia")
db.logout()
def test_authenticate_and_safe(self):
if (is_mongos(self.client) and not
version.at_least(self.client, (2, 0, 0))):
raise SkipTest("Auth with sharding requires MongoDB >= 2.0.0")
if not server_started_with_auth(self.client):
raise SkipTest('Authentication is not enabled on server')
db = self.client.auth_test
db.add_user("bernie", "password",
roles=["userAdmin", "dbAdmin", "readWrite"])
db.authenticate("bernie", "password")
try:
db.test.remove({})
self.assertTrue(db.test.insert({"bim": "baz"}))
self.assertEqual(1, db.test.count())
self.assertEqual(1,
db.test.update({"bim": "baz"},
{"$set": {"bim": "bar"}}).get('n'))
self.assertEqual(1,
db.test.remove({}).get('n'))
self.assertEqual(0, db.test.count())
finally:
db.remove_user("bernie")
db.logout()
def test_authenticate_and_request(self):
if (is_mongos(self.client) and not
version.at_least(self.client, (2, 0, 0))):
raise SkipTest("Auth with sharding requires MongoDB >= 2.0.0")
if not server_started_with_auth(self.client):
raise SkipTest('Authentication is not enabled on server')
# Database.authenticate() needs to be in a request - check that it
# always runs in a request, and that it restores the request state
# (in or not in a request) properly when it's finished.
self.assertFalse(self.client.auto_start_request)
db = self.client.pymongo_test
db.add_user("mike", "password",
roles=["userAdmin", "dbAdmin", "readWrite"])
try:
self.assertFalse(self.client.in_request())
self.assertTrue(db.authenticate("mike", "password"))
self.assertFalse(self.client.in_request())
request_cx = get_client(auto_start_request=True)
request_db = request_cx.pymongo_test
self.assertTrue(request_db.authenticate("mike", "password"))
self.assertTrue(request_cx.in_request())
finally:
db.authenticate("mike", "password")
db.remove_user("mike")
db.logout()
request_db.logout()
def test_authenticate_multiple(self):
client = get_client()
if (is_mongos(client) and not
version.at_least(self.client, (2, 2, 0))):
raise SkipTest("Need mongos >= 2.2.0")
if not server_started_with_auth(client):
raise SkipTest("Authentication is not enabled on server")
# Setup
users_db = client.pymongo_test
admin_db = client.admin
other_db = client.pymongo_test1
users_db.test.remove()
other_db.test.remove()
admin_db.add_user('admin', 'pass',
roles=["userAdminAnyDatabase", "dbAdmin",
"clusterAdmin", "readWrite"])
try:
self.assertTrue(admin_db.authenticate('admin', 'pass'))
if version.at_least(self.client, (2, 5, 3, -1)):
admin_db.add_user('ro-admin', 'pass',
roles=["userAdmin", "readAnyDatabase"])
else:
admin_db.add_user('ro-admin', 'pass', read_only=True)
users_db.add_user('user', 'pass',
roles=["userAdmin", "readWrite"])
admin_db.logout()
self.assertRaises(OperationFailure, users_db.test.find_one)
# Regular user should be able to query its own db, but
# no other.
users_db.authenticate('user', 'pass')
self.assertEqual(0, users_db.test.count())
self.assertRaises(OperationFailure, other_db.test.find_one)
# Admin read-only user should be able to query any db,
# but not write.
admin_db.authenticate('ro-admin', 'pass')
self.assertEqual(0, other_db.test.count())
self.assertRaises(OperationFailure,
other_db.test.insert, {})
# Force close all sockets
client.disconnect()
# We should still be able to write to the regular user's db
self.assertTrue(users_db.test.remove())
# And read from other dbs...
self.assertEqual(0, other_db.test.count())
# But still not write to other dbs...
self.assertRaises(OperationFailure,
other_db.test.insert, {})
# Cleanup
finally:
admin_db.logout()
users_db.logout()
admin_db.authenticate('admin', 'pass')
remove_all_users(users_db)
remove_all_users(admin_db)
def test_id_ordering(self):
# PyMongo attempts to have _id show up first
# when you iterate key/value pairs in a document.
@ -1020,6 +708,5 @@ class TestDatabase(unittest.TestCase):
self.assertEqual('value', out.get('value'))
if __name__ == "__main__":
unittest.main()

View File

@ -39,7 +39,10 @@ from gridfs.errors import (NoFile,
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure
from test.test_client import get_client
from test import qcheck
from test import qcheck, skip_restricted_localhost
setUpModule = skip_restricted_localhost
class TestGridFile(unittest.TestCase):

View File

@ -32,11 +32,15 @@ from gridfs.errors import (FileExists, NoFile)
from pymongo.errors import ConnectionFailure
from pymongo.mongo_client import MongoClient
from pymongo.read_preferences import ReadPreference
from test import skip_restricted_localhost
from test.test_client import get_client
from test.test_replica_set_client import TestReplicaSetClientBase
from test.utils import catch_warnings, joinall
setUpModule = skip_restricted_localhost
class JustWrite(threading.Thread):
def __init__(self, fs, n):

View File

@ -37,6 +37,7 @@ from bson.son import RE_TYPE
from bson.timestamp import Timestamp
from bson.tz_util import utc
from test import skip_restricted_localhost
from test.test_client import get_client
PY3 = sys.version_info[0] == 3
@ -221,6 +222,7 @@ class TestJsonUtil(unittest.TestCase):
self.assertEqual('{"$code": "return z", "$scope": {"z": 2}}', res)
def test_cursor(self):
skip_restricted_localhost()
db = self.db
db.drop_collection("test")

View File

@ -27,11 +27,14 @@ import pymongo
from pymongo.connection import Connection
from pymongo.replica_set_connection import ReplicaSetConnection
from pymongo.errors import ConfigurationError
from test import host, port, pair
from test import host, port, pair, skip_restricted_localhost
from test.test_replica_set_client import TestReplicaSetClientBase
from test.utils import catch_warnings, get_pool
setUpModule = skip_restricted_localhost
class TestConnection(unittest.TestCase):
def test_connection(self):
c = Connection(host, port)

View File

@ -15,7 +15,6 @@
"""Test for master slave connections."""
import datetime
import os
import sys
import threading
import time
@ -36,10 +35,16 @@ from pymongo.database import Database
from pymongo.mongo_client import MongoClient
from pymongo.collection import Collection
from pymongo.master_slave_connection import MasterSlaveConnection
from test import host, port, host2, port2, host3, port3
from test import (host, port,
host2, port2,
host3, port3,
skip_restricted_localhost)
from test.utils import TestRequestMixin, catch_warnings, get_pool
setUpModule = skip_restricted_localhost
class TestMasterSlaveConnection(unittest.TestCase, TestRequestMixin):
def setUp(self):

View File

@ -21,9 +21,13 @@ import unittest
sys.path[0:0] = [""]
from pymongo.errors import AutoReconnect
from test import skip_restricted_localhost
from test.pymongo_mocks import MockClient
setUpModule = skip_restricted_localhost
class FindOne(threading.Thread):
def __init__(self, client):
super(FindOne, self).__init__()

View File

@ -18,14 +18,13 @@ import datetime
import pickle
import unittest
import sys
import time
sys.path[0:0] = [""]
from nose.plugins.skip import SkipTest
from bson.errors import InvalidId
from bson.objectid import ObjectId
from bson.py3compat import b, binary_type
from bson.py3compat import b
from bson.tz_util import (FixedOffset,
utc)

View File

@ -23,13 +23,16 @@ sys.path[0:0] = [""]
from nose.plugins.skip import SkipTest
from test import host, port
from test import host, port, skip_restricted_localhost
from test.test_pooling_base import (
_TestPooling, _TestMaxPoolSize, _TestMaxOpenSockets,
_TestPoolSocketSharing, _TestWaitQueueMultiple, one)
from test.utils import get_pool
setUpModule = skip_restricted_localhost
class TestPoolingThreads(_TestPooling, unittest.TestCase):
use_greenlets = False

View File

@ -23,13 +23,16 @@ from nose.plugins.skip import SkipTest
from pymongo import pool
from pymongo.errors import ConfigurationError
from test import host, port
from test import host, port, skip_restricted_localhost
from test.utils import looplet
from test.test_pooling_base import (
_TestPooling, _TestMaxPoolSize, _TestMaxOpenSockets,
_TestPoolSocketSharing, _TestWaitQueueMultiple, has_gevent)
setUpModule = skip_restricted_localhost
class TestPoolingGevent(_TestPooling, unittest.TestCase):
"""Apply all the standard pool tests with greenlets and Gevent"""
use_greenlets = True

View File

@ -15,7 +15,6 @@
"""Test the pymongo module itself."""
import unittest
import os
import sys
sys.path[0:0] = [""]

View File

@ -31,10 +31,13 @@ from pymongo.errors import ConfigurationError
from test.test_replica_set_client import TestReplicaSetClientBase
from test.test_client import get_client
from test import version, utils, host, port
from test import version, utils, host, port, skip_restricted_localhost
from test.utils import catch_warnings
setUpModule = skip_restricted_localhost
class TestReadPreferencesBase(TestReplicaSetClientBase):
def setUp(self):
super(TestReadPreferencesBase, self).setUp()

View File

@ -35,7 +35,7 @@ from bson.son import SON
from bson.tz_util import utc
from pymongo.mongo_client import MongoClient
from pymongo.read_preferences import ReadPreference
from pymongo.member import PRIMARY, SECONDARY, OTHER
from pymongo.member import SECONDARY
from pymongo.mongo_replica_set_client import MongoReplicaSetClient
from pymongo.mongo_replica_set_client import _partition_node, have_gevent
from pymongo.database import Database
@ -45,16 +45,17 @@ from pymongo.errors import (AutoReconnect,
ConnectionFailure,
InvalidName,
OperationFailure, InvalidOperation)
from pymongo import auth
from test import version, port, pair
from test import version, port, pair, skip_restricted_localhost, auth_context
from test.pymongo_mocks import MockReplicaSetClient
from test.utils import (
delay, assertReadFrom, assertReadFromAll, read_from_which_host,
remove_all_users, assertRaisesExactly, TestRequestMixin, one,
server_started_with_auth, pools_from_rs_client, get_pool,
assertRaisesExactly, TestRequestMixin, one, pools_from_rs_client, get_pool,
_TestLazyConnectMixin, _TestExhaustCursorMixin)
setUpModule = skip_restricted_localhost
class TestReplicaSetClientAgainstStandalone(unittest.TestCase):
"""This is a funny beast -- we want to run tests for MongoReplicaSetClient
but only if the database at DB_IP and DB_PORT is a standalone.
@ -83,7 +84,10 @@ class TestReplicaSetClientBase(unittest.TestCase):
self.arbiters = set([_partition_node(h)
for h in response.get("arbiters", [])])
repl_set_status = client.admin.command('replSetGetStatus')
# Cannot run replSetGetStatus in MongoDB >= 2.7.1 under auth once a
# user has been added.
repl_set_status = auth_context.client.admin.command(
'replSetGetStatus')
primary_info = [
m for m in repl_set_status['members']
if m['stateStr'] == 'PRIMARY'
@ -168,44 +172,6 @@ class TestReplicaSetClient(TestReplicaSetClientBase, TestRequestMixin):
self.assertRaises(ConnectionFailure, c.pymongo_test.test.find_one)
def test_init_disconnected_with_auth_failure(self):
c = MongoReplicaSetClient(
"mongodb://user:pass@somedomainthatdoesntexist", replicaSet="rs",
connectTimeoutMS=1, _connect=False)
self.assertRaises(ConnectionFailure, c.pymongo_test.test.find_one)
def test_init_disconnected_with_auth(self):
c = self._get_client()
if not server_started_with_auth(c):
raise SkipTest('Authentication is not enabled on server')
c.admin.add_user("admin", "pass")
c.admin.authenticate("admin", "pass")
try:
c.pymongo_test.add_user("user", "pass", roles=['readWrite', 'userAdmin'])
# Auth with lazy connection.
host = one(self.hosts)
uri = "mongodb://user:pass@%s:%d/pymongo_test?replicaSet=%s" % (
host[0], host[1], self.name)
authenticated_client = MongoReplicaSetClient(uri, _connect=False)
authenticated_client.pymongo_test.test.find_one()
# Wrong password.
bad_uri = "mongodb://user:wrong@%s:%d/pymongo_test?replicaSet=%s" % (
host[0], host[1], self.name)
bad_client = MongoReplicaSetClient(bad_uri, _connect=False)
self.assertRaises(
OperationFailure, bad_client.pymongo_test.test.find_one)
finally:
# Clean up.
remove_all_users(c.pymongo_test)
remove_all_users(c.admin)
def test_connect(self):
assertRaisesExactly(ConnectionFailure, MongoReplicaSetClient,
"somedomainthatdoesntexist.org:27017",
@ -341,20 +307,6 @@ class TestReplicaSetClient(TestReplicaSetClientBase, TestRequestMixin):
finally:
socket.socket.sendall = old_sendall
def test_lazy_auth_raises_operation_failure(self):
# Check if we have the prerequisites to run this test.
c = self._get_client()
if not server_started_with_auth(c):
raise SkipTest('Authentication is not enabled on server')
lazy_client = MongoReplicaSetClient(
"mongodb://user:wrong@%s/pymongo_test" % pair,
replicaSet=self.name,
_connect=False)
assertRaisesExactly(
OperationFailure, lazy_client.test.collection.find_one)
def test_operations(self):
c = self._get_client()
@ -466,35 +418,6 @@ class TestReplicaSetClient(TestReplicaSetClientBase, TestRequestMixin):
self.assertTrue("pymongo_test2" in c.database_names())
self.assertEqual("bar", c.pymongo_test2.test.find_one()["foo"])
if version.at_least(c, (1, 3, 3, 1)) and server_started_with_auth(c):
c.drop_database("pymongo_test1")
c.admin.add_user("admin", "password")
c.admin.authenticate("admin", "password")
try:
c.pymongo_test.add_user("mike", "password")
self.assertRaises(OperationFailure, c.copy_database,
"pymongo_test", "pymongo_test1",
username="foo", password="bar")
self.assertFalse("pymongo_test1" in c.database_names())
self.assertRaises(OperationFailure, c.copy_database,
"pymongo_test", "pymongo_test1",
username="mike", password="bar")
self.assertFalse("pymongo_test1" in c.database_names())
c.copy_database("pymongo_test", "pymongo_test1",
username="mike", password="password")
self.assertTrue("pymongo_test1" in c.database_names())
res = c.pymongo_test1.test.find_one(_must_use_master=True)
self.assertEqual("bar", res["foo"])
finally:
# Cleanup
remove_all_users(c.pymongo_test)
c.admin.remove_user("admin")
c.close()
def test_get_default_database(self):
host = one(self.hosts)
uri = "mongodb://%s:%d/foo?replicaSet=%s" % (
@ -1127,42 +1050,6 @@ class TestReplicaSetClient(TestReplicaSetClientBase, TestRequestMixin):
self.assertFalse(client.alive())
def test_auth_network_error(self):
# Make sure there's no semaphore leak if we get a network error
# when authenticating a new socket with cached credentials.
auth_client = self._get_client()
if not server_started_with_auth(auth_client):
raise SkipTest('Authentication is not enabled on server')
auth_client.admin.add_user('admin', 'password')
auth_client.admin.authenticate('admin', 'password')
try:
# Get a client with one socket so we detect if it's leaked.
c = self._get_client(max_pool_size=1, waitQueueTimeoutMS=1)
# Simulate an authenticate() call on a different socket.
credentials = auth._build_credentials_tuple(
'MONGODB-CR', 'admin',
unicode('admin'), unicode('password'),
{})
c._cache_credentials('test', credentials, connect=False)
# Cause a network error on the actual socket.
pool = get_pool(c)
socket_info = one(pool.sockets)
socket_info.sock.close()
# In __check_auth, the client authenticates its socket with the
# new credential, but gets a socket.error. Should be reraised as
# AutoReconnect.
self.assertRaises(AutoReconnect, c.test.collection.find_one)
# No semaphore leak, the pool is allowed to make a new socket.
c.test.collection.find_one()
finally:
remove_all_users(auth_client.admin)
class TestReplicaSetWireVersion(unittest.TestCase):
def test_wire_version(self):

View File

@ -21,9 +21,13 @@ sys.path[0:0] = [""]
from pymongo.errors import ConfigurationError, ConnectionFailure
from pymongo import ReadPreference
from test import skip_restricted_localhost
from test.pymongo_mocks import MockClient, MockReplicaSetClient
setUpModule = skip_restricted_localhost
class TestSecondaryBecomesStandalone(unittest.TestCase):
# An administrator removes a secondary from a 3-node set and
# brings it back up as standalone, without updating the other

View File

@ -18,14 +18,15 @@ import unittest
import threading
import traceback
from nose.plugins.skip import SkipTest
from test.utils import (joinall, remove_all_users,
server_started_with_auth, RendezvousThread)
from test import skip_restricted_localhost
from test.utils import joinall, RendezvousThread
from test.test_client import get_client
from test.utils import get_pool
from pymongo.pool import SocketInfo, _closed
from pymongo.errors import AutoReconnect, OperationFailure
from pymongo.errors import AutoReconnect
setUpModule = skip_restricted_localhost
class AutoAuthenticateThreads(threading.Thread):
@ -299,87 +300,9 @@ class BaseTestThreads(object):
self.assertTrue(t.passed, "%s threw exception" % t)
class BaseTestThreadsAuth(object):
"""
Base test class for TestThreadsAuth and TestThreadsAuthReplicaSet. (This is
not itself a unittest.TestCase, otherwise it'd be run twice -- once when
nose imports this module, and once when nose imports
test_threads_replica_set_connection.py, which imports this module.)
"""
def _get_client(self):
"""
Intended for overriding in TestThreadsAuthReplicaSet. This method
returns a MongoClient here, and a MongoReplicaSetClient in
test_threads_replica_set_connection.py.
"""
# Regular test client
return get_client()
def setUp(self):
client = self._get_client()
if not server_started_with_auth(client):
raise SkipTest("Authentication is not enabled on server")
self.client = client
self.client.admin.add_user('admin-user', 'password',
roles=['clusterAdmin',
'dbAdminAnyDatabase',
'readWriteAnyDatabase',
'userAdminAnyDatabase'])
self.client.admin.authenticate("admin-user", "password")
self.client.auth_test.add_user("test-user", "password",
roles=['readWrite'])
def tearDown(self):
# Remove auth users from databases
self.client.admin.authenticate("admin-user", "password")
remove_all_users(self.client.auth_test)
self.client.drop_database('auth_test')
remove_all_users(self.client.admin)
# Clear client reference so that RSC's monitor thread
# dies.
self.client = None
def test_auto_auth_login(self):
client = self._get_client()
self.assertRaises(OperationFailure, client.auth_test.test.find_one)
# Admin auth
client = self._get_client()
client.admin.authenticate("admin-user", "password")
nthreads = 10
threads = []
for _ in xrange(nthreads):
t = AutoAuthenticateThreads(client.auth_test.test, 100)
t.start()
threads.append(t)
joinall(threads)
for t in threads:
self.assertTrue(t.success)
# Database-specific auth
client = self._get_client()
client.auth_test.authenticate("test-user", "password")
threads = []
for _ in xrange(nthreads):
t = AutoAuthenticateThreads(client.auth_test.test, 100)
t.start()
threads.append(t)
joinall(threads)
for t in threads:
self.assertTrue(t.success)
class TestThreads(BaseTestThreads, unittest.TestCase):
pass
class TestThreadsAuth(BaseTestThreadsAuth, unittest.TestCase):
pass
if __name__ == "__main__":
unittest.main()

View File

@ -16,10 +16,12 @@
import unittest
from pymongo.mongo_replica_set_client import MongoReplicaSetClient
from test import skip_restricted_localhost
from test.test_threads import BaseTestThreads
from test.test_replica_set_client import TestReplicaSetClientBase
from test.test_threads import BaseTestThreads, BaseTestThreadsAuth
from test.test_replica_set_client import TestReplicaSetClientBase, pair
setUpModule = skip_restricted_localhost
class TestThreadsReplicaSet(TestReplicaSetClientBase, BaseTestThreads):
@ -39,31 +41,6 @@ class TestThreadsReplicaSet(TestReplicaSetClientBase, BaseTestThreads):
return TestReplicaSetClientBase._get_client(self, **kwargs)
class TestThreadsAuthReplicaSet(TestReplicaSetClientBase, BaseTestThreadsAuth):
def setUp(self):
"""
Prepare to test all the same things that TestThreads tests, but do it
with a replica-set client
"""
TestReplicaSetClientBase.setUp(self)
BaseTestThreadsAuth.setUp(self)
def tearDown(self):
TestReplicaSetClientBase.tearDown(self)
BaseTestThreadsAuth.tearDown(self)
def _get_client(self):
"""
Override TestThreadsAuth, so its tests run on a MongoReplicaSetClient
instead of a regular MongoClient.
"""
return MongoReplicaSetClient(pair, replicaSet=self.name)
if __name__ == "__main__":
suite = unittest.TestSuite([
unittest.makeSuite(TestThreadsReplicaSet),
unittest.makeSuite(TestThreadsAuthReplicaSet)
])
suite = unittest.makeSuite(TestThreadsReplicaSet)
unittest.TextTestRunner(verbosity=2).run(suite)

View File

@ -92,10 +92,8 @@ def server_started_with_auth(client):
# MongoDB >= 2.6
if 'security' in parsed:
security = parsed['security']
# >= rc3
if 'authorization' in security:
return security['authorization'] == 'enabled'
# < rc3
return security.get('auth', False) or bool(security.get('keyFile'))
return parsed.get('auth', False) or bool(parsed.get('keyFile'))
# Legacy