diff options
-rw-r--r-- | src/mongo/db/auth/authorization_manager.cpp | 119 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager.h | 82 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager_test.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_session_test.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state.cpp | 89 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state.h | 73 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_d.cpp | 86 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_d.h | 17 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_mock.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_mock.h | 7 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_s.cpp | 50 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_s.h | 18 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.cpp | 684 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.h | 50 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands_common.cpp | 173 |
15 files changed, 614 insertions, 854 deletions
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp index 4a1def087c4..1cd1a137450 100644 --- a/src/mongo/db/auth/authorization_manager.cpp +++ b/src/mongo/db/auth/authorization_manager.cpp @@ -329,107 +329,6 @@ namespace mongo { return _privilegeDocsExist; } - Status AuthorizationManager::writeAuthSchemaVersionIfNeeded(OperationContext* txn, - int foundSchemaVersion) { - Status status = _externalState->updateOne( - txn, - AuthorizationManager::versionCollectionNamespace, - AuthorizationManager::versionDocumentQuery, - BSON("$set" << BSON(AuthorizationManager::schemaVersionFieldName << - foundSchemaVersion)), - true, // upsert - BSONObj()); // write concern - if (status == ErrorCodes::NoMatchingDocument) { // SERVER-11492 - status = Status::OK(); - } - return status; - } - - Status AuthorizationManager::insertPrivilegeDocument(OperationContext* txn, - const std::string& dbname, - const BSONObj& userObj, - const BSONObj& writeConcern) const { - return _externalState->insertPrivilegeDocument(txn, dbname, userObj, writeConcern); - } - - Status AuthorizationManager::updatePrivilegeDocument(OperationContext* txn, - const UserName& user, - const BSONObj& updateObj, - const BSONObj& writeConcern) const { - return _externalState->updatePrivilegeDocument(txn, user, updateObj, writeConcern); - } - - Status AuthorizationManager::removePrivilegeDocuments(OperationContext* txn, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved) const { - return _externalState->removePrivilegeDocuments(txn, query, writeConcern, numRemoved); - } - - Status AuthorizationManager::removeRoleDocuments(OperationContext* txn, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved) const { - Status status = _externalState->remove(txn, - rolesCollectionNamespace, - query, - writeConcern, - numRemoved); - if (status.code() == ErrorCodes::UnknownError) { - return Status(ErrorCodes::RoleModificationFailed, status.reason()); - } - return status; - } - - Status AuthorizationManager::insertRoleDocument(OperationContext* txn, - const BSONObj& roleObj, - const BSONObj& writeConcern) const { - Status status = _externalState->insert(txn, - rolesCollectionNamespace, - roleObj, - writeConcern); - if (status.isOK()) { - return status; - } - if (status.code() == ErrorCodes::DuplicateKey) { - std::string name = roleObj[AuthorizationManager::ROLE_NAME_FIELD_NAME].String(); - std::string source = roleObj[AuthorizationManager::ROLE_DB_FIELD_NAME].String(); - return Status(ErrorCodes::DuplicateKey, - mongoutils::str::stream() << "Role \"" << name << "@" << source << - "\" already exists"); - } - if (status.code() == ErrorCodes::UnknownError) { - return Status(ErrorCodes::RoleModificationFailed, status.reason()); - } - return status; - } - - Status AuthorizationManager::updateRoleDocument(OperationContext* txn, - const RoleName& role, - const BSONObj& updateObj, - const BSONObj& writeConcern) const { - Status status = _externalState->updateOne( - txn, - rolesCollectionNamespace, - BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() << - AuthorizationManager::ROLE_DB_FIELD_NAME << role.getDB()), - updateObj, - false, - writeConcern); - if (status.isOK()) { - return status; - } - if (status.code() == ErrorCodes::NoMatchingDocument) { - return Status(ErrorCodes::RoleNotFound, - mongoutils::str::stream() << "Role " << role.getFullName() << - " not found"); - } - if (status.code() == ErrorCodes::UnknownError) { - return Status(ErrorCodes::RoleModificationFailed, status.reason()); - } - return status; - } - Status AuthorizationManager::queryAuthzDocument( OperationContext* txn, const NamespaceString& collectionName, @@ -439,24 +338,6 @@ namespace mongo { return _externalState->query(txn, collectionName, query, projection, resultProcessor); } - Status AuthorizationManager::updateAuthzDocuments(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& updatePattern, - bool upsert, - bool multi, - const BSONObj& writeConcern, - int* nMatched) const { - return _externalState->update(txn, - collectionName, - query, - updatePattern, - upsert, - multi, - writeConcern, - nMatched); - } - Status AuthorizationManager::getBSONForPrivileges(const PrivilegeVector& privileges, mutablebson::Element resultArray) { for (PrivilegeVector::const_iterator it = privileges.begin(); diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h index 7a42df327db..1f8db64b6d9 100644 --- a/src/mongo/db/auth/authorization_manager.h +++ b/src/mongo/db/auth/authorization_manager.h @@ -199,88 +199,6 @@ namespace mongo { bool hasAnyPrivilegeDocuments(OperationContext* txn); /** - * Updates the auth schema version document to reflect the current state of the system. - * 'foundSchemaVersion' is the authSchemaVersion to update with. - */ - Status writeAuthSchemaVersionIfNeeded(OperationContext* txn, - int foundSchemaVersion); - - /** - * Creates the given user object in the given database. - * 'writeConcern' contains the arguments to be passed to getLastError to block for - * successful completion of the write. - */ - Status insertPrivilegeDocument(OperationContext* txn, - const std::string& dbname, - const BSONObj& userObj, - const BSONObj& writeConcern) const; - - /** - * Updates the given user object with the given update modifier. - * 'writeConcern' contains the arguments to be passed to getLastError to block for - * successful completion of the write. - */ - Status updatePrivilegeDocument(OperationContext* txn, - const UserName& user, - const BSONObj& updateObj, - const BSONObj& writeConcern) const; - - /* - * Removes users for the given database matching the given query. - * Writes into *numRemoved the number of user documents that were modified. - * 'writeConcern' contains the arguments to be passed to getLastError to block for - * successful completion of the write. - */ - Status removePrivilegeDocuments(OperationContext* txn, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved) const; - - /** - * Creates the given role object in the given database. - * 'writeConcern' contains the arguments to be passed to getLastError to block for - * successful completion of the write. - */ - Status insertRoleDocument(OperationContext* txn, - const BSONObj& roleObj, - const BSONObj& writeConcern) const; - - /** - * Updates the given role object with the given update modifier. - * 'writeConcern' contains the arguments to be passed to getLastError to block for - * successful completion of the write. - */ - Status updateRoleDocument(OperationContext* txn, - const RoleName& role, - const BSONObj& updateObj, - const BSONObj& writeConcern) const; - - /** - * Updates documents matching "query" according to "updatePattern" in "collectionName". - * Should only be called on collections with authorization documents in them - * (ie admin.system.users and admin.system.roles). - */ - Status updateAuthzDocuments(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& updatePattern, - bool upsert, - bool multi, - const BSONObj& writeConcern, - int* nMatched) const; - - /* - * Removes roles matching the given query. - * Writes into *numRemoved the number of role documents that were modified. - * 'writeConcern' contains the arguments to be passed to getLastError to block for - * successful completion of the write. - */ - Status removeRoleDocuments(OperationContext* txn, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved) const; - - /** * Finds all documents matching "query" in "collectionName". For each document returned, * calls the function resultProcessor on it. * Should only be called on collections with authorization documents in them diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp index d91d09f499a..65a2f84243c 100644 --- a/src/mongo/db/auth/authorization_manager_test.cpp +++ b/src/mongo/db/auth/authorization_manager_test.cpp @@ -178,7 +178,6 @@ namespace { ASSERT_OK(externalState->insertPrivilegeDocument( &txn, - "admin", BSON("_id" << "admin.v2read" << "user" << "v2read" << "db" << "test" << @@ -187,7 +186,6 @@ namespace { BSONObj())); ASSERT_OK(externalState->insertPrivilegeDocument( &txn, - "admin", BSON("_id" << "admin.v2cluster" << "user" << "v2cluster" << "db" << "admin" << diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp index 5e55ed3b93a..5ce06edb4a7 100644 --- a/src/mongo/db/auth/authorization_session_test.cpp +++ b/src/mongo/db/auth/authorization_session_test.cpp @@ -138,7 +138,6 @@ namespace { // Add a user with readWrite and dbAdmin on the test DB ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "spencer" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -158,7 +157,6 @@ namespace { // Add an admin user with readWriteAnyDatabase ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "admin" << "db" << "admin" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -200,7 +198,6 @@ namespace { TEST_F(AuthorizationSessionTest, DuplicateRolesOK) { // Add a user with doubled-up readWrite and single dbAdmin on the test DB ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "spencer" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -223,7 +220,6 @@ namespace { TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) { ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "rw" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -233,7 +229,6 @@ namespace { "db" << "test"))), BSONObj())); ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "useradmin" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -241,7 +236,6 @@ namespace { "db" << "test"))), BSONObj())); ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "rwany" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -251,7 +245,6 @@ namespace { "db" << "admin"))), BSONObj())); ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "useradminany" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -341,7 +334,6 @@ namespace { TEST_F(AuthorizationSessionTest, InvalidateUser) { // Add a readWrite user ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "spencer" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -367,7 +359,6 @@ namespace { BSONObj(), &ignored); ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "spencer" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -406,7 +397,6 @@ namespace { TEST_F(AuthorizationSessionTest, UseOldUserInfoInFaceOfConnectivityProblems) { // Add a readWrite user ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "spencer" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << @@ -433,7 +423,6 @@ namespace { BSONObj(), &ignored); ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - "admin", BSON("user" << "spencer" << "db" << "test" << "credentials" << BSON("MONGODB-CR" << "a") << diff --git a/src/mongo/db/auth/authz_manager_external_state.cpp b/src/mongo/db/auth/authz_manager_external_state.cpp index 9d9d1763439..ded9792e7c2 100644 --- a/src/mongo/db/auth/authz_manager_external_state.cpp +++ b/src/mongo/db/auth/authz_manager_external_state.cpp @@ -59,93 +59,4 @@ namespace mongo { return status != ErrorCodes::NoMatchingDocument; } - - Status AuthzManagerExternalState::insertPrivilegeDocument(OperationContext* txn, - const string& dbname, - const BSONObj& userObj, - const BSONObj& writeConcern) { - Status status = insert(txn, NamespaceString("admin.system.users"), userObj, writeConcern); - if (status.isOK()) { - return status; - } - if (status.code() == ErrorCodes::DuplicateKey) { - std::string name = userObj[AuthorizationManager::USER_NAME_FIELD_NAME].String(); - std::string source = userObj[AuthorizationManager::USER_DB_FIELD_NAME].String(); - return Status(ErrorCodes::DuplicateKey, - mongoutils::str::stream() << "User \"" << name << "@" << source << - "\" already exists"); - } - if (status.code() == ErrorCodes::UnknownError) { - return Status(ErrorCodes::UserModificationFailed, status.reason()); - } - return status; - } - - Status AuthzManagerExternalState::updatePrivilegeDocument(OperationContext* txn, - const UserName& user, - const BSONObj& updateObj, - const BSONObj& writeConcern) { - Status status = updateOne( - txn, - NamespaceString("admin.system.users"), - BSON(AuthorizationManager::USER_NAME_FIELD_NAME << user.getUser() << - AuthorizationManager::USER_DB_FIELD_NAME << user.getDB()), - updateObj, - false, - writeConcern); - if (status.isOK()) { - return status; - } - if (status.code() == ErrorCodes::NoMatchingDocument) { - return Status(ErrorCodes::UserNotFound, - mongoutils::str::stream() << "User " << user.getFullName() << - " not found"); - } - if (status.code() == ErrorCodes::UnknownError) { - return Status(ErrorCodes::UserModificationFailed, status.reason()); - } - return status; - } - - Status AuthzManagerExternalState::removePrivilegeDocuments(OperationContext* txn, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved) { - Status status = remove(txn, - NamespaceString("admin.system.users"), - query, - writeConcern, - numRemoved); - if (status.code() == ErrorCodes::UnknownError) { - return Status(ErrorCodes::UserModificationFailed, status.reason()); - } - return status; - } - - Status AuthzManagerExternalState::updateOne( - OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& updatePattern, - bool upsert, - const BSONObj& writeConcern) { - int nMatched; - Status status = update(txn, - collectionName, - query, - updatePattern, - upsert, - false, - writeConcern, - &nMatched); - if (!status.isOK()) { - return status; - } - dassert(nMatched == 1 || nMatched == 0); - if (nMatched == 0) { - return Status(ErrorCodes::NoMatchingDocument, "No document found"); - } - return Status::OK(); - } - } // namespace mongo diff --git a/src/mongo/db/auth/authz_manager_external_state.h b/src/mongo/db/auth/authz_manager_external_state.h index 05b1ba18aeb..4c08e181a0a 100644 --- a/src/mongo/db/auth/authz_manager_external_state.h +++ b/src/mongo/db/auth/authz_manager_external_state.h @@ -132,33 +132,6 @@ namespace mongo { bool hasAnyPrivilegeDocuments(OperationContext* txn); /** - * Creates the given user object in the given database. - * - * TODO(spencer): remove dbname argument once users are only written into the admin db - */ - Status insertPrivilegeDocument(OperationContext* txn, - const std::string& dbname, - const BSONObj& userObj, - const BSONObj& writeConcern); - - /** - * Updates the given user object with the given update modifier. - */ - Status updatePrivilegeDocument(OperationContext* txn, - const UserName& user, - const BSONObj& updateObj, - const BSONObj& writeConcern); - - /** - * Removes users for the given database matching the given query. - * Writes into *numRemoved the number of user documents that were modified. - */ - Status removePrivilegeDocuments(OperationContext* txn, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved); - - /** * Finds a document matching "query" in "collectionName", and store a shared-ownership * copy into "result". * @@ -180,52 +153,6 @@ namespace mongo { const BSONObj& projection, const stdx::function<void(const BSONObj&)>& resultProcessor) = 0; - /** - * Inserts "document" into "collectionName". - * If there is a duplicate key error, returns a Status with code DuplicateKey. - */ - virtual Status insert(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& document, - const BSONObj& writeConcern) = 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. - * If "upsert" is false and no document matches "query", return a Status with the code - * NoMatchingDocument. The Status message in that case is not very descriptive and should - * not be displayed to the end user. - */ - virtual Status updateOne(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& updatePattern, - bool upsert, - const BSONObj& writeConcern); - - /** - * Updates documents matching "query" according to "updatePattern" in "collectionName". - */ - virtual Status update(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& updatePattern, - bool upsert, - bool multi, - const BSONObj& writeConcern, - int* nMatched) = 0; - - /** - * Removes all documents matching "query" from "collectionName". - */ - virtual Status remove(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved) = 0; - virtual void logOp( OperationContext* txn, const char* op, 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 79e81727242..d62771144ca 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_d.cpp @@ -101,90 +101,4 @@ namespace mongo { "No document in " << collectionName.ns() << " matches " << query); } - Status AuthzManagerExternalStateMongod::insert( - OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& document, - const BSONObj& writeConcern) { - try { - DBDirectClient client(txn); - client.insert(collectionName, document); - - // Handle write concern - BSONObjBuilder gleBuilder; - gleBuilder.append("getLastError", 1); - gleBuilder.appendElements(writeConcern); - BSONObj res; - client.runCommand("admin", gleBuilder.done(), res); - string errstr = client.getLastErrorString(res); - if (errstr.empty()) { - return Status::OK(); - } - if (res.hasField("code") && res["code"].Int() == ASSERT_ID_DUPKEY) { - return Status(ErrorCodes::DuplicateKey, errstr); - } - return Status(ErrorCodes::UnknownError, errstr); - } catch (const DBException& e) { - return e.toStatus(); - } - } - - Status AuthzManagerExternalStateMongod::update(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& updatePattern, - bool upsert, - bool multi, - const BSONObj& writeConcern, - int* nMatched) { - try { - DBDirectClient client(txn); - client.update(collectionName, query, updatePattern, upsert, multi); - - // Handle write concern - BSONObjBuilder gleBuilder; - gleBuilder.append("getLastError", 1); - gleBuilder.appendElements(writeConcern); - BSONObj res; - client.runCommand("admin", gleBuilder.done(), res); - string err = client.getLastErrorString(res); - if (!err.empty()) { - return Status(ErrorCodes::UnknownError, err); - } - - *nMatched = res["n"].numberInt(); - return Status::OK(); - } catch (const DBException& e) { - return e.toStatus(); - } - } - - Status AuthzManagerExternalStateMongod::remove( - OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved) { - try { - DBDirectClient client(txn); - client.remove(collectionName, query); - - // Handle write concern - BSONObjBuilder gleBuilder; - gleBuilder.append("getLastError", 1); - gleBuilder.appendElements(writeConcern); - BSONObj res; - client.runCommand("admin", gleBuilder.done(), res); - string errstr = client.getLastErrorString(res); - if (!errstr.empty()) { - return Status(ErrorCodes::UnknownError, errstr); - } - - *numRemoved = res["n"].numberInt(); - return Status::OK(); - } catch (const DBException& e) { - return e.toStatus(); - } - } - } // 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 3c8fa8aa1c6..b288bc6321c 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.h +++ b/src/mongo/db/auth/authz_manager_external_state_d.h @@ -62,23 +62,6 @@ namespace mongo { const BSONObj& query, const BSONObj& projection, const stdx::function<void(const BSONObj&)>& resultProcessor); - virtual Status insert(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& document, - const BSONObj& writeConcern); - virtual Status update(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& updatePattern, - bool upsert, - bool multi, - const BSONObj& writeConcern, - int* nMatched); - virtual Status remove(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved); }; } // 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 047ca78d52c..92274c74627 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp @@ -174,6 +174,13 @@ namespace { return Status::OK(); } + Status AuthzManagerExternalStateMock::insertPrivilegeDocument( + OperationContext* txn, + const BSONObj& userObj, + const BSONObj& writeConcern) { + return insert(txn, AuthorizationManager::usersCollectionNamespace, userObj, writeConcern); + } + Status AuthzManagerExternalStateMock::updateOne( OperationContext* txn, const NamespaceString& collectionName, 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 585d954e7ba..43f3abb2546 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.h +++ b/src/mongo/db/auth/authz_manager_external_state_mock.h @@ -72,6 +72,13 @@ namespace mongo { const BSONObj& projection, // Currently unused in mock const stdx::function<void(const BSONObj&)>& resultProcessor); + /** + * Inserts the given user object into the "admin" database. + */ + Status insertPrivilegeDocument(OperationContext* txn, + const BSONObj& userObj, + const BSONObj& writeConcern); + // This implementation does not understand uniqueness constraints. virtual Status insert(OperationContext* txn, const NamespaceString& collectionName, 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 19e32f62003..d05fac906f2 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp @@ -44,7 +44,6 @@ #include "mongo/db/auth/authz_session_external_state_s.h" #include "mongo/db/auth/user_name.h" #include "mongo/db/jsobj.h" -#include "mongo/s/catalog/catalog_manager.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/config.h" #include "mongo/s/grid.h" @@ -283,53 +282,4 @@ namespace { } } - Status AuthzManagerExternalStateMongos::insert( - OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& document, - const BSONObj& writeConcern) { - - return grid.catalogManager()->insert(collectionName, document, NULL); - } - - Status AuthzManagerExternalStateMongos::update(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& updatePattern, - bool upsert, - bool multi, - const BSONObj& writeConcern, - int* nMatched) { - - BatchedCommandResponse response; - Status res = grid.catalogManager()->update(collectionName, - query, - updatePattern, - upsert, - multi, - &response); - if (res.isOK()) { - *nMatched = response.getN(); - } - - return res; - } - - Status AuthzManagerExternalStateMongos::remove( - OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved) { - - BatchedCommandResponse response; - - Status res = grid.catalogManager()->remove(collectionName, query, 0, &response); - if (res.isOK()) { - *numRemoved = response.getN(); - } - - return res; - } - } // 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 31295aa3ec3..606f423f61c 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.h +++ b/src/mongo/db/auth/authz_manager_external_state_s.h @@ -87,24 +87,6 @@ namespace mongo { const BSONObj& query, const BSONObj& projection, const stdx::function<void(const BSONObj&)>& resultProcessor); - - virtual Status insert(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& document, - const BSONObj& writeConcern); - virtual Status update(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& updatePattern, - bool upsert, - bool multi, - const BSONObj& writeConcern, - int* nMatched); - virtual Status remove(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - const BSONObj& writeConcern, - int* numRemoved); }; } // namespace mongo diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp index 7e2e1c100b3..58d17a75fa5 100644 --- a/src/mongo/db/commands/user_management_commands.cpp +++ b/src/mongo/db/commands/user_management_commands.cpp @@ -58,6 +58,7 @@ #include "mongo/db/auth/user_management_commands_parser.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" +#include "mongo/db/dbdirectclient.h" #include "mongo/db/jsobj.h" #include "mongo/db/operation_context.h" #include "mongo/db/service_context.h" @@ -85,8 +86,527 @@ namespace { const Seconds authzDataMutexAcquisitionTimeout{5}; + BSONArray roleSetToBSONArray(const unordered_set<RoleName>& roles) { + BSONArrayBuilder rolesArrayBuilder; + for (unordered_set<RoleName>::const_iterator it = roles.begin(); it != roles.end(); ++it) { + const RoleName& role = *it; + rolesArrayBuilder.append( + BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() << + AuthorizationManager::ROLE_DB_FIELD_NAME << role.getDB())); + } + return rolesArrayBuilder.arr(); + } + + BSONArray rolesVectorToBSONArray(const std::vector<RoleName>& roles) { + BSONArrayBuilder rolesArrayBuilder; + for (std::vector<RoleName>::const_iterator it = roles.begin(); it != roles.end(); ++it) { + const RoleName& role = *it; + rolesArrayBuilder.append( + BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() << + AuthorizationManager::ROLE_DB_FIELD_NAME << role.getDB())); + } + return rolesArrayBuilder.arr(); + } + + Status privilegeVectorToBSONArray(const PrivilegeVector& privileges, BSONArray* result) { + BSONArrayBuilder arrBuilder; + for (PrivilegeVector::const_iterator it = privileges.begin(); + it != privileges.end(); ++it) { + const Privilege& privilege = *it; + + ParsedPrivilege parsedPrivilege; + std::string errmsg; + if (!ParsedPrivilege::privilegeToParsedPrivilege(privilege, + &parsedPrivilege, + &errmsg)) { + return Status(ErrorCodes::FailedToParse, errmsg); + } + if (!parsedPrivilege.isValid(&errmsg)) { + return Status(ErrorCodes::FailedToParse, errmsg); + } + arrBuilder.append(parsedPrivilege.toBSON()); + } + *result = arrBuilder.arr(); + return Status::OK(); + } + + /** + * Used to get all current roles of the user identified by 'userName'. + */ + Status getCurrentUserRoles(OperationContext* txn, + AuthorizationManager* authzManager, + const UserName& userName, + unordered_set<RoleName>* roles) { + User* user; + authzManager->invalidateUserByName(userName); // Need to make sure cache entry is up to date + Status status = authzManager->acquireUser(txn, userName, &user); + if (!status.isOK()) { + return status; + } + RoleNameIterator rolesIt = user->getRoles(); + while (rolesIt.more()) { + roles->insert(rolesIt.next()); + } + authzManager->releaseUser(user); + return Status::OK(); + } + + /** + * Checks that every role in "rolesToAdd" exists, that adding each of those roles to "role" + * will not result in a cycle to the role graph, and that every role being added comes from the + * same database as the role it is being added to (or that the role being added to is from the + * "admin" database. + */ + Status checkOkayToGrantRolesToRole(const RoleName& role, + const std::vector<RoleName> rolesToAdd, + AuthorizationManager* authzManager) { + for (std::vector<RoleName>::const_iterator it = rolesToAdd.begin(); + it != rolesToAdd.end(); ++it) { + const RoleName& roleToAdd = *it; + if (roleToAdd == role) { + return Status(ErrorCodes::InvalidRoleModification, + mongoutils::str::stream() << "Cannot grant role " << + role.getFullName() << " to itself."); + } + + if (role.getDB() != "admin" && roleToAdd.getDB() != role.getDB()) { + return Status(ErrorCodes::InvalidRoleModification, + str::stream() << "Roles on the \'" << role.getDB() << + "\' database cannot be granted roles from other databases"); + } + + BSONObj roleToAddDoc; + Status status = authzManager->getRoleDescription(roleToAdd, false, &roleToAddDoc); + if (status == ErrorCodes::RoleNotFound) { + return Status(ErrorCodes::RoleNotFound, + "Cannot grant nonexistent role " + roleToAdd.toString()); + } + if (!status.isOK()) { + return status; + } + std::vector<RoleName> indirectRoles; + status = auth::parseRoleNamesFromBSONArray( + BSONArray(roleToAddDoc["inheritedRoles"].Obj()), + role.getDB(), + &indirectRoles); + if (!status.isOK()) { + return status; + } + + if (sequenceContains(indirectRoles, role)) { + return Status(ErrorCodes::InvalidRoleModification, + mongoutils::str::stream() << "Granting " << + roleToAdd.getFullName() << " to " << role.getFullName() + << " would introduce a cycle in the role graph."); + } + } + return Status::OK(); + } + + /** + * Checks that every privilege being granted targets just the database the role is from, or that + * the role is from the "admin" db. + */ + Status checkOkayToGrantPrivilegesToRole(const RoleName& role, + const PrivilegeVector& privileges) { + if (role.getDB() == "admin") { + return Status::OK(); + } + + for (PrivilegeVector::const_iterator it = privileges.begin(); + it != privileges.end(); ++it) { + const ResourcePattern& resource = (*it).getResourcePattern(); + if ((resource.isDatabasePattern() || resource.isExactNamespacePattern()) && + (resource.databaseToMatch() == role.getDB())) { + continue; + } + + return Status(ErrorCodes::InvalidRoleModification, + str::stream() << "Roles on the \'" << role.getDB() << + "\' database cannot be granted privileges that target other " + "databases or the cluster"); + } + + return Status::OK(); + } + + void appendBSONObjToBSONArrayBuilder(BSONArrayBuilder* array, const BSONObj& obj) { + array->append(obj); + } + + /** + * Inserts "document" into "collectionName". + * If there is a duplicate key error, returns a Status with code DuplicateKey. + * + * Should only be called on collections with authorization documents in them + * (ie admin.system.users and admin.system.roles). + */ + Status insertAuthzDocument(OperationContext* txn, + const NamespaceString& collectionName, + const BSONObj& document, + const BSONObj& writeConcern) { + try { + DBDirectClient client(txn); + client.insert(collectionName, document); + + // Handle write concern + BSONObjBuilder gleBuilder; + gleBuilder.append("getLastError", 1); + gleBuilder.appendElements(writeConcern); + BSONObj res; + client.runCommand("admin", gleBuilder.done(), res); + string errstr = client.getLastErrorString(res); + if (errstr.empty()) { + return Status::OK(); + } + if (res.hasField("code") && res["code"].Int() == ASSERT_ID_DUPKEY) { + return Status(ErrorCodes::DuplicateKey, errstr); + } + return Status(ErrorCodes::UnknownError, errstr); + } catch (const DBException& e) { + return e.toStatus(); + } + } + + /** + * Updates documents matching "query" according to "updatePattern" in "collectionName". + * + * Should only be called on collections with authorization documents in them + * (ie admin.system.users and admin.system.roles). + */ + Status updateAuthzDocuments(OperationContext* txn, + const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert, + bool multi, + const BSONObj& writeConcern, + int* nMatched) { + try { + DBDirectClient client(txn); + client.update(collectionName, query, updatePattern, upsert, multi); + + // Handle write concern + BSONObjBuilder gleBuilder; + gleBuilder.append("getLastError", 1); + gleBuilder.appendElements(writeConcern); + BSONObj res; + client.runCommand("admin", gleBuilder.done(), res); + string errstr = client.getLastErrorString(res); + if (errstr.empty()) { + *nMatched = res["n"].numberInt(); + return Status::OK(); + } + return Status(ErrorCodes::UnknownError, errstr); + } catch (const DBException& e) { + return e.toStatus(); + } + } + + /** + * 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. + * If "upsert" is false and no document matches "query", return a Status with the code + * NoMatchingDocument. The Status message in that case is not very descriptive and should + * not be displayed to the end user. + * + * Should only be called on collections with authorization documents in them + * (ie admin.system.users and admin.system.roles). + */ + Status updateOneAuthzDocument( + OperationContext* txn, + const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert, + const BSONObj& writeConcern) { + int nMatched; + Status status = updateAuthzDocuments(txn, + collectionName, + query, + updatePattern, + upsert, + false, + writeConcern, + &nMatched); + if (!status.isOK()) { + return status; + } + dassert(nMatched == 1 || nMatched == 0); + if (nMatched == 0) { + return Status(ErrorCodes::NoMatchingDocument, "No document found"); + } + return Status::OK(); + } + + /** + * Removes all documents matching "query" from "collectionName". + * + * Should only be called on collections with authorization documents in them + * (ie admin.system.users and admin.system.roles). + */ + Status removeAuthzDocuments( + OperationContext* txn, + const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& writeConcern, + int* numRemoved) { + try { + DBDirectClient client(txn); + client.remove(collectionName, query); + + // Handle write concern + BSONObjBuilder gleBuilder; + gleBuilder.append("getLastError", 1); + gleBuilder.appendElements(writeConcern); + BSONObj res; + client.runCommand("admin", gleBuilder.done(), res); + string errstr = client.getLastErrorString(res); + if (errstr.empty()) { + *numRemoved = res["n"].numberInt(); + return Status::OK(); + } + return Status(ErrorCodes::UnknownError, errstr); + } catch (const DBException& e) { + return e.toStatus(); + } + } + + /** + * Creates the given role object in the given database. + * 'writeConcern' contains the arguments to be passed to getLastError to block for + * successful completion of the write. + */ + Status insertRoleDocument(OperationContext* txn, + const BSONObj& roleObj, + const BSONObj& writeConcern) { + Status status = insertAuthzDocument(txn, + AuthorizationManager::rolesCollectionNamespace, + roleObj, + writeConcern); + if (status.isOK()) { + return status; + } + if (status.code() == ErrorCodes::DuplicateKey) { + std::string name = roleObj[AuthorizationManager::ROLE_NAME_FIELD_NAME].String(); + std::string source = roleObj[AuthorizationManager::ROLE_DB_FIELD_NAME].String(); + return Status(ErrorCodes::DuplicateKey, + str::stream() << "Role \"" << name << "@" << source + << "\" already exists"); + } + if (status.code() == ErrorCodes::UnknownError) { + return Status(ErrorCodes::RoleModificationFailed, status.reason()); + } + return status; + } + + /** + * Updates the given role object with the given update modifier. + * 'writeConcern' contains the arguments to be passed to getLastError to block for + * successful completion of the write. + */ + Status updateRoleDocument(OperationContext* txn, + const RoleName& role, + const BSONObj& updateObj, + const BSONObj& writeConcern) { + Status status = updateOneAuthzDocument( + txn, + AuthorizationManager::rolesCollectionNamespace, + BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() << + AuthorizationManager::ROLE_DB_FIELD_NAME << role.getDB()), + updateObj, + false, + writeConcern); + if (status.isOK()) { + return status; + } + if (status.code() == ErrorCodes::NoMatchingDocument) { + return Status(ErrorCodes::RoleNotFound, + str::stream() << "Role " << role.getFullName() + << " not found"); + } + if (status.code() == ErrorCodes::UnknownError) { + return Status(ErrorCodes::RoleModificationFailed, status.reason()); + } + return status; + } + + /** + * Removes roles matching the given query. + * Writes into *numRemoved the number of role documents that were modified. + * 'writeConcern' contains the arguments to be passed to getLastError to block for + * successful completion of the write. + */ + Status removeRoleDocuments(OperationContext* txn, + const BSONObj& query, + const BSONObj& writeConcern, + int* numRemoved) { + Status status = removeAuthzDocuments(txn, + AuthorizationManager::rolesCollectionNamespace, + query, + writeConcern, + numRemoved); + if (status.code() == ErrorCodes::UnknownError) { + return Status(ErrorCodes::RoleModificationFailed, status.reason()); + } + return status; + } + + /** + * Creates the given user object in the given database. + * 'writeConcern' contains the arguments to be passed to getLastError to block for + * successful completion of the write. + */ + Status insertPrivilegeDocument(OperationContext* txn, + const BSONObj& userObj, + const BSONObj& writeConcern) { + Status status = insertAuthzDocument(txn, + AuthorizationManager::usersCollectionNamespace, + userObj, + writeConcern); + if (status.isOK()) { + return status; + } + if (status.code() == ErrorCodes::DuplicateKey) { + std::string name = userObj[AuthorizationManager::USER_NAME_FIELD_NAME].String(); + std::string source = userObj[AuthorizationManager::USER_DB_FIELD_NAME].String(); + return Status(ErrorCodes::DuplicateKey, + str::stream() << "User \"" << name << "@" << source + << "\" already exists"); + } + if (status.code() == ErrorCodes::UnknownError) { + return Status(ErrorCodes::UserModificationFailed, status.reason()); + } + return status; + } + + /** + * Updates the given user object with the given update modifier. + * 'writeConcern' contains the arguments to be passed to getLastError to block for + * successful completion of the write. + */ + Status updatePrivilegeDocument(OperationContext* txn, + const UserName& user, + const BSONObj& updateObj, + const BSONObj& writeConcern) { + Status status = updateOneAuthzDocument( + txn, + AuthorizationManager::usersCollectionNamespace, + BSON(AuthorizationManager::USER_NAME_FIELD_NAME << user.getUser() << + AuthorizationManager::USER_DB_FIELD_NAME << user.getDB()), + updateObj, + false, + writeConcern); + if (status.isOK()) { + return status; + } + if (status.code() == ErrorCodes::NoMatchingDocument) { + return Status(ErrorCodes::UserNotFound, + str::stream() << "User " << user.getFullName() + << " not found"); + } + if (status.code() == ErrorCodes::UnknownError) { + return Status(ErrorCodes::UserModificationFailed, status.reason()); + } + return status; + } + + /** + * Removes users for the given database matching the given query. + * Writes into *numRemoved the number of user documents that were modified. + * 'writeConcern' contains the arguments to be passed to getLastError to block for + * successful completion of the write. + */ + Status removePrivilegeDocuments(OperationContext* txn, + const BSONObj& query, + const BSONObj& writeConcern, + int* numRemoved) { + Status status = removeAuthzDocuments(txn, + AuthorizationManager::usersCollectionNamespace, + query, + writeConcern, + numRemoved); + if (status.code() == ErrorCodes::UnknownError) { + return Status(ErrorCodes::UserModificationFailed, status.reason()); + } + return status; + } + + /** + * Updates the auth schema version document to reflect the current state of the system. + * 'foundSchemaVersion' is the authSchemaVersion to update with. + */ + Status writeAuthSchemaVersionIfNeeded(OperationContext* txn, + AuthorizationManager* authzManager, + int foundSchemaVersion) { + Status status = updateOneAuthzDocument(txn, + AuthorizationManager::versionCollectionNamespace, + AuthorizationManager::versionDocumentQuery, + BSON("$set" << BSON(AuthorizationManager::schemaVersionFieldName + << foundSchemaVersion)), + true, // upsert + BSONObj()); // write concern + if (status == ErrorCodes::NoMatchingDocument) { // SERVER-11492 + status = Status::OK(); + } + + return status; + } + + /** + * Returns Status::OK() if the current Auth schema version is at least the auth schema version + * for the MongoDB 2.6 and 3.0 MongoDB-CR/SCRAM mixed auth mode. + * Returns an error otherwise. + */ + Status requireAuthSchemaVersion26Final(OperationContext* txn, + AuthorizationManager* authzManager) { + int foundSchemaVersion; + Status status = authzManager->getAuthorizationVersion(txn, &foundSchemaVersion); + if (!status.isOK()) { + return status; + } + + if (foundSchemaVersion < AuthorizationManager::schemaVersion26Final) { + return Status( + ErrorCodes::AuthSchemaIncompatible, + str::stream() << "User and role management commands require auth data to have " + << "at least schema version " + << AuthorizationManager::schemaVersion26Final + << " but found " << foundSchemaVersion); + } + return writeAuthSchemaVersionIfNeeded(txn, authzManager, foundSchemaVersion); + } + + /** + * Returns Status::OK() if the current Auth schema version is at least the auth schema version + * for MongoDB 2.6 during the upgrade process. + * Returns an error otherwise. + */ + Status requireAuthSchemaVersion26UpgradeOrFinal(OperationContext* txn, + AuthorizationManager* authzManager) { + int foundSchemaVersion; + Status status = authzManager->getAuthorizationVersion(txn, &foundSchemaVersion); + if (!status.isOK()) { + return status; + } + + if (foundSchemaVersion < AuthorizationManager::schemaVersion26Upgrade) { + return Status( + ErrorCodes::AuthSchemaIncompatible, + str::stream() << "The usersInfo and rolesInfo commands require auth data to " + << "have at least schema version " + << AuthorizationManager::schemaVersion26Upgrade + << " but found " << foundSchemaVersion); + } + return Status::OK(); + } + } // namespace + + class CmdCreateUser : public Command { public: @@ -205,7 +725,7 @@ namespace { if (args.hasCustomData) { userObjBuilder.append("customData", args.customData); } - userObjBuilder.append("roles", auth::rolesVectorToBSONArray(args.roles)); + userObjBuilder.append("roles", rolesVectorToBSONArray(args.roles)); BSONObj userObj = userObjBuilder.obj(); V2UserDocumentParser parser; @@ -222,7 +742,7 @@ namespace { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -241,10 +761,9 @@ namespace { args.hasHashedPassword, args.hasCustomData? &args.customData : NULL, args.roles); - status = authzManager->insertPrivilegeDocument(txn, - dbname, - userObj, - args.writeConcern); + status = insertPrivilegeDocument(txn, + userObj, + args.writeConcern); return appendCommandStatus(result, status); } @@ -331,7 +850,7 @@ namespace { updateSetBuilder.append("customData", args.customData); } if (args.hasRoles) { - updateSetBuilder.append("roles", auth::rolesVectorToBSONArray(args.roles)); + updateSetBuilder.append("roles", rolesVectorToBSONArray(args.roles)); } ServiceContext* serviceContext = txn->getClient()->getServiceContext(); @@ -344,7 +863,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -367,10 +886,10 @@ namespace { args.hasCustomData? &args.customData : NULL, args.hasRoles? &args.roles : NULL); - status = authzManager->updatePrivilegeDocument(txn, - args.userName, - BSON("$set" << updateSetBuilder.done()), - args.writeConcern); + status = updatePrivilegeDocument(txn, + args.userName, + BSON("$set" << updateSetBuilder.done()), + args.writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserByName(args.userName); return appendCommandStatus(result, status); @@ -418,7 +937,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -438,7 +957,7 @@ namespace { audit::logDropUser(ClientBasic::getCurrent(), userName); - status = authzManager->removePrivilegeDocuments( + status = removePrivilegeDocuments( txn, BSON(AuthorizationManager::USER_NAME_FIELD_NAME << userName.getUser() << AuthorizationManager::USER_DB_FIELD_NAME << userName.getDB()), @@ -499,7 +1018,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -516,7 +1035,7 @@ namespace { audit::logDropAllUsersFromDatabase(ClientBasic::getCurrent(), dbname); - status = authzManager->removePrivilegeDocuments( + status = removePrivilegeDocuments( txn, BSON(AuthorizationManager::USER_DB_FIELD_NAME << dbname), writeConcern, @@ -569,7 +1088,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -589,7 +1108,7 @@ namespace { UserName userName(userNameString, dbname); unordered_set<RoleName> userRoles; - status = auth::getCurrentUserRoles(txn, authzManager, userName, &userRoles); + status = getCurrentUserRoles(txn, authzManager, userName, &userRoles); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -608,8 +1127,8 @@ namespace { audit::logGrantRolesToUser(ClientBasic::getCurrent(), userName, roles); - BSONArray newRolesBSONArray = auth::roleSetToBSONArray(userRoles); - status = authzManager->updatePrivilegeDocument( + BSONArray newRolesBSONArray = roleSetToBSONArray(userRoles); + status = updatePrivilegeDocument( txn, userName, BSON("$set" << BSON("roles" << newRolesBSONArray)), writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserByName(userName); @@ -654,7 +1173,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -674,7 +1193,7 @@ namespace { UserName userName(userNameString, dbname); unordered_set<RoleName> userRoles; - status = auth::getCurrentUserRoles(txn, authzManager, userName, &userRoles); + status = getCurrentUserRoles(txn, authzManager, userName, &userRoles); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -693,8 +1212,8 @@ namespace { audit::logRevokeRolesFromUser(ClientBasic::getCurrent(), userName, roles); - BSONArray newRolesBSONArray = auth::roleSetToBSONArray(userRoles); - status = authzManager->updatePrivilegeDocument( + BSONArray newRolesBSONArray = roleSetToBSONArray(userRoles); + status = updatePrivilegeDocument( txn, userName, BSON("$set" << BSON("roles" << newRolesBSONArray)), writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserByName(userName); @@ -740,9 +1259,8 @@ namespace { return appendCommandStatus(result, status); } - status = - auth::requireAuthSchemaVersion26UpgradeOrFinal(txn, - getGlobalAuthorizationManager()); + status = requireAuthSchemaVersion26UpgradeOrFinal(txn, + getGlobalAuthorizationManager()); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -804,7 +1322,7 @@ namespace { projection.append("credentials", 0); } const stdx::function<void(const BSONObj&)> function = stdx::bind( - auth::appendBSONObjToBSONArrayBuilder, + appendBSONObjToBSONArrayBuilder, &usersArrayBuilder, stdx::placeholders::_1); authzManager->queryAuthzDocument(txn, @@ -897,13 +1415,13 @@ namespace { args.roleName.getDB()); BSONArray privileges; - status = auth::privilegeVectorToBSONArray(args.privileges, &privileges); + status = privilegeVectorToBSONArray(args.privileges, &privileges); if (!status.isOK()) { return appendCommandStatus(result, status); } roleObjBuilder.append("privileges", privileges); - roleObjBuilder.append("roles", auth::rolesVectorToBSONArray(args.roles)); + roleObjBuilder.append("roles", rolesVectorToBSONArray(args.roles)); ServiceContext* serviceContext = txn->getClient()->getServiceContext(); boost::unique_lock<boost::timed_mutex> lk(getAuthzDataMutex(serviceContext), @@ -915,18 +1433,18 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } // Role existence has to be checked after acquiring the update lock - status = auth::checkOkayToGrantRolesToRole(args.roleName, args.roles, authzManager); + status = checkOkayToGrantRolesToRole(args.roleName, args.roles, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } - status = auth::checkOkayToGrantPrivilegesToRole(args.roleName, args.privileges); + status = checkOkayToGrantPrivilegesToRole(args.roleName, args.privileges); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -936,7 +1454,7 @@ namespace { args.roles, args.privileges); - status = authzManager->insertRoleDocument(txn, roleObjBuilder.done(), args.writeConcern); + status = insertRoleDocument(txn, roleObjBuilder.done(), args.writeConcern); return appendCommandStatus(result, status); } @@ -988,7 +1506,7 @@ namespace { if (args.hasPrivileges) { BSONArray privileges; - status = auth::privilegeVectorToBSONArray(args.privileges, &privileges); + status = privilegeVectorToBSONArray(args.privileges, &privileges); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -996,7 +1514,7 @@ namespace { } if (args.hasRoles) { - updateSetBuilder.append("roles", auth::rolesVectorToBSONArray(args.roles)); + updateSetBuilder.append("roles", rolesVectorToBSONArray(args.roles)); } ServiceContext* serviceContext = txn->getClient()->getServiceContext(); @@ -1009,7 +1527,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1022,14 +1540,14 @@ namespace { } if (args.hasRoles) { - status = auth::checkOkayToGrantRolesToRole(args.roleName, args.roles, authzManager); + status = checkOkayToGrantRolesToRole(args.roleName, args.roles, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } } if (args.hasPrivileges) { - status = auth::checkOkayToGrantPrivilegesToRole(args.roleName, args.privileges); + status = checkOkayToGrantPrivilegesToRole(args.roleName, args.privileges); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1040,10 +1558,10 @@ namespace { args.hasRoles? &args.roles : NULL, args.hasPrivileges? &args.privileges : NULL); - status = authzManager->updateRoleDocument(txn, - args.roleName, - BSON("$set" << updateSetBuilder.done()), - args.writeConcern); + status = updateRoleDocument(txn, + args.roleName, + BSON("$set" << updateSetBuilder.done()), + args.writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserCache(); return appendCommandStatus(result, status); @@ -1086,7 +1604,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1113,7 +1631,7 @@ namespace { " is a built-in role and cannot be modified.")); } - status = auth::checkOkayToGrantPrivilegesToRole(roleName, privilegesToAdd); + status = checkOkayToGrantPrivilegesToRole(roleName, privilegesToAdd); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1161,7 +1679,7 @@ namespace { roleName, privilegesToAdd); - status = authzManager->updateRoleDocument( + status = updateRoleDocument( txn, roleName, updateBSONBuilder.done(), @@ -1209,7 +1727,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1286,7 +1804,7 @@ namespace { BSONObjBuilder updateBSONBuilder; updateObj.writeTo(&updateBSONBuilder); - status = authzManager->updateRoleDocument( + status = updateRoleDocument( txn, roleName, updateBSONBuilder.done(), @@ -1357,7 +1875,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1370,7 +1888,7 @@ namespace { } // Check for cycles - status = auth::checkOkayToGrantRolesToRole(roleName, rolesToAdd, authzManager); + status = checkOkayToGrantRolesToRole(roleName, rolesToAdd, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1393,10 +1911,10 @@ namespace { roleName, rolesToAdd); - status = authzManager->updateRoleDocument( + status = updateRoleDocument( txn, roleName, - BSON("$set" << BSON("roles" << auth::rolesVectorToBSONArray(directRoles))), + BSON("$set" << BSON("roles" << rolesVectorToBSONArray(directRoles))), writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserCache(); @@ -1441,7 +1959,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1494,10 +2012,10 @@ namespace { roleName, rolesToRemove); - status = authzManager->updateRoleDocument( + status = updateRoleDocument( txn, roleName, - BSON("$set" << BSON("roles" << auth::rolesVectorToBSONArray(roles))), + BSON("$set" << BSON("roles" << rolesVectorToBSONArray(roles))), writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? authzManager->invalidateUserCache(); @@ -1545,7 +2063,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - Status status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1576,9 +2094,9 @@ namespace { // Remove this role from all users int nMatched; - status = authzManager->updateAuthzDocuments( + status = updateAuthzDocuments( txn, - NamespaceString("admin.system.users"), + AuthorizationManager::usersCollectionNamespace, BSON("roles" << BSON("$elemMatch" << BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << roleName.getRole() << @@ -1606,9 +2124,9 @@ namespace { } // Remove this role from all other roles - status = authzManager->updateAuthzDocuments( + status = updateAuthzDocuments( txn, - NamespaceString("admin.system.roles"), + AuthorizationManager::rolesCollectionNamespace, BSON("roles" << BSON("$elemMatch" << BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << roleName.getRole() << @@ -1639,7 +2157,7 @@ namespace { audit::logDropRole(ClientBasic::getCurrent(), roleName); // Finally, remove the actual role document - status = authzManager->removeRoleDocuments( + status = removeRoleDocuments( txn, BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << roleName.getRole() << AuthorizationManager::ROLE_DB_FIELD_NAME << roleName.getDB()), @@ -1718,14 +2236,14 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } // Remove these roles from all users int nMatched; - status = authzManager->updateAuthzDocuments( + status = updateAuthzDocuments( txn, AuthorizationManager::usersCollectionNamespace, BSON("roles" << BSON(AuthorizationManager::ROLE_DB_FIELD_NAME << dbname)), @@ -1751,7 +2269,7 @@ namespace { // Remove these roles from all other roles std::string sourceFieldName = str::stream() << "roles." << AuthorizationManager::ROLE_DB_FIELD_NAME; - status = authzManager->updateAuthzDocuments( + status = updateAuthzDocuments( txn, AuthorizationManager::rolesCollectionNamespace, BSON(sourceFieldName << dbname), @@ -1776,7 +2294,7 @@ namespace { audit::logDropAllRolesFromDatabase(ClientBasic::getCurrent(), dbname); // Finally, remove the actual role documents - status = authzManager->removeRoleDocuments( + status = removeRoleDocuments( txn, BSON(AuthorizationManager::ROLE_DB_FIELD_NAME << dbname), writeConcern, @@ -1836,9 +2354,8 @@ namespace { return appendCommandStatus(result, status); } - status = - auth::requireAuthSchemaVersion26UpgradeOrFinal(txn, - getGlobalAuthorizationManager()); + status = requireAuthSchemaVersion26UpgradeOrFinal(txn, + getGlobalAuthorizationManager()); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -2110,10 +2627,10 @@ namespace { if (update && usersToDrop->count(userName)) { auditCreateOrUpdateUser(userObj, false); - Status status = authzManager->updatePrivilegeDocument(txn, - userName, - userObj, - writeConcern); + Status status = updatePrivilegeDocument(txn, + userName, + userObj, + writeConcern); if (!status.isOK()) { // Match the behavior of mongorestore to continue on failure warning() << "Could not update user " << userName << @@ -2121,10 +2638,9 @@ namespace { } } else { auditCreateOrUpdateUser(userObj, true); - Status status = authzManager->insertPrivilegeDocument(txn, - userName.getDB().toString(), - userObj, - writeConcern); + Status status = insertPrivilegeDocument(txn, + userObj, + writeConcern); if (!status.isOK()) { // Match the behavior of mongorestore to continue on failure warning() << "Could not insert user " << userName << @@ -2155,10 +2671,10 @@ namespace { if (update && rolesToDrop->count(roleName)) { auditCreateOrUpdateRole(roleObj, false); - Status status = authzManager->updateRoleDocument(txn, - roleName, - roleObj, - writeConcern); + Status status = updateRoleDocument(txn, + roleName, + roleObj, + writeConcern); if (!status.isOK()) { // Match the behavior of mongorestore to continue on failure warning() << "Could not update role " << roleName << @@ -2166,7 +2682,7 @@ namespace { } } else { auditCreateOrUpdateRole(roleObj, true); - Status status = authzManager->insertRoleDocument(txn, roleObj, writeConcern); + Status status = insertRoleDocument(txn, roleObj, writeConcern); if (!status.isOK()) { // Match the behavior of mongorestore to continue on failure warning() << "Could not insert role " << roleName << @@ -2240,7 +2756,7 @@ namespace { it != usersToDrop.end(); ++it) { const UserName& userName = *it; audit::logDropUser(ClientBasic::getCurrent(), userName); - status = authzManager->removePrivilegeDocuments( + status = removePrivilegeDocuments( txn, BSON(AuthorizationManager::USER_NAME_FIELD_NAME << userName.getUser().toString() << @@ -2323,7 +2839,7 @@ namespace { it != rolesToDrop.end(); ++it) { const RoleName& roleName = *it; audit::logDropRole(ClientBasic::getCurrent(), roleName); - status = authzManager->removeRoleDocuments( + status = removeRoleDocuments( txn, BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << roleName.getRole().toString() << @@ -2371,7 +2887,7 @@ namespace { } AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext); - status = auth::requireAuthSchemaVersion26Final(txn, authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } diff --git a/src/mongo/db/commands/user_management_commands.h b/src/mongo/db/commands/user_management_commands.h index 5f21c719117..6b67b8f7891 100644 --- a/src/mongo/db/commands/user_management_commands.h +++ b/src/mongo/db/commands/user_management_commands.h @@ -35,7 +35,6 @@ #include "mongo/db/auth/privilege.h" #include "mongo/db/auth/role_name.h" #include "mongo/db/auth/user_name.h" -#include "mongo/platform/unordered_set.h" namespace mongo { @@ -55,55 +54,6 @@ namespace auth { */ void redactPasswordData(mutablebson::Element parent); - BSONArray roleSetToBSONArray(const unordered_set<RoleName>& roles); - - BSONArray rolesVectorToBSONArray(const std::vector<RoleName>& roles); - - Status privilegeVectorToBSONArray(const PrivilegeVector& privileges, BSONArray* result); - - /** - * Used to get all current roles of the user identified by 'userName'. - */ - Status getCurrentUserRoles(OperationContext* txn, - AuthorizationManager* authzManager, - const UserName& userName, - unordered_set<RoleName>* roles); - - /** - * Checks that every role in "rolesToAdd" exists, that adding each of those roles to "role" - * will not result in a cycle to the role graph, and that every role being added comes from the - * same database as the role it is being added to (or that the role being added to is from the - * "admin" database. - */ - Status checkOkayToGrantRolesToRole(const RoleName& role, - const std::vector<RoleName> rolesToAdd, - AuthorizationManager* authzManager); - - /** - * Checks that every privilege being granted targets just the database the role is from, or that - * the role is from the "admin" db. - */ - Status checkOkayToGrantPrivilegesToRole(const RoleName& role, - const PrivilegeVector& privileges); - - /** - * Returns Status::OK() if the current Auth schema version is at least the auth schema version - * for the MongoDB 2.6 and 3.0 MongoDB-CR/SCRAM mixed auth mode. - * Returns an error otherwise. - */ - Status requireAuthSchemaVersion26Final(OperationContext* txn, - AuthorizationManager* authzManager); - - /** - * Returns Status::OK() if the current Auth schema version is at least the auth schema version - * for MongoDB 2.6 during the upgrade process. - * Returns an error otherwise. - */ - Status requireAuthSchemaVersion26UpgradeOrFinal(OperationContext* txn, - AuthorizationManager* authzManager); - - void appendBSONObjToBSONArrayBuilder(BSONArrayBuilder* array, const BSONObj& obj); - // // checkAuthorizedTo* methods // diff --git a/src/mongo/db/commands/user_management_commands_common.cpp b/src/mongo/db/commands/user_management_commands_common.cpp index cfe634f142a..9e2210a92d5 100644 --- a/src/mongo/db/commands/user_management_commands_common.cpp +++ b/src/mongo/db/commands/user_management_commands_common.cpp @@ -40,7 +40,6 @@ #include "mongo/config.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" -#include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/resource_pattern.h" #include "mongo/db/auth/user.h" @@ -64,178 +63,6 @@ namespace auth { } } - BSONArray roleSetToBSONArray(const unordered_set<RoleName>& roles) { - BSONArrayBuilder rolesArrayBuilder; - for (unordered_set<RoleName>::const_iterator it = roles.begin(); it != roles.end(); ++it) { - const RoleName& role = *it; - rolesArrayBuilder.append( - BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() << - AuthorizationManager::ROLE_DB_FIELD_NAME << role.getDB())); - } - return rolesArrayBuilder.arr(); - } - - BSONArray rolesVectorToBSONArray(const std::vector<RoleName>& roles) { - BSONArrayBuilder rolesArrayBuilder; - for (std::vector<RoleName>::const_iterator it = roles.begin(); it != roles.end(); ++it) { - const RoleName& role = *it; - rolesArrayBuilder.append( - BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() << - AuthorizationManager::ROLE_DB_FIELD_NAME << role.getDB())); - } - return rolesArrayBuilder.arr(); - } - - Status privilegeVectorToBSONArray(const PrivilegeVector& privileges, BSONArray* result) { - BSONArrayBuilder arrBuilder; - for (PrivilegeVector::const_iterator it = privileges.begin(); - it != privileges.end(); ++it) { - const Privilege& privilege = *it; - - ParsedPrivilege parsedPrivilege; - std::string errmsg; - if (!ParsedPrivilege::privilegeToParsedPrivilege(privilege, - &parsedPrivilege, - &errmsg)) { - return Status(ErrorCodes::FailedToParse, errmsg); - } - if (!parsedPrivilege.isValid(&errmsg)) { - return Status(ErrorCodes::FailedToParse, errmsg); - } - arrBuilder.append(parsedPrivilege.toBSON()); - } - *result = arrBuilder.arr(); - return Status::OK(); - } - - Status getCurrentUserRoles(OperationContext* txn, - AuthorizationManager* authzManager, - const UserName& userName, - unordered_set<RoleName>* roles) { - User* user; - authzManager->invalidateUserByName(userName); // Need to make sure cache entry is up to date - Status status = authzManager->acquireUser(txn, userName, &user); - if (!status.isOK()) { - return status; - } - RoleNameIterator rolesIt = user->getRoles(); - while (rolesIt.more()) { - roles->insert(rolesIt.next()); - } - authzManager->releaseUser(user); - return Status::OK(); - } - - Status checkOkayToGrantRolesToRole(const RoleName& role, - const std::vector<RoleName> rolesToAdd, - AuthorizationManager* authzManager) { - for (std::vector<RoleName>::const_iterator it = rolesToAdd.begin(); - it != rolesToAdd.end(); ++it) { - const RoleName& roleToAdd = *it; - if (roleToAdd == role) { - return Status(ErrorCodes::InvalidRoleModification, - mongoutils::str::stream() << "Cannot grant role " << - role.getFullName() << " to itself."); - } - - if (role.getDB() != "admin" && roleToAdd.getDB() != role.getDB()) { - return Status(ErrorCodes::InvalidRoleModification, - str::stream() << "Roles on the \'" << role.getDB() << - "\' database cannot be granted roles from other databases"); - } - - BSONObj roleToAddDoc; - Status status = authzManager->getRoleDescription(roleToAdd, false, &roleToAddDoc); - if (status == ErrorCodes::RoleNotFound) { - return Status(ErrorCodes::RoleNotFound, - "Cannot grant nonexistent role " + roleToAdd.toString()); - } - if (!status.isOK()) { - return status; - } - std::vector<RoleName> indirectRoles; - status = auth::parseRoleNamesFromBSONArray( - BSONArray(roleToAddDoc["inheritedRoles"].Obj()), - role.getDB(), - &indirectRoles); - if (!status.isOK()) { - return status; - } - - if (sequenceContains(indirectRoles, role)) { - return Status(ErrorCodes::InvalidRoleModification, - mongoutils::str::stream() << "Granting " << - roleToAdd.getFullName() << " to " << role.getFullName() - << " would introduce a cycle in the role graph."); - } - } - return Status::OK(); - } - - Status checkOkayToGrantPrivilegesToRole(const RoleName& role, - const PrivilegeVector& privileges) { - if (role.getDB() == "admin") { - return Status::OK(); - } - - for (PrivilegeVector::const_iterator it = privileges.begin(); - it != privileges.end(); ++it) { - const ResourcePattern& resource = (*it).getResourcePattern(); - if ((resource.isDatabasePattern() || resource.isExactNamespacePattern()) && - (resource.databaseToMatch() == role.getDB())) { - continue; - } - - return Status(ErrorCodes::InvalidRoleModification, - str::stream() << "Roles on the \'" << role.getDB() << - "\' database cannot be granted privileges that target other " - "databases or the cluster"); - } - - return Status::OK(); - } - - Status requireAuthSchemaVersion26Final(OperationContext* txn, - AuthorizationManager* authzManager) { - int foundSchemaVersion; - Status status = authzManager->getAuthorizationVersion(txn, &foundSchemaVersion); - if (!status.isOK()) { - return status; - } - - if (foundSchemaVersion < AuthorizationManager::schemaVersion26Final) { - return Status( - ErrorCodes::AuthSchemaIncompatible, - str::stream() << "User and role management commands require auth data to have " - "at least schema version " << AuthorizationManager::schemaVersion26Final << - " but found " << foundSchemaVersion); - } - return authzManager->writeAuthSchemaVersionIfNeeded(txn, foundSchemaVersion); - } - - Status requireAuthSchemaVersion26UpgradeOrFinal(OperationContext* txn, - AuthorizationManager* authzManager) { - int foundSchemaVersion; - Status status = authzManager->getAuthorizationVersion(txn, &foundSchemaVersion); - if (!status.isOK()) { - return status; - } - - if (foundSchemaVersion < AuthorizationManager::schemaVersion26Upgrade) { - return Status( - ErrorCodes::AuthSchemaIncompatible, - str::stream() << "The usersInfo and rolesInfo commands require auth data to " - "have at least schema version " << - AuthorizationManager::schemaVersion26Upgrade << - " but found " << foundSchemaVersion); - } - return Status::OK(); - } - - void appendBSONObjToBSONArrayBuilder(BSONArrayBuilder* array, const BSONObj& obj) { - array->append(obj); - } - Status checkAuthorizedToGrantRoles(AuthorizationSession* authzSession, const std::vector<RoleName>& roles) { for (size_t i = 0; i < roles.size(); ++i) { |