diff options
author | Andy Schwerin <schwerin@10gen.com> | 2013-08-23 17:13:35 -0400 |
---|---|---|
committer | Andy Schwerin <schwerin@10gen.com> | 2013-09-03 18:14:01 -0400 |
commit | 5fb2c2c35426d907057bccf6ffefec0493897af6 (patch) | |
tree | 3f4106feb72f3d3eb1f769a98c9b12de65dad785 /src/mongo/db | |
parent | 2f0c929ee17921cf122a3f3fb73f826841126a0c (diff) | |
download | mongo-5fb2c2c35426d907057bccf6ffefec0493897af6.tar.gz |
SERVER-9516 Logic of system.users schema upgrade process.
Includes AuthorizationManagerExternalState interface changes and implementation
in the mock, plus unit tests.
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/auth/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager.cpp | 172 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager.h | 16 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager_test.cpp | 210 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_session_test.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state.h | 87 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_d.cpp | 71 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_d.h | 34 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_mock.cpp | 208 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_mock.h | 58 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_s.cpp | 71 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_s.h | 34 | ||||
-rw-r--r-- | src/mongo/db/namespace_string.h | 2 |
14 files changed, 854 insertions, 118 deletions
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index a00e79166e0..0e3ad48287d 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -45,7 +45,8 @@ env.StaticLibrary('authmongos', env.StaticLibrary('authmocks', ['authz_manager_external_state_mock.cpp'], - LIBDEPS=['$BUILD_DIR/mongo/expressions']) + LIBDEPS=['$BUILD_DIR/mongo/db/ops/update_driver', + '$BUILD_DIR/mongo/expressions']) env.CppUnitTest('action_set_test', 'action_set_test.cpp', LIBDEPS=['authcore']) env.CppUnitTest('privilege_document_parser_test', 'privilege_document_parser_test.cpp', diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp index 0f5a96a6230..8a01809da4f 100644 --- a/src/mongo/db/auth/authorization_manager.cpp +++ b/src/mongo/db/auth/authorization_manager.cpp @@ -613,4 +613,176 @@ namespace { return Status::OK(); } + + namespace { + class AuthzUpgradeLockGuard { + MONGO_DISALLOW_COPYING(AuthzUpgradeLockGuard); + public: + explicit AuthzUpgradeLockGuard(AuthzManagerExternalState* externalState) + : _externalState(externalState), _locked(false) { + } + + ~AuthzUpgradeLockGuard() { + if (_locked) + unlock(); + } + + bool tryLock() { + fassert(17111, !_locked); + _locked = _externalState->tryLockUpgradeProcess(); + return _locked; + } + + void unlock() { + fassert(17112, _locked); + _externalState->unlockUpgradeProcess(); + _locked = false; + } + private: + AuthzManagerExternalState* _externalState; + bool _locked; + }; + + BSONObj userAsV2PrivilegeDocument(const User& user) { + BSONObjBuilder builder; + + const UserName& name = user.getName(); + builder.append(AuthorizationManager::USER_NAME_FIELD_NAME, name.getUser()); + builder.append(AuthorizationManager::USER_SOURCE_FIELD_NAME, name.getDB()); + + const User::CredentialData& credentials = user.getCredentials(); + if (!credentials.isExternal) { + BSONObjBuilder credentialsBuilder(builder.subobjStart("credentials")); + credentialsBuilder.append("MONGODB-CR", credentials.password); + credentialsBuilder.doneFast(); + } + + BSONArrayBuilder rolesArray(builder.subarrayStart("roles")); + for (RoleNameIterator roles = user.getRoles(); roles.more(); roles.next()) { + const RoleName& roleName = roles.get(); + BSONObjBuilder roleBuilder(rolesArray.subobjStart()); + roleBuilder.append("name", roleName.getRole()); + roleBuilder.append("source", roleName.getDB()); + roleBuilder.appendBool("canDelegate", false); + roleBuilder.appendBool("hasRole", true); + roleBuilder.doneFast(); + } + rolesArray.doneFast(); + return builder.obj(); + } + + const NamespaceString newusersCollectionName("admin._newusers"); + const NamespaceString usersCollectionName("admin.system.users"); + const NamespaceString backupUsersCollectionName("admin.backup.users"); + const NamespaceString versionCollectionName("admin.system.version"); + const BSONObj versionDocumentQuery = BSON("_id" << 1); + + /** + * Fetches the admin.system.version document and extracts the currentVersion field's + * value, supposing it is an integer, and writes it to outVersion. + */ + Status readAuthzVersion(AuthzManagerExternalState* externalState, int* outVersion) { + BSONObj versionDoc; + Status status = externalState->findOne( + versionCollectionName, versionDocumentQuery, &versionDoc); + if (!status.isOK() && ErrorCodes::NoMatchingDocument != status) { + return status; + } + BSONElement currentVersionElement = versionDoc["currentVersion"]; + if (!versionDoc.isEmpty() && !currentVersionElement.isNumber()) { + return Status(ErrorCodes::TypeMismatch, + "Field 'currentVersion' in admin.system.version must be a number."); + } + *outVersion = currentVersionElement.numberInt(); + return Status::OK(); + } + } // namespace + + Status AuthorizationManager::upgradeAuthCollections() { + boost::lock_guard<boost::mutex> lkLocal(_lock); + AuthzUpgradeLockGuard lkUpgrade(_externalState.get()); + if (!lkUpgrade.tryLock()) { + return Status(ErrorCodes::LockBusy, "Could not lock auth data upgrade process lock."); + } + int durableVersion; + Status status = readAuthzVersion(_externalState.get(), &durableVersion); + if (!status.isOK()) + return status; + + if (_version == 2) { + switch (durableVersion) { + case 0: + case 1: { + const char msg[] = "User data format version in memory and on disk inconsistent; " + "please restart this node."; + error() << msg; + return Status(ErrorCodes::UserDataInconsistent, msg); + } + case 2: + return Status::OK(); + default: + return Status(ErrorCodes::BadValue, + mongoutils::str::stream() << + "Cannot upgrade admin.system.version to 2 from " << + durableVersion); + } + } + fassert(17113, _version == 1); + switch (durableVersion) { + case 0: + case 1: + break; + case 2: { + const char msg[] = "User data format version in memory and on disk inconsistent; " + "please restart this node."; + error() << msg; + return Status(ErrorCodes::UserDataInconsistent, msg); + } + default: + return Status(ErrorCodes::BadValue, + mongoutils::str::stream() << + "Cannot upgrade admin.system.version from 2 to " << + durableVersion); + } + + // Upgrade from v1 to v2. + status = _externalState->copyCollection(usersCollectionName, backupUsersCollectionName); + if (!status.isOK()) + return status; + status = _externalState->dropCollection(newusersCollectionName); + if (!status.isOK()) + return status; + status = _externalState->createIndex( + newusersCollectionName, + BSON(USER_NAME_FIELD_NAME << 1 << USER_SOURCE_FIELD_NAME << 1), + true // unique + ); + if (!status.isOK()) + return status; + for (unordered_map<UserName, User*>::const_iterator iter = _userCache.begin(); + iter != _userCache.end(); ++iter) { + + // Do not create a user document for the internal user. + if (iter->second == internalSecurity.user) + continue; + + status = _externalState->insert( + newusersCollectionName, userAsV2PrivilegeDocument(*iter->second)); + if (!status.isOK()) + return status; + } + status = _externalState->renameCollection(newusersCollectionName, usersCollectionName); + if (!status.isOK()) + return status; + status = _externalState->updateOne( + versionCollectionName, + versionDocumentQuery, + BSON("$set" << BSON("currentVersion" << 2)), + true); + if (!status.isOK()) + return status; + _version = 2; + return status; + } + } // namespace mongo diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h index e080c9635e9..e8f36e25598 100644 --- a/src/mongo/db/auth/authorization_manager.h +++ b/src/mongo/db/auth/authorization_manager.h @@ -179,6 +179,22 @@ namespace mongo { Status _initializeUserFromPrivilegeDocument(User* user, const BSONObj& privDoc) const; + /** + * Upgrades authorization data stored in collections from the v1 form (one system.users + * collection per database) to the v2 form (a single admin.system.users collection). + * + * Returns Status::OK() if the AuthorizationManager and the admin.system.version collection + * agree that the system is already upgraded, or if the upgrade completes successfully. + * + * This method will create and destroy an admin._newusers collection in addition to writing + * to admin.system.users and admin.system.version. + * + * User information is taken from the in-memory user cache, constructed at start-up. This + * is safe to do because MongoD and MongoS build complete copies of the data stored in + * *.system.users at start-up if they detect that the upgrade has not yet completed. + */ + Status upgradeAuthCollections(); + private: /** diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp index eb3d8472884..4ae65310108 100644 --- a/src/mongo/db/auth/authorization_manager_test.cpp +++ b/src/mongo/db/auth/authorization_manager_test.cpp @@ -321,13 +321,12 @@ namespace { TEST_F(AuthorizationManagerTest, testAquireV0User) { - externalState->insertPrivilegeDocument("test", - BSON("user" << "v0RW" << - "pwd" << "password")); - externalState->insertPrivilegeDocument("admin", - BSON("user" << "v0AdminRO" << - "pwd" << "password" << - "readOnly" << true)); + ASSERT_OK(externalState->insertPrivilegeDocument( + "test", + BSON("user" << "v0RW" << "pwd" << "password"))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "admin", + BSON("user" << "v0AdminRO" << "pwd" << "password" << "readOnly" << true))); User* v0RW; ASSERT_OK(authzManager->acquireUser(UserName("v0RW", "test"), &v0RW)); @@ -372,14 +371,16 @@ namespace { } TEST_F(AuthorizationManagerTest, testAquireV1User) { - externalState->insertPrivilegeDocument("test", - BSON("user" << "v1read" << - "pwd" << "password" << - "roles" << BSON_ARRAY("read"))); - externalState->insertPrivilegeDocument("admin", - BSON("user" << "v1cluster" << - "pwd" << "password" << - "roles" << BSON_ARRAY("clusterAdmin"))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "test", + BSON("user" << "v1read" << + "pwd" << "password" << + "roles" << BSON_ARRAY("read")))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "admin", + BSON("user" << "v1cluster" << + "pwd" << "password" << + "roles" << BSON_ARRAY("clusterAdmin")))); User* v1read; ASSERT_OK(authzManager->acquireUser(UserName("v1read", "test"), &v1read)); @@ -422,22 +423,26 @@ namespace { } TEST_F(AuthorizationManagerTest, initializeAllV1UserData) { - externalState->insertPrivilegeDocument("test", - BSON("user" << "readOnly" << - "pwd" << "password" << - "roles" << BSON_ARRAY("read"))); - externalState->insertPrivilegeDocument("admin", - BSON("user" << "clusterAdmin" << - "userSource" << "$external" << - "roles" << BSON_ARRAY("clusterAdmin"))); - externalState->insertPrivilegeDocument("test", - BSON("user" << "readWriteMultiDB" << - "pwd" << "password" << - "roles" << BSON_ARRAY("readWrite"))); - externalState->insertPrivilegeDocument("test2", - BSON("user" << "readWriteMultiDB" << - "userSource" << "test" << - "roles" << BSON_ARRAY("readWrite"))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "test", + BSON("user" << "readOnly" << + "pwd" << "password" << + "roles" << BSON_ARRAY("read")))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "admin", + BSON("user" << "clusterAdmin" << + "userSource" << "$external" << + "roles" << BSON_ARRAY("clusterAdmin")))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "test", + BSON("user" << "readWriteMultiDB" << + "pwd" << "password" << + "roles" << BSON_ARRAY("readWrite")))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "test2", + BSON("user" << "readWriteMultiDB" << + "userSource" << "test" << + "roles" << BSON_ARRAY("readWrite")))); Status status = authzManager->initializeAllV1UserData(); ASSERT_OK(status); @@ -531,10 +536,11 @@ namespace { authzManager->releaseUser(multiDB); } + TEST_F(AuthorizationManagerTest, testAquireV2User) { authzManager->setAuthorizationVersion(2); - externalState->insertPrivilegeDocument( + ASSERT_OK(externalState->insertPrivilegeDocument( "admin", BSON("name" << "v2read" << "source" << "test" << @@ -542,8 +548,8 @@ namespace { "roles" << BSON_ARRAY(BSON("name" << "read" << "source" << "test" << "canDelegate" << false << - "hasRole" << true)))); - externalState->insertPrivilegeDocument( + "hasRole" << true))))); + ASSERT_OK(externalState->insertPrivilegeDocument( "admin", BSON("name" << "v2cluster" << "source" << "admin" << @@ -551,7 +557,7 @@ namespace { "roles" << BSON_ARRAY(BSON("name" << "clusterAdmin" << "source" << "admin" << "canDelegate" << false << - "hasRole" << true)))); + "hasRole" << true))))); User* v2read; ASSERT_OK(authzManager->acquireUser(UserName("v2read", "test"), &v2read)); @@ -592,5 +598,139 @@ namespace { // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(v2cluster); } + + class AuthzUpgradeTest : public AuthorizationManagerTest { + public: + static const NamespaceString versionCollectionName; + static const NamespaceString usersCollectionName; + static const NamespaceString backupUsersCollectionName; + static const NamespaceString newUsersCollectioName; + + void setUpV1UserData() { + ASSERT_OK(externalState->insertPrivilegeDocument( + "test", + BSON("user" << "readOnly" << + "pwd" << "password" << + "roles" << BSON_ARRAY("read")))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "admin", + BSON("user" << "clusterAdmin" << + "userSource" << "$external" << + "roles" << BSON_ARRAY("clusterAdmin")))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "test", + BSON("user" << "readWriteMultiDB" << + "pwd" << "password" << + "roles" << BSON_ARRAY("readWrite")))); + ASSERT_OK(externalState->insertPrivilegeDocument( + "test2", + BSON("user" << "readWriteMultiDB" << + "userSource" << "test" << + "roles" << BSON_ARRAY("readWrite")))); + + ASSERT_OK(authzManager->initializeAllV1UserData()); + } + + void validateV1AdminUserData(const NamespaceString& collectionName) { + BSONObj doc; + + // Verify that the expected users are present. + ASSERT_EQUALS(1U, externalState->getCollectionContents(collectionName).size()); + ASSERT_OK(externalState->findOne(collectionName, + BSON("user" << "clusterAdmin" << + "userSource" << "$external"), + &doc)); + ASSERT_EQUALS("clusterAdmin", doc["user"].str()); + ASSERT_EQUALS("$external", doc["userSource"].str()); + ASSERT_TRUE(doc["pwd"].eoo()); + ASSERT_EQUALS(1U, doc["roles"].Array().size()); + ASSERT_EQUALS("clusterAdmin", doc["roles"].Array()[0].str()); + } + + void validateV2UserData() { + BSONObj doc; + + // Verify that the admin.system.version document reflects correct upgrade. + ASSERT_OK(externalState->findOne(versionCollectionName, + BSON("_id" << 1 << "currentVersion" << 2), + &doc)); + ASSERT_EQUALS(2, doc.nFields()); + ASSERT_EQUALS(1U, externalState->getCollectionContents(versionCollectionName).size()); + + // Verify that the admin._newusers collection was dropped. + ASSERT_EQUALS(0U, externalState->getCollectionContents(newUsersCollectioName).size()); + + // Verify that the expected users are present. + ASSERT_EQUALS(3U, externalState->getCollectionContents(usersCollectionName).size()); + ASSERT_OK(externalState->findOne(usersCollectionName, + BSON("name" << "readOnly" << "source" << "test"), + &doc)); + ASSERT_EQUALS("readOnly", doc["name"].str()); + ASSERT_EQUALS("test", doc["source"].str()); + ASSERT_EQUALS("password", doc["credentials"]["MONGODB-CR"].str()); + ASSERT_EQUALS(1U, doc["roles"].Array().size()); + + ASSERT_OK(externalState->findOne( + usersCollectionName, + BSON("name" << "clusterAdmin" << "source" << "$external"), + &doc)); + ASSERT_EQUALS("clusterAdmin", doc["name"].str()); + ASSERT_EQUALS("$external", doc["source"].str()); + ASSERT_EQUALS(1U, doc["roles"].Array().size()); + + ASSERT_OK(externalState->findOne( + usersCollectionName, + BSON("name" << "readWriteMultiDB" << "source" << "test"), + &doc)); + ASSERT_EQUALS("readWriteMultiDB", doc["name"].str()); + ASSERT_EQUALS("test", doc["source"].str()); + ASSERT_EQUALS("password", doc["credentials"]["MONGODB-CR"].str()); + ASSERT_EQUALS(2U, doc["roles"].Array().size()); + } + }; + + const NamespaceString AuthzUpgradeTest::versionCollectionName("admin.system.version"); + const NamespaceString AuthzUpgradeTest::usersCollectionName("admin.system.users"); + const NamespaceString AuthzUpgradeTest::backupUsersCollectionName("admin.backup.users"); + const NamespaceString AuthzUpgradeTest::newUsersCollectioName("admin._newusers"); + + TEST_F(AuthzUpgradeTest, upgradeUserDataFromV1ToV2Clean) { + setUpV1UserData(); + ASSERT_OK(authzManager->upgradeAuthCollections()); + + validateV2UserData(); + validateV1AdminUserData(backupUsersCollectionName); + } + + TEST_F(AuthzUpgradeTest, upgradeUserDataFromV1ToV2WithSysVerDoc) { + setUpV1UserData(); + ASSERT_OK(externalState->insert(versionCollectionName, + BSON("_id" << 1 << "currentVersion" << 1))); + ASSERT_OK(authzManager->upgradeAuthCollections()); + + validateV1AdminUserData(backupUsersCollectionName); + validateV2UserData(); + } + + TEST_F(AuthzUpgradeTest, upgradeUserDataFromV1ToV2FailsWithBadInitialVersionDoc) { + setUpV1UserData(); + ASSERT_OK(externalState->insert(versionCollectionName, + BSON("_id" << 1 << "currentVersion" << 3))); + ASSERT_NOT_OK(authzManager->upgradeAuthCollections()); + validateV1AdminUserData(usersCollectionName); + ASSERT_OK(externalState->remove(versionCollectionName, BSONObj())); + ASSERT_OK(authzManager->upgradeAuthCollections()); + validateV1AdminUserData(backupUsersCollectionName); + validateV2UserData(); + } + + TEST_F(AuthzUpgradeTest, upgradeUserDataFromV1ToV2FailsWithVersionDocMispatch) { + setUpV1UserData(); + ASSERT_OK(externalState->insert(versionCollectionName, + BSON("_id" << 1 << "currentVersion" << 2))); + ASSERT_NOT_OK(authzManager->upgradeAuthCollections()); + validateV1AdminUserData(usersCollectionName); + } + } // namespace } // namespace mongo diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp index d4f506315a9..fc4f9f70510 100644 --- a/src/mongo/db/auth/authorization_session_test.cpp +++ b/src/mongo/db/auth/authorization_session_test.cpp @@ -43,7 +43,7 @@ namespace { virtual Status _findUser(const std::string& usersNamespace, const BSONObj& query, - BSONObj* result) const { + BSONObj* result) { if (_findsShouldFail) { return Status(ErrorCodes::UnknownError, "_findUser set to fail in mock."); } diff --git a/src/mongo/db/auth/authz_manager_external_state.cpp b/src/mongo/db/auth/authz_manager_external_state.cpp index dd14e79b7ec..f982cffe69d 100644 --- a/src/mongo/db/auth/authz_manager_external_state.cpp +++ b/src/mongo/db/auth/authz_manager_external_state.cpp @@ -30,7 +30,7 @@ namespace mongo { Status AuthzManagerExternalState::getPrivilegeDocument(const UserName& userName, int authzVersion, - BSONObj* result) const { + BSONObj* result) { if (userName == internalSecurity.user->getName()) { return Status(ErrorCodes::InternalError, "Requested privilege document for the internal user"); @@ -88,7 +88,7 @@ namespace mongo { return Status::OK(); } - bool AuthzManagerExternalState::hasAnyPrivilegeDocuments() const { + bool AuthzManagerExternalState::hasAnyPrivilegeDocuments() { std::string usersNamespace = "admin.system.users"; BSONObj userBSONObj; diff --git a/src/mongo/db/auth/authz_manager_external_state.h b/src/mongo/db/auth/authz_manager_external_state.h index e31fdc88813..89ecbc3603e 100644 --- a/src/mongo/db/auth/authz_manager_external_state.h +++ b/src/mongo/db/auth/authz_manager_external_state.h @@ -23,6 +23,7 @@ #include "mongo/base/status.h" #include "mongo/db/auth/user_name.h" #include "mongo/db/jsobj.h" +#include "mongo/db/namespace_string.h" namespace mongo { @@ -46,36 +47,106 @@ namespace mongo { // "result". Status getPrivilegeDocument(const UserName& userName, int authzVersion, - BSONObj* result) const; + BSONObj* result); // Returns true if there exists at least one privilege document in the system. - bool hasAnyPrivilegeDocuments() const; + bool hasAnyPrivilegeDocuments(); // Creates the given user object in the given database. // TODO(spencer): remove dbname argument once users are only written into the admin db virtual Status insertPrivilegeDocument(const std::string& dbname, - const BSONObj& userObj) const = 0; + const BSONObj& userObj) = 0; // Updates the given user object with the given update modifier. virtual Status updatePrivilegeDocument(const UserName& user, - const BSONObj& updateObj) const = 0; + const BSONObj& updateObj) = 0; // Removes users for the given database matching the given query. // TODO(spencer): remove dbname argument once users are only written into the admin db virtual Status removePrivilegeDocuments(const std::string& dbname, - const BSONObj& query) const = 0; + const BSONObj& query) = 0; /** * Puts into the *dbnames vector the name of every database in the cluster. */ - virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames) const = 0; + virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames) = 0; /** * Puts into the *privDocs vector every privilege document from the given database's * system.users collection. */ virtual Status getAllV1PrivilegeDocsForDB(const std::string& dbname, - std::vector<BSONObj>* privDocs) const = 0; + std::vector<BSONObj>* privDocs) = 0; + + /** + * Finds a document matching "query" in "collectionName", and store a shared-ownership + * copy into "result". + * + * Returns Status::OK() on success. If no match is found, returns + * ErrorCodes::NoMatchingDocument. Other errors returned as appropriate. + */ + virtual Status findOne(const NamespaceString& collectionName, + const BSONObj& query, + BSONObj* result) = 0; + + /** + * Inserts "document" into "collectionName". + */ + virtual Status insert(const NamespaceString& collectionName, + const BSONObj& document) = 0; + + /** + * Update one document matching "query" according to "updatePattern" in "collectionName". + * + * If "upsert" is true and no document matches "query", inserts one using "query" as a + * template. + */ + virtual Status updateOne(const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert) = 0; + + /** + * Removes all documents matching "query" from "collectionName". + */ + virtual Status remove(const NamespaceString& collectionName, + const BSONObj& query) = 0; + + /** + * Creates an index with the given pattern on "collectionName". + */ + virtual Status createIndex(const NamespaceString& collectionName, + const BSONObj& pattern, + bool unique) = 0; + + /** + * Drops the named collection. + */ + virtual Status dropCollection(const NamespaceString& collectionName) = 0; + + /** + * Renames collection "oldName" to "newName", possibly dropping the previous + * collection named "newName". + */ + virtual Status renameCollection(const NamespaceString& oldName, + const NamespaceString& newName) = 0; + + /** + * Copies the contents of collection "fromName" into "toName". Fails + * if "toName" is already a collection. + */ + virtual Status copyCollection(const NamespaceString& fromName, + const NamespaceString& toName) = 0; + + /** + * Tries to acquire the global lock guarding the upgrade process. + */ + virtual bool tryLockUpgradeProcess() = 0; + + /** + * Releases the lock guarding the upgrade process, which must already be held. + */ + virtual void unlockUpgradeProcess() = 0; protected: AuthzManagerExternalState(); // This class should never be instantiated directly. @@ -86,7 +157,7 @@ namespace mongo { // errors may return other Status codes. virtual Status _findUser(const std::string& usersNamespace, const BSONObj& query, - BSONObj* result) const = 0; + BSONObj* result) = 0; }; } // namespace mongo diff --git a/src/mongo/db/auth/authz_manager_external_state_d.cpp b/src/mongo/db/auth/authz_manager_external_state_d.cpp index 857511a8a3b..fb7a999f268 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_d.cpp @@ -36,7 +36,7 @@ namespace { AuthzManagerExternalStateMongod::~AuthzManagerExternalStateMongod() {} Status AuthzManagerExternalStateMongod::insertPrivilegeDocument(const string& dbname, - const BSONObj& userObj) const { + const BSONObj& userObj) { try { string userNS = dbname + ".system.users"; DBDirectClient client; @@ -68,7 +68,7 @@ namespace { } Status AuthzManagerExternalStateMongod::updatePrivilegeDocument( - const UserName& user, const BSONObj& updateObj) const { + const UserName& user, const BSONObj& updateObj) { try { string userNS = mongoutils::str::stream() << user.getDB() << ".system.users"; DBDirectClient client; @@ -106,7 +106,7 @@ namespace { } Status AuthzManagerExternalStateMongod::removePrivilegeDocuments(const string& dbname, - const BSONObj& query) const { + const BSONObj& query) { try { string userNS = dbname + ".system.users"; DBDirectClient client; @@ -141,7 +141,7 @@ namespace { Status AuthzManagerExternalStateMongod::_findUser(const string& usersNamespace, const BSONObj& query, - BSONObj* result) const { + BSONObj* result) { Client::GodScope gs; Client::ReadContext ctx(usersNamespace); @@ -152,14 +152,14 @@ namespace { } Status AuthzManagerExternalStateMongod::getAllDatabaseNames( - std::vector<std::string>* dbnames) const { + std::vector<std::string>* dbnames) { Lock::GlobalWrite lk; getDatabaseNames(*dbnames); return Status::OK(); } Status AuthzManagerExternalStateMongod::getAllV1PrivilegeDocsForDB( - const std::string& dbname, std::vector<BSONObj>* privDocs) const { + const std::string& dbname, std::vector<BSONObj>* privDocs) { std::string usersNamespace = dbname + ".system.users"; Client::GodScope gs; @@ -169,4 +169,63 @@ namespace { return Status::OK(); } + Status AuthzManagerExternalStateMongod::findOne( + const NamespaceString& collectionName, + const BSONObj& query, + BSONObj* result) { + fassertFailed(17091); + } + + Status AuthzManagerExternalStateMongod::insert( + const NamespaceString& collectionName, + const BSONObj& document) { + fassertFailed(17092); + } + + Status AuthzManagerExternalStateMongod::updateOne( + const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert) { + fassertFailed(17093); + } + + Status AuthzManagerExternalStateMongod::remove( + const NamespaceString& collectionName, + const BSONObj& query) { + fassertFailed(17094); + } + + Status AuthzManagerExternalStateMongod::createIndex( + const NamespaceString& collectionName, + const BSONObj& pattern, + bool unique) { + fassertFailed(17095); + } + + Status AuthzManagerExternalStateMongod::dropCollection( + const NamespaceString& collectionName) { + fassertFailed(17096); + } + + Status AuthzManagerExternalStateMongod::renameCollection( + const NamespaceString& oldName, + const NamespaceString& newName) { + fassertFailed(17097); + } + + Status AuthzManagerExternalStateMongod::copyCollection( + const NamespaceString& fromName, + const NamespaceString& toName) { + fassertFailed(17098); + } + + bool AuthzManagerExternalStateMongod::tryLockUpgradeProcess() { + fassertFailed(17099); + } + + void AuthzManagerExternalStateMongod::unlockUpgradeProcess() { + fassertFailed(17100); + } + } // namespace mongo diff --git a/src/mongo/db/auth/authz_manager_external_state_d.h b/src/mongo/db/auth/authz_manager_external_state_d.h index e4cac9da17a..1d0b0eb9d8e 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.h +++ b/src/mongo/db/auth/authz_manager_external_state_d.h @@ -36,23 +36,45 @@ namespace mongo { virtual ~AuthzManagerExternalStateMongod(); virtual Status insertPrivilegeDocument(const std::string& dbname, - const BSONObj& userObj) const; + const BSONObj& userObj); virtual Status updatePrivilegeDocument(const UserName& user, - const BSONObj& updateObj) const; + const BSONObj& updateObj); virtual Status removePrivilegeDocuments(const std::string& dbname, - const BSONObj& query) const; + const BSONObj& query); - virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames) const; + virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames); virtual Status getAllV1PrivilegeDocsForDB(const std::string& dbname, - std::vector<BSONObj>* privDocs) const; + std::vector<BSONObj>* privDocs); + + virtual Status findOne(const NamespaceString& collectionName, + const BSONObj& query, + BSONObj* result); + virtual Status insert(const NamespaceString& collectionName, + const BSONObj& document); + virtual Status updateOne(const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert); + virtual Status remove(const NamespaceString& collectionName, + const BSONObj& query); + virtual Status createIndex(const NamespaceString& collectionName, + const BSONObj& pattern, + bool unique); + virtual Status dropCollection(const NamespaceString& collectionName); + virtual Status renameCollection(const NamespaceString& oldName, + const NamespaceString& newName); + virtual Status copyCollection(const NamespaceString& fromName, + const NamespaceString& toName); + virtual bool tryLockUpgradeProcess(); + virtual void unlockUpgradeProcess(); protected: virtual Status _findUser(const string& usersNamespace, const BSONObj& query, - BSONObj* result) const; + BSONObj* result); }; } // namespace mongo diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.cpp b/src/mongo/db/auth/authz_manager_external_state_mock.cpp index 359abe8cc84..0cdd2e20462 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp @@ -19,78 +19,220 @@ #include <string> #include "mongo/base/status.h" +#include "mongo/bson/mutable/algorithm.h" +#include "mongo/bson/mutable/document.h" +#include "mongo/bson/mutable/element.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/namespace_string.h" -#include "mongo/platform/unordered_map.h" +#include "mongo/db/ops/update_driver.h" +#include "mongo/platform/unordered_set.h" +#include "mongo/util/map_util.h" namespace mongo { - Status AuthzManagerExternalStateMock::insertPrivilegeDocument(const std::string& dbname, - const BSONObj& userObj) const { - return Status::OK(); - } - Status AuthzManagerExternalStateMock::updatePrivilegeDocument(const UserName& user, - const BSONObj& updateObj) const { - return Status::OK(); + const BSONObj& updateObj) { + return Status(ErrorCodes::InternalError, "Not implemented in mock."); } Status AuthzManagerExternalStateMock::removePrivilegeDocuments(const std::string& dbname, - const BSONObj& query) const { - return Status::OK(); + const BSONObj& query) { + return Status(ErrorCodes::InternalError, "Not implemented in mock."); } Status AuthzManagerExternalStateMock::insertPrivilegeDocument(const std::string& dbname, const BSONObj& userObj) { - _userDocuments[dbname].push_back(userObj); - return Status::OK(); + NamespaceString usersCollection(dbname + ".system.users"); + return insert(usersCollection, userObj); } void AuthzManagerExternalStateMock::clearPrivilegeDocuments() { - _userDocuments.clear(); + _documents.clear(); } Status AuthzManagerExternalStateMock::getAllDatabaseNames( - std::vector<std::string>* dbnames) const { - unordered_map<std::string, std::vector<BSONObj> >::const_iterator it; - for (it = _userDocuments.begin(); it != _userDocuments.end(); ++it) { - dbnames->push_back(it->first); + std::vector<std::string>* dbnames) { + unordered_set<std::string> dbnameSet; + NamespaceDocumentMap::const_iterator it; + for (it = _documents.begin(); it != _documents.end(); ++it) { + dbnameSet.insert(it->first.db().toString()); } + *dbnames = std::vector<std::string>(dbnameSet.begin(), dbnameSet.end()); return Status::OK(); } Status AuthzManagerExternalStateMock::getAllV1PrivilegeDocsForDB( - const std::string& dbname, std::vector<BSONObj>* privDocs) const { - const std::vector<BSONObj>& dbDocs = _userDocuments.find(dbname)->second; - for (std::vector<BSONObj>::const_iterator it = dbDocs.begin(); it != dbDocs.end(); ++it) { + const std::string& dbname, BSONObjCollection* privDocs) { + NamespaceDocumentMap::const_iterator iter = + _documents.find(NamespaceString(dbname + ".system.users")); + if (iter == _documents.end()) + return Status::OK(); // No system.users collection in DB "dbname". + const BSONObjCollection& dbDocs = iter->second; + for (BSONObjCollection::const_iterator it = dbDocs.begin(); it != dbDocs.end(); ++it) { privDocs->push_back(*it); } return Status::OK(); } + Status AuthzManagerExternalStateMock::_findUser( + const std::string& usersNamespace, + const BSONObj& query, + BSONObj* result) { + if (!findOne(NamespaceString(usersNamespace), query, result).isOK()) { + return Status(ErrorCodes::UserNotFound, + "No matching user for query " + query.toString()); + } + return Status::OK(); + } + + Status AuthzManagerExternalStateMock::findOne( + const NamespaceString& collectionName, + const BSONObj& query, + BSONObj* result) { + BSONObjCollection::iterator iter; + Status status = _findOneIter(collectionName, query, &iter); + if (!status.isOK()) + return status; + *result = iter->copy(); + return Status::OK(); + } + + Status AuthzManagerExternalStateMock::insert( + const NamespaceString& collectionName, + const BSONObj& document) { + _documents[collectionName].push_back(document.copy()); + return Status::OK(); + } + + Status AuthzManagerExternalStateMock::updateOne( + const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert) { + + namespace mmb = mutablebson; + UpdateDriver::Options updateOptions; + updateOptions.upsert = upsert; + UpdateDriver driver(updateOptions); + Status status = driver.parse(updatePattern); + if (!status.isOK()) + return status; + + BSONObjCollection::iterator iter; + status = _findOneIter(collectionName, query, &iter); + mmb::Document document; + if (status.isOK()) { + document.reset(*iter, mmb::Document::kInPlaceDisabled); + status = driver.update(StringData(), &document, NULL); + if (!status.isOK()) + return status; + *iter = document.getObject().copy(); + return Status::OK(); + } + else if (status == ErrorCodes::NoMatchingDocument && upsert) { + if (query.hasField("_id")) { + document.root().appendElement(query["_id"]); + } + status = driver.createFromQuery(query, document); + if (!status.isOK()) { + return status; + } + status = driver.update(StringData(), &document, NULL); + if (!status.isOK()) { + return status; + } + return insert(collectionName, document.getObject()); + } + else { + return status; + } + } + + Status AuthzManagerExternalStateMock::remove( + const NamespaceString& collectionName, + const BSONObj& query) { + BSONObjCollection::iterator iter; + while (_findOneIter(collectionName, query, &iter).isOK()) { + _documents[collectionName].erase(iter); + } + return Status::OK(); + } + + Status AuthzManagerExternalStateMock::createIndex( + const NamespaceString& collectionName, + const BSONObj& pattern, + bool unique) { + return Status::OK(); + } + + Status AuthzManagerExternalStateMock::dropCollection(const NamespaceString& collectionName) { + _documents.erase(collectionName); + return Status::OK(); + } + + Status AuthzManagerExternalStateMock::renameCollection(const NamespaceString& oldName, + const NamespaceString& newName) { + if (_documents.count(oldName) == 0) { + return Status(ErrorCodes::NamespaceNotFound, + "No collection to rename named " + oldName.ns()); + } + std::swap(_documents[newName], _documents[oldName]); + return dropCollection(oldName); + } + + Status AuthzManagerExternalStateMock::copyCollection(const NamespaceString& fromName, + const NamespaceString& toName) { + if (_documents.count(fromName) == 0) { + return Status(ErrorCodes::NamespaceNotFound, + "No collection to copy named " + fromName.ns()); + } + if (_documents.count(toName) > 0) { + return Status(ErrorCodes::NamespaceExists, + "Cannot copy into existing namespace " + fromName.ns()); + } + + _documents[toName] = _documents[fromName]; + return Status::OK(); + } + + bool AuthzManagerExternalStateMock::tryLockUpgradeProcess() { + return true; + } + + void AuthzManagerExternalStateMock::unlockUpgradeProcess() {} + + std::vector<BSONObj> AuthzManagerExternalStateMock::getCollectionContents( + const NamespaceString& collectionName) { + return mapFindWithDefault(_documents, collectionName, std::vector<BSONObj>()); + } + + Status AuthzManagerExternalStateMock::_findOneIter( + const NamespaceString& collectionName, + const BSONObj& query, + BSONObjCollection::iterator* result) { - Status AuthzManagerExternalStateMock::_findUser(const std::string& usersNamespace, - const BSONObj& query, - BSONObj* result) const { StatusWithMatchExpression parseResult = MatchExpressionParser::parse(query); if (!parseResult.isOK()) { return parseResult.getStatus(); } MatchExpression* matcher = parseResult.getValue(); - unordered_map<std::string, std::vector<BSONObj> >::const_iterator mapIt; - for (mapIt = _userDocuments.begin(); mapIt != _userDocuments.end(); ++mapIt) { - for (std::vector<BSONObj>::const_iterator vecIt = mapIt->second.begin(); - vecIt != mapIt->second.end(); ++vecIt) { - if (nsToDatabase(usersNamespace) == mapIt->first && - matcher->matchesBSON(*vecIt)) { - *result = *vecIt; - return Status::OK(); - } + NamespaceDocumentMap::iterator mapIt = _documents.find(collectionName); + if (mapIt == _documents.end()) + return Status(ErrorCodes::NoMatchingDocument, + "No collection named " + collectionName.ns()); + + for (BSONObjCollection::iterator vecIt = mapIt->second.begin(); + vecIt != mapIt->second.end(); + ++vecIt) { + + if (matcher->matchesBSON(*vecIt)) { + *result = vecIt; + return Status::OK(); } } - return Status(ErrorCodes::UserNotFound, "User not found"); + return Status(ErrorCodes::NoMatchingDocument, "No matching document"); } } // namespace mongo diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.h b/src/mongo/db/auth/authz_manager_external_state_mock.h index 7551af9c427..e835966929e 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.h +++ b/src/mongo/db/auth/authz_manager_external_state_mock.h @@ -17,13 +17,14 @@ #pragma once #include <string> +#include <map> #include <vector> #include "mongo/base/disallow_copying.h" #include "mongo/base/status.h" #include "mongo/db/auth/authz_manager_external_state.h" #include "mongo/db/jsobj.h" -#include "mongo/platform/unordered_map.h" +#include "mongo/db/namespace_string.h" namespace mongo { @@ -37,35 +38,64 @@ namespace mongo { AuthzManagerExternalStateMock() {}; - // no-op for the mock virtual Status insertPrivilegeDocument(const std::string& dbname, - const BSONObj& userObj) const; + const BSONObj& userObj); - // no-op for the mock virtual Status updatePrivilegeDocument(const UserName& user, - const BSONObj& updateObj) const; + const BSONObj& updateObj); - // no-op for the mock virtual Status removePrivilegeDocuments(const std::string& dbname, - const BSONObj& query) const; - - // Non-const version that puts document into a vector that can be accessed later - Status insertPrivilegeDocument(const std::string& dbname, const BSONObj& userObj); + const BSONObj& query); void clearPrivilegeDocuments(); - virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames) const; + virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames); virtual Status getAllV1PrivilegeDocsForDB(const std::string& dbname, - std::vector<BSONObj>* privDocs) const; + std::vector<BSONObj>* privDocs); virtual Status _findUser(const std::string& usersNamespace, const BSONObj& query, - BSONObj* result) const; + BSONObj* result); + + virtual Status findOne(const NamespaceString& collectionName, + const BSONObj& query, + BSONObj* result); + + // This implementation does not understand uniqueness constraints. + virtual Status insert(const NamespaceString& collectionName, + const BSONObj& document); + // This implementation does not understand uniqueness constraints, + // and only correctly handles some upsert behaviors. + virtual Status updateOne(const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert); + virtual Status remove(const NamespaceString& collectionName, + const BSONObj& query); + virtual Status createIndex(const NamespaceString& collectionName, + const BSONObj& pattern, + bool unique); + virtual Status dropCollection(const NamespaceString& collectionName); + virtual Status renameCollection(const NamespaceString& oldName, + const NamespaceString& newName); + virtual Status copyCollection(const NamespaceString& fromName, + const NamespaceString& toName); + virtual bool tryLockUpgradeProcess(); + virtual void unlockUpgradeProcess(); + + std::vector<BSONObj> getCollectionContents(const NamespaceString& collectionName); private: - unordered_map<std::string, std::vector<BSONObj> > _userDocuments; // dbname to user docs + typedef std::vector<BSONObj> BSONObjCollection; + typedef std::map<NamespaceString, BSONObjCollection> NamespaceDocumentMap; + + Status _findOneIter(const NamespaceString& collectionName, + const BSONObj& query, + BSONObjCollection::iterator* result); + + NamespaceDocumentMap _documents; // Mock database. }; } // namespace mongo diff --git a/src/mongo/db/auth/authz_manager_external_state_s.cpp b/src/mongo/db/auth/authz_manager_external_state_s.cpp index a0b3bd35b61..ed6fd9e9828 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp @@ -52,7 +52,7 @@ namespace { Status AuthzManagerExternalStateMongos::_findUser(const string& usersNamespace, const BSONObj& query, - BSONObj* result) const { + BSONObj* result) { try { scoped_ptr<ScopedDbConnection> conn(getConnectionForUsersCollection(usersNamespace)); *result = conn->get()->findOne(usersNamespace, query).getOwned(); @@ -67,7 +67,7 @@ namespace { } Status AuthzManagerExternalStateMongos::insertPrivilegeDocument(const string& dbname, - const BSONObj& userObj) const { + const BSONObj& userObj) { try { string userNS = dbname + ".system.users"; scoped_ptr<ScopedDbConnection> conn(getConnectionForUsersCollection(userNS)); @@ -94,7 +94,7 @@ namespace { } Status AuthzManagerExternalStateMongos::updatePrivilegeDocument( - const UserName& user, const BSONObj& updateObj) const { + const UserName& user, const BSONObj& updateObj) { try { string userNS = mongoutils::str::stream() << user.getDB() << ".system.users"; scoped_ptr<ScopedDbConnection> conn(getConnectionForUsersCollection(userNS)); @@ -127,7 +127,7 @@ namespace { } Status AuthzManagerExternalStateMongos::removePrivilegeDocuments(const string& dbname, - const BSONObj& query) const { + const BSONObj& query) { try { string userNS = dbname + ".system.users"; scoped_ptr<ScopedDbConnection> conn(getConnectionForUsersCollection(userNS)); @@ -156,7 +156,7 @@ namespace { } Status AuthzManagerExternalStateMongos::getAllDatabaseNames( - std::vector<std::string>* dbnames) const { + std::vector<std::string>* dbnames) { try { scoped_ptr<ScopedDbConnection> conn( getConnectionForUsersCollection(DatabaseType::ConfigNS)); @@ -179,7 +179,7 @@ namespace { } Status AuthzManagerExternalStateMongos::getAllV1PrivilegeDocsForDB( - const std::string& dbname, std::vector<BSONObj>* privDocs) const { + const std::string& dbname, std::vector<BSONObj>* privDocs) { try { std::string usersNamespace = dbname + ".system.users"; scoped_ptr<ScopedDbConnection> conn(getConnectionForUsersCollection(usersNamespace)); @@ -195,4 +195,63 @@ namespace { } } + Status AuthzManagerExternalStateMongos::findOne( + const NamespaceString& collectionName, + const BSONObj& query, + BSONObj* result) { + fassertFailed(17101); + } + + Status AuthzManagerExternalStateMongos::insert( + const NamespaceString& collectionName, + const BSONObj& document) { + fassertFailed(17102); + } + + Status AuthzManagerExternalStateMongos::updateOne( + const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert) { + fassertFailed(17103); + } + + Status AuthzManagerExternalStateMongos::remove( + const NamespaceString& collectionName, + const BSONObj& query) { + fassertFailed(17104); + } + + Status AuthzManagerExternalStateMongos::createIndex( + const NamespaceString& collectionName, + const BSONObj& pattern, + bool unique) { + fassertFailed(17105); + } + + Status AuthzManagerExternalStateMongos::dropCollection( + const NamespaceString& collectionName) { + fassertFailed(17106); + } + + Status AuthzManagerExternalStateMongos::renameCollection( + const NamespaceString& oldName, + const NamespaceString& newName) { + fassertFailed(17107); + } + + Status AuthzManagerExternalStateMongos::copyCollection( + const NamespaceString& fromName, + const NamespaceString& toName) { + fassertFailed(17108); + } + + bool AuthzManagerExternalStateMongos::tryLockUpgradeProcess() { + fassertFailed(17109); + } + + void AuthzManagerExternalStateMongos::unlockUpgradeProcess() { + fassertFailed(17110); + } + } // namespace mongo diff --git a/src/mongo/db/auth/authz_manager_external_state_s.h b/src/mongo/db/auth/authz_manager_external_state_s.h index 4a9f72ded7f..12cbfb667f7 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.h +++ b/src/mongo/db/auth/authz_manager_external_state_s.h @@ -36,23 +36,45 @@ namespace mongo { virtual ~AuthzManagerExternalStateMongos(); virtual Status insertPrivilegeDocument(const std::string& dbname, - const BSONObj& userObj) const; + const BSONObj& userObj); virtual Status updatePrivilegeDocument(const UserName& user, - const BSONObj& updateObj) const; + const BSONObj& updateObj); virtual Status removePrivilegeDocuments(const std::string& dbname, - const BSONObj& query) const; + const BSONObj& query); - virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames) const; + virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames); virtual Status getAllV1PrivilegeDocsForDB(const std::string& dbname, - std::vector<BSONObj>* privDocs) const; + std::vector<BSONObj>* privDocs); + + virtual Status findOne(const NamespaceString& collectionName, + const BSONObj& query, + BSONObj* result); + virtual Status insert(const NamespaceString& collectionName, + const BSONObj& document); + virtual Status updateOne(const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert); + virtual Status remove(const NamespaceString& collectionName, + const BSONObj& query); + virtual Status createIndex(const NamespaceString& collectionName, + const BSONObj& pattern, + bool unique); + virtual Status dropCollection(const NamespaceString& collectionName); + virtual Status renameCollection(const NamespaceString& oldName, + const NamespaceString& newName); + virtual Status copyCollection(const NamespaceString& fromName, + const NamespaceString& toName); + virtual bool tryLockUpgradeProcess(); + virtual void unlockUpgradeProcess(); protected: virtual Status _findUser(const string& usersNamespace, const BSONObj& query, - BSONObj* result) const; + BSONObj* result); }; } // namespace mongo diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h index 56ecd38daac..8658aec5eaa 100644 --- a/src/mongo/db/namespace_string.h +++ b/src/mongo/db/namespace_string.h @@ -65,6 +65,8 @@ namespace mongo { bool operator!=( const string& nsIn ) const { return nsIn != _ns; } bool operator!=( const NamespaceString& nsIn ) const { return nsIn._ns != _ns; } + bool operator<( const NamespaceString& rhs ) const { return _ns < rhs._ns; } + /** ( foo.bar ).getSisterNS( "blah" ) == foo.blah */ string getSisterNS( const StringData& local ) const; |