/** * Copyright (C) 2013 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include "mongo/base/status.h" #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/document.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/client/dbclientinterface.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_manager_global.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/auth/user.h" #include "mongo/db/commands.h" #include "mongo/db/commands/user_management_commands_parser.h" #include "mongo/db/jsobj.h" #include "mongo/platform/unordered_set.h" #include "mongo/util/mongoutils/str.h" namespace mongo { static void addStatus(const Status& status, BSONObjBuilder& builder) { builder.append("ok", status.isOK() ? 1.0: 0.0); if (!status.isOK()) builder.append("code", status.code()); if (!status.reason().empty()) builder.append("errmsg", status.reason()); } static void redactPasswordData(mutablebson::Element parent) { namespace mmb = mutablebson; const StringData pwdFieldName("pwd", StringData::LiteralTag()); for (mmb::Element pwdElement = mmb::findFirstChildNamed(parent, pwdFieldName); pwdElement.ok(); pwdElement = mmb::findElementNamed(pwdElement.rightSibling(), pwdFieldName)) { pwdElement.setValueString("xxx"); } } class CmdCreateUser : public Command { public: virtual bool logTheOp() { return false; } virtual bool slaveOk() const { return false; } virtual LockType locktype() const { return NONE; } CmdCreateUser() : Command("createUser") {} virtual void help(stringstream& ss) const { ss << "Adds a user to the system" << endl; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector* out) { // TODO: update this with the new rules around user creation in 2.6. ActionSet actions; actions.addAction(ActionType::userAdmin); out->push_back(Privilege(dbname, actions)); } bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); BSONObj userObj; Status status = auth::parseAndValidateCreateUserCommand(cmdObj, dbname, authzManager, &userObj); if (!status.isOK()) { addStatus(status, result); return false; } status = authzManager->insertPrivilegeDocument(dbname, userObj); if (!status.isOK()) { addStatus(status, result); return false; } return true; } virtual void redactForLogging(mutablebson::Document* cmdObj) { redactPasswordData(cmdObj->root()); } } cmdCreateUser; class CmdUpdateUser : public Command { public: virtual bool logTheOp() { return false; } virtual bool slaveOk() const { return false; } virtual LockType locktype() const { return NONE; } CmdUpdateUser() : Command("updateUser") {} virtual void help(stringstream& ss) const { ss << "Used to update a user, for example to change its password" << endl; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector* out) { // TODO: update this with the new rules around user creation in 2.6. ActionSet actions; actions.addAction(ActionType::userAdmin); out->push_back(Privilege(dbname, actions)); } bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); BSONObj updateObj; UserName userName; Status status = auth::parseAndValidateUpdateUserCommand(cmdObj, dbname, authzManager, &updateObj, &userName); if (!status.isOK()) { addStatus(status, result); return false; } status = authzManager->updatePrivilegeDocument(userName, updateObj); if (!status.isOK()) { addStatus(status, result); return false; } authzManager->invalidateUserByName(userName); return true; } virtual void redactForLogging(mutablebson::Document* cmdObj) { redactPasswordData(cmdObj->root()); } } cmdUpdateUser; class CmdRemoveUser : public Command { public: virtual bool logTheOp() { return false; } virtual bool slaveOk() const { return false; } virtual LockType locktype() const { return NONE; } CmdRemoveUser() : Command("removeUser") {} virtual void help(stringstream& ss) const { ss << "Removes a single user." << endl; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector* out) { // TODO: update this with the new rules around user creation in 2.6. ActionSet actions; actions.addAction(ActionType::userAdmin); out->push_back(Privilege(dbname, actions)); } bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { std::string user; Status status = bsonExtractStringField(cmdObj, "removeUser", &user); if (!status.isOK()) { addStatus(status, result); return false; } int numUpdated; AuthorizationManager* authzManager = getGlobalAuthorizationManager(); status = authzManager->removePrivilegeDocuments( BSON(AuthorizationManager::USER_NAME_FIELD_NAME << user << AuthorizationManager::USER_SOURCE_FIELD_NAME << dbname), &numUpdated); if (!status.isOK()) { addStatus(status, result); return false; } if (numUpdated == 0) { addStatus(Status(ErrorCodes::UserNotFound, mongoutils::str::stream() << "User '" << user << "@" << dbname << "' not found"), result); return false; } authzManager->invalidateUserByName(UserName(user, dbname)); return true; } } cmdRemoveUser; class CmdRemoveUsersFromDatabase : public Command { public: virtual bool logTheOp() { return false; } virtual bool slaveOk() const { return false; } virtual LockType locktype() const { return NONE; } CmdRemoveUsersFromDatabase() : Command("removeUsersFromDatabase") {} virtual void help(stringstream& ss) const { ss << "Removes all users for a single database." << endl; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector* out) { // TODO: update this with the new rules around user creation in 2.6. ActionSet actions; actions.addAction(ActionType::userAdmin); out->push_back(Privilege(dbname, actions)); } bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { int numRemoved; AuthorizationManager* authzManager = getGlobalAuthorizationManager(); Status status = authzManager->removePrivilegeDocuments( BSON(AuthorizationManager::USER_SOURCE_FIELD_NAME << dbname), &numRemoved); if (!status.isOK()) { addStatus(status, result); return false; } result.append("n", numRemoved); authzManager->invalidateUsersFromDB(dbname); return true; } } cmdRemoveUsersFromDatabase; }