summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@10gen.com>2013-08-23 17:13:35 -0400
committerAndy Schwerin <schwerin@10gen.com>2013-09-03 18:14:01 -0400
commit5fb2c2c35426d907057bccf6ffefec0493897af6 (patch)
tree3f4106feb72f3d3eb1f769a98c9b12de65dad785 /src/mongo/db
parent2f0c929ee17921cf122a3f3fb73f826841126a0c (diff)
downloadmongo-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/SConscript3
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp172
-rw-r--r--src/mongo/db/auth/authorization_manager.h16
-rw-r--r--src/mongo/db/auth/authorization_manager_test.cpp210
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp2
-rw-r--r--src/mongo/db/auth/authz_manager_external_state.cpp4
-rw-r--r--src/mongo/db/auth/authz_manager_external_state.h87
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_d.cpp71
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_d.h34
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.cpp208
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.h58
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.cpp71
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.h34
-rw-r--r--src/mongo/db/namespace_string.h2
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;