Status AuthzManagerExternalStateMongos::getRoleDescription(const RoleName& roleName,
                                                            BSONObj* result) {
     try {
         scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(
                 AuthorizationManager::rolesCollectionNamespace));
         BSONObj cmdResult;
         conn->get()->runCommand(
                 "admin",
                 BSON("rolesInfo" <<
                      BSON_ARRAY(BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME <<
                                      roleName.getRole() <<
                                      AuthorizationManager::ROLE_SOURCE_FIELD_NAME <<
                                      roleName.getDB()))),
                 cmdResult);
         if (!cmdResult["ok"].trueValue()) {
             int code = cmdResult["code"].numberInt();
             if (code == 0) code = ErrorCodes::UnknownError;
             return Status(ErrorCodes::Error(code), cmdResult["errmsg"].str());
         }
         *result = cmdResult["roles"]["0"].Obj().getOwned();
         conn->done();
         return Status::OK();
     } catch (const DBException& e) {
         return e.toStatus();
     }
 }
    Status AuthzManagerExternalStateMongos::createIndex(
            const NamespaceString& collectionName,
            const BSONObj& pattern,
            bool unique,
            const BSONObj& writeConcern) {
        try {
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(collectionName));

            if (conn->get()->ensureIndex(collectionName.ns(), pattern, unique)) {

                // Handle write concern
                BSONObjBuilder gleBuilder;
                gleBuilder.append("getLastError", 1);
                gleBuilder.appendElements(writeConcern);
                BSONObj res;
                conn->get()->runCommand("admin", gleBuilder.done(), res);
                string err = conn->get()->getLastErrorString(res);

                if (!err.empty()) {
                    conn->done();
                    return Status(ErrorCodes::UnknownError, err);
                }
            }
            conn->done();
            return Status::OK();

        } catch (const DBException& ex) {
            return ex.toStatus();
        }
    }
    Status AuthzManagerExternalStateMongos::insert(
            const NamespaceString& collectionName,
            const BSONObj& document,
            const BSONObj& writeConcern) {
        try {
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(collectionName));

            conn->get()->insert(collectionName, document);

            // Handle write concern
            BSONObjBuilder gleBuilder;
            gleBuilder.append("getLastError", 1);
            gleBuilder.appendElements(writeConcern);
            BSONObj res;
            conn->get()->runCommand("admin", gleBuilder.done(), res);
            string errstr = conn->get()->getLastErrorString(res);
            conn->done();

            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 AuthzManagerExternalStateMongos::remove(
            const NamespaceString& collectionName,
            const BSONObj& query,
            const BSONObj& writeConcern,
            int* numRemoved) {
        try {
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(collectionName));

            conn->get()->remove(collectionName, query);

            // Handle write concern
            BSONObjBuilder gleBuilder;
            gleBuilder.append("getLastError", 1);
            gleBuilder.appendElements(writeConcern);
            BSONObj res;
            conn->get()->runCommand("admin", gleBuilder.done(), res);
            string err = conn->get()->getLastErrorString(res);
            conn->done();

            if (!err.empty()) {
                return Status(ErrorCodes::UnknownError, err);
            }

            *numRemoved = res["n"].numberInt();
            return Status::OK();
        } catch (const DBException& e) {
            return e.toStatus();
        }
    }
    Status AuthzManagerExternalStateMongos::removePrivilegeDocuments(const BSONObj& query,
                                                                     const BSONObj& writeConcern,
                                                                     int* numRemoved) {
        try {
            string userNS = "admin.system.users";
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(userNS));

            conn->get()->remove(userNS, query);

            // Handle write concern
            BSONObjBuilder gleBuilder;
            gleBuilder.append("getLastError", 1);
            gleBuilder.appendElements(writeConcern);
            BSONObj res;
            conn->get()->runCommand("admin", gleBuilder.done(), res);
            string err = conn->get()->getLastErrorString(res);
            conn->done();

            if (!err.empty()) {
                return Status(ErrorCodes::UserModificationFailed, err);
            }

            *numRemoved = res["n"].numberInt();
            return Status::OK();
        } catch (const DBException& e) {
            return e.toStatus();
        }
    }
 Status AuthzManagerExternalStateMongos::getUserDescription(const UserName& userName,
                                                            BSONObj* result) {
     try {
         scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(
                 AuthorizationManager::usersCollectionNamespace));
         BSONObj cmdResult;
         conn->get()->runCommand(
                 "admin",
                 BSON("usersInfo" <<
                      BSON_ARRAY(BSON(AuthorizationManager::USER_NAME_FIELD_NAME <<
                                      userName.getUser() <<
                                      AuthorizationManager::USER_DB_FIELD_NAME <<
                                      userName.getDB())) <<
                      "showPrivileges" << true <<
                      "showCredentials" << true),
                 cmdResult);
         if (!cmdResult["ok"].trueValue()) {
             int code = cmdResult["code"].numberInt();
             if (code == 0) code = ErrorCodes::UnknownError;
             return Status(ErrorCodes::Error(code), cmdResult["errmsg"].str());
         }
         *result = cmdResult["users"]["0"].Obj().getOwned();
         conn->done();
         return Status::OK();
     } catch (const DBException& e) {
         return e.toStatus();
     }
 }
    Status AuthzManagerExternalStateMongos::insertPrivilegeDocument(const string& dbname,
                                                                    const BSONObj& userObj,
                                                                    const BSONObj& writeConcern) {
        try {
            const std::string userNS = "admin.system.users";
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(userNS));

            conn->get()->insert(userNS, userObj);

            // Handle write concern
            BSONObjBuilder gleBuilder;
            gleBuilder.append("getLastError", 1);
            gleBuilder.appendElements(writeConcern);
            BSONObj res;
            conn->get()->runCommand("admin", gleBuilder.done(), res);
            string errstr = conn->get()->getLastErrorString(res);
            conn->done();

            if (errstr.empty()) {
                return Status::OK();
            }
            if (res.hasField("code") && res["code"].Int() == ASSERT_ID_DUPKEY) {
                std::string name = userObj[AuthorizationManager::USER_NAME_FIELD_NAME].String();
                std::string source = userObj[AuthorizationManager::USER_SOURCE_FIELD_NAME].String();
                return Status(ErrorCodes::DuplicateKey,
                              mongoutils::str::stream() << "User \"" << name << "@" << source <<
                                      "\" already exists");
            }
            return Status(ErrorCodes::UserModificationFailed, errstr);
        } catch (const DBException& e) {
            return e.toStatus();
        }
    }
 Status AuthzManagerExternalStateMongos::getStoredAuthorizationVersion(int* outVersion) {
     scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(
             AuthorizationManager::usersCollectionNamespace));
     Status status = auth::getRemoteStoredAuthorizationVersion(conn->get(), outVersion);
     conn->done();
     return status;
 }
 Status AuthzManagerExternalStateMongos::getRoleDescriptionsForDB(const std::string dbname,
                                                                  bool showPrivileges,
                                                                  bool showBuiltinRoles,
                                                                  vector<BSONObj>* result) {
     try {
         scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(
                 AuthorizationManager::rolesCollectionNamespace));
         BSONObj cmdResult;
         conn->get()->runCommand(
                 dbname,
                 BSON("rolesInfo" << 1 <<
                      "showPrivileges" << showPrivileges <<
                      "showBuiltinRoles" << showBuiltinRoles),
                 cmdResult);
         if (!cmdResult["ok"].trueValue()) {
             int code = cmdResult["code"].numberInt();
             if (code == 0) code = ErrorCodes::UnknownError;
             return Status(ErrorCodes::Error(code), cmdResult["errmsg"].str());
         }
         for (BSONObjIterator it(cmdResult["roles"].Obj()); it.more(); it.next()) {
             result->push_back((*it).Obj().getOwned());
         }
         conn->done();
         return Status::OK();
     } catch (const DBException& e) {
         return e.toStatus();
     }
 }
 Status AuthzManagerExternalStateMongos::query(
         const NamespaceString& collectionName,
         const BSONObj& query,
         const boost::function<void(const BSONObj&)>& resultProcessor) {
     try {
         scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(collectionName));
         conn->get()->query(resultProcessor, collectionName.ns(), query);
         return Status::OK();
     } catch (const DBException& e) {
         return e.toStatus();
     }
 }
 Status AuthzManagerExternalStateMongos::query(
         const NamespaceString& collectionName,
         const BSONObj& queryDoc,
         const BSONObj& projection,
         const stdx::function<void(const BSONObj&)>& resultProcessor) {
     try {
         scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(collectionName));
         Query query(queryDoc);
         query.readPref(ReadPreference_PrimaryPreferred, BSONArray());
         conn->get()->query(resultProcessor, collectionName.ns(), query, &projection);
         return Status::OK();
     } catch (const DBException& e) {
         return e.toStatus();
     }
 }
 Status AuthzManagerExternalStateMongos::_findUser(const string& usersNamespace,
                                                   const BSONObj& query,
                                                   BSONObj* result) {
     try {
         scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(usersNamespace));
         *result = conn->get()->findOne(usersNamespace, query).getOwned();
         conn->done();
         if (result->isEmpty()) {
             return userNotFoundStatus;
         }
         return Status::OK();
     } catch (const DBException& e) {
         return e.toStatus();
     }
 }
    Status AuthzManagerExternalStateMongos::getAllV1PrivilegeDocsForDB(
            const std::string& dbname, std::vector<BSONObj>* privDocs) {
        try {
            NamespaceString usersNamespace(dbname, "system.users");
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(usersNamespace));
            auto_ptr<DBClientCursor> c = conn->get()->query(usersNamespace, Query());

            while (c->more()) {
                privDocs->push_back(c->nextSafe().getOwned());
            }
            conn->done();
            return Status::OK();
        } catch (const DBException& e) {
            return e.toStatus();
        }
    }
 Status AuthzManagerExternalStateMongos::findOne(
         const NamespaceString& collectionName,
         const BSONObj& queryDoc,
         BSONObj* result) {
     try {
         scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(collectionName));
         Query query(queryDoc);
         query.readPref(ReadPreference_PrimaryPreferred, BSONArray());
         *result = conn->get()->findOne(collectionName, query).getOwned();
         conn->done();
         if (result->isEmpty()) {
             return Status(ErrorCodes::NoMatchingDocument, mongoutils::str::stream() <<
                           "No document in " << collectionName.ns() << " matches " << queryDoc);
         }
         return Status::OK();
     } catch (const DBException& e) {
         return e.toStatus();
     }
 }
    Status AuthzManagerExternalStateMongos::getRoleDescription(const RoleName& roleName,
                                                               bool showPrivileges,
                                                               BSONObj* result) {
        try {
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(
                    AuthorizationManager::rolesCollectionNamespace));
            BSONObj cmdResult;
            conn->get()->runCommand(
                    "admin",
                    BSON("rolesInfo" <<
                         BSON_ARRAY(BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME <<
                                         roleName.getRole() <<
                                         AuthorizationManager::ROLE_SOURCE_FIELD_NAME <<
                                         roleName.getDB())) <<
                         "showPrivileges" << showPrivileges),
                    cmdResult);
            if (!cmdResult["ok"].trueValue()) {
                int code = cmdResult["code"].numberInt();
                if (code == 0) code = ErrorCodes::UnknownError;
                return Status(ErrorCodes::Error(code), cmdResult["errmsg"].str());
            }

            std::vector<BSONElement> foundRoles = cmdResult["roles"].Array();
            if (foundRoles.size() == 0) {
                return Status(ErrorCodes::RoleNotFound,
                              "Role \"" + roleName.toString() + "\" not found");
            }
            if (foundRoles.size() > 1) {
                return Status(ErrorCodes::RoleDataInconsistent,
                              mongoutils::str::stream() << "Found multiple roles on the \"" <<
                                      roleName.getDB() << "\" database with name \"" <<
                                      roleName.getRole() << "\"");
            }
            *result = foundRoles[0].Obj().getOwned();
            conn->done();
            return Status::OK();
        } catch (const DBException& e) {
            return e.toStatus();
        }
    }
    Status AuthzManagerExternalStateMongos::getUserDescription(
                    OperationContext* txn, const UserName& userName, BSONObj* result) {
        try {
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(
                    AuthorizationManager::usersCollectionNamespace));
            BSONObj cmdResult;
            conn->get()->runCommand(
                    "admin",
                    BSON("usersInfo" <<
                         BSON_ARRAY(BSON(AuthorizationManager::USER_NAME_FIELD_NAME <<
                                         userName.getUser() <<
                                         AuthorizationManager::USER_DB_FIELD_NAME <<
                                         userName.getDB())) <<
                         "showPrivileges" << true <<
                         "showCredentials" << true),
                    cmdResult);
            if (!cmdResult["ok"].trueValue()) {
                int code = cmdResult["code"].numberInt();
                if (code == 0) code = ErrorCodes::UnknownError;
                return Status(ErrorCodes::Error(code), cmdResult["errmsg"].str());
            }

            std::vector<BSONElement> foundUsers = cmdResult["users"].Array();
            if (foundUsers.size() == 0) {
                return Status(ErrorCodes::UserNotFound,
                              "User \"" + userName.toString() + "\" not found");
            }
            if (foundUsers.size() > 1) {
                return Status(ErrorCodes::UserDataInconsistent,
                              mongoutils::str::stream() << "Found multiple users on the \"" <<
                                      userName.getDB() << "\" database with name \"" <<
                                      userName.getUser() << "\"");
            }
            *result = foundUsers[0].Obj().getOwned();
            conn->done();
            return Status::OK();
        } catch (const DBException& e) {
            return e.toStatus();
        }
    }
 Status AuthzManagerExternalStateMongos::getUserDescription(const UserName& userName,
                                                            BSONObj* result) {
     try {
         scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(
                 AuthorizationManager::usersCollectionNamespace));
         BSONObj cmdResult;
         conn->get()->runCommand(
                 userName.getDB().toString(),  // TODO: Change usersInfo so this command can always go to "admin".
                 BSON("usersInfo" << userName.getUser() << "details" << true),
                 cmdResult);
         if (!cmdResult["ok"].trueValue()) {
             int code = cmdResult["code"].numberInt();
             if (code == 0) code = ErrorCodes::UnknownError;
             return Status(ErrorCodes::Error(code), cmdResult["errmsg"].str());
         }
         *result = cmdResult["users"]["0"].Obj().getOwned();
         conn->done();
         return Status::OK();
     } catch (const DBException& e) {
         return e.toStatus();
     }
 }
    Status AuthzManagerExternalStateMongos::getAllDatabaseNames(
            std::vector<std::string>* dbnames) {
        try {
            scoped_ptr<ScopedDbConnection> conn(
                    getConnectionForAuthzCollection(NamespaceString(DatabaseType::ConfigNS)));
            auto_ptr<DBClientCursor> c = conn->get()->query(DatabaseType::ConfigNS, Query());

            while (c->more()) {
                DatabaseType dbInfo;
                std::string errmsg;
                if (!dbInfo.parseBSON( c->nextSafe(), &errmsg) || !dbInfo.isValid( &errmsg )) {
                    return Status(ErrorCodes::FailedToParse, errmsg);
                }
                dbnames->push_back(dbInfo.getName());
            }
            conn->done();
            dbnames->push_back("config"); // config db isn't listed in config.databases
            return Status::OK();
        } catch (const DBException& e) {
            return e.toStatus();
        }
    }
    Status AuthzManagerExternalStateMongos::updatePrivilegeDocument(
            const UserName& user, const BSONObj& updateObj, const BSONObj& writeConcern) {
        try {
            const std::string userNS = "admin.system.users";
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(userNS));

            conn->get()->update(
                    userNS,
                    QUERY(AuthorizationManager::USER_NAME_FIELD_NAME << user.getUser() <<
                          AuthorizationManager::USER_SOURCE_FIELD_NAME << user.getDB()),
                    updateObj);

            // Handle write concern
            BSONObjBuilder gleBuilder;
            gleBuilder.append("getLastError", 1);
            gleBuilder.appendElements(writeConcern);
            BSONObj res;
            conn->get()->runCommand("admin", gleBuilder.done(), res);
            string err = conn->get()->getLastErrorString(res);
            conn->done();

            if (!err.empty()) {
                return Status(ErrorCodes::UserModificationFailed, err);
            }

            int numUpdated = res["n"].numberInt();
            dassert(numUpdated <= 1 && numUpdated >= 0);
            if (numUpdated == 0) {
                return Status(ErrorCodes::UserNotFound,
                              mongoutils::str::stream() << "User " << user.getFullName() <<
                                      " not found");
            }

            return Status::OK();
        } catch (const DBException& e) {
            return e.toStatus();
        }
    }
    Status AuthzManagerExternalStateMongos::getStoredAuthorizationVersion(int* outVersion) {
        try {
            scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection(
                    AuthorizationManager::usersCollectionNamespace));
            BSONObj cmdResult;
            conn->get()->runCommand(
                    "admin",
                    BSON("getParameter" << 1 <<
                         AuthorizationManager::schemaVersionServerParameter << 1),
                    cmdResult);
            if (!cmdResult["ok"].trueValue()) {
                std::string errmsg = cmdResult["errmsg"].str();
                if (errmsg == "no option found to get" ||
                    StringData(errmsg).startsWith("no such cmd")) {

                    *outVersion = 1;
                    conn->done();
                    return Status::OK();
                }
                int code = cmdResult["code"].numberInt();
                if (code == 0) {
                    code = ErrorCodes::UnknownError;
                }
                return Status(ErrorCodes::Error(code), errmsg);
            }
            BSONElement versionElement =
                cmdResult[AuthorizationManager::schemaVersionServerParameter];
            if (versionElement.eoo())
                return Status(ErrorCodes::UnknownError, "getParameter misbehaved.");
            *outVersion = versionElement.numberInt();
            conn->done();
            return Status::OK();
        } catch (const DBException& e) {
            return e.toStatus();
        }
    }