summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp5
-rw-r--r--src/mongo/db/auth/authorization_manager.h3
-rw-r--r--src/mongo/db/auth/authz_manager_external_state.h4
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_d.cpp34
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_d.h3
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.cpp5
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.h4
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.cpp29
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.h3
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp74
10 files changed, 164 insertions, 0 deletions
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp
index 8ace35e30bc..45401ee5c33 100644
--- a/src/mongo/db/auth/authorization_manager.cpp
+++ b/src/mongo/db/auth/authorization_manager.cpp
@@ -326,6 +326,11 @@ namespace {
return _externalState->updatePrivilegeDocument(user, updateObj);
}
+ Status AuthorizationManager::removePrivilegeDocuments(const std::string& dbname,
+ const BSONObj& query) const {
+ return _externalState->removePrivilegeDocuments(dbname, query);
+ }
+
ActionSet AuthorizationManager::getAllUserActions() const {
ActionSet allActions;
allActions.addAllActionsFromSet(readRoleActions);
diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h
index c35fd0e9f62..ea9c2446f94 100644
--- a/src/mongo/db/auth/authorization_manager.h
+++ b/src/mongo/db/auth/authorization_manager.h
@@ -103,6 +103,9 @@ namespace mongo {
// Updates the given user object with the given update modifier.
Status updatePrivilegeDocument(const UserName& user, const BSONObj& updateObj) const;
+ // Removes users for the given database matching the given query.
+ Status removePrivilegeDocuments(const std::string& dbname, const BSONObj& query) const;
+
// Checks to see if "doc" is a valid privilege document, assuming it is stored in the
// "system.users" collection of database "dbname".
//
diff --git a/src/mongo/db/auth/authz_manager_external_state.h b/src/mongo/db/auth/authz_manager_external_state.h
index 74584b867c6..72abb3e5190 100644
--- a/src/mongo/db/auth/authz_manager_external_state.h
+++ b/src/mongo/db/auth/authz_manager_external_state.h
@@ -58,6 +58,10 @@ namespace mongo {
virtual Status updatePrivilegeDocument(const UserName& user,
const BSONObj& updateObj) const = 0;
+ // Removes users for the given database matching the given query.
+ virtual Status removePrivilegeDocuments(const std::string& dbname,
+ const BSONObj& query) const = 0;
+
/**
* Puts into the *dbnames vector the name of every database in the cluster.
*/
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 6a72f3b8fac..b6647ded718 100644
--- a/src/mongo/db/auth/authz_manager_external_state_d.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_d.cpp
@@ -105,6 +105,40 @@ namespace {
}
}
+ Status AuthzManagerExternalStateMongod::removePrivilegeDocuments(const string& dbname,
+ const BSONObj& query) const {
+ try {
+ string userNS = dbname + ".system.users";
+ DBDirectClient client;
+ {
+ Client::GodScope gs;
+ // TODO(spencer): Once we're no longer fully rebuilding the user cache on every
+ // change to user data we should remove the global lock and uncomment the
+ // WriteContext below
+ Lock::GlobalWrite w;
+ // Client::WriteContext ctx(userNS);
+ client.remove(userNS, query);
+ }
+
+ // 30 second timeout for w:majority
+ BSONObj res = client.getLastErrorDetailed(false, false, -1, 30*1000);
+ string errstr = client.getLastErrorString(res);
+ if (!errstr.empty()) {
+ return Status(ErrorCodes::UserModificationFailed, errstr);
+ }
+
+ int numUpdated = res["n"].numberInt();
+ if (numUpdated == 0) {
+ return Status(ErrorCodes::UserNotFound,
+ mongoutils::str::stream() << "No users found on database \"" << dbname
+ << "\" matching query: " << query.toString());
+ }
+ return Status::OK();
+ } catch (const DBException& e) {
+ return e.toStatus();
+ }
+ }
+
Status AuthzManagerExternalStateMongod::_findUser(const string& usersNamespace,
const BSONObj& query,
BSONObj* result) const {
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 3998d6e7885..e4cac9da17a 100644
--- a/src/mongo/db/auth/authz_manager_external_state_d.h
+++ b/src/mongo/db/auth/authz_manager_external_state_d.h
@@ -41,6 +41,9 @@ namespace mongo {
virtual Status updatePrivilegeDocument(const UserName& user,
const BSONObj& updateObj) const;
+ virtual Status removePrivilegeDocuments(const std::string& dbname,
+ const BSONObj& query) const;
+
virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames) const;
virtual Status getAllV1PrivilegeDocsForDB(const std::string& dbname,
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 6dbbfffb48a..000edc6e418 100644
--- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp
@@ -36,6 +36,11 @@ namespace mongo {
return Status::OK();
}
+ Status AuthzManagerExternalStateMock::removePrivilegeDocuments(const std::string& dbname,
+ const BSONObj& query) const {
+ return Status::OK();
+ }
+
Status AuthzManagerExternalStateMock::insertPrivilegeDocument(const std::string& dbname,
const BSONObj& userObj) {
_userDocuments[dbname].push_back(userObj);
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 894088047b1..7551af9c427 100644
--- a/src/mongo/db/auth/authz_manager_external_state_mock.h
+++ b/src/mongo/db/auth/authz_manager_external_state_mock.h
@@ -45,6 +45,10 @@ namespace mongo {
virtual Status updatePrivilegeDocument(const UserName& user,
const BSONObj& updateObj) const;
+ // no-op for the mock
+ virtual Status removePrivilegeDocuments(const std::string& dbname,
+ const BSONObj& query) const;
+
// Non-const version that puts document into a vector that can be accessed later
Status insertPrivilegeDocument(const std::string& dbname, const BSONObj& userObj);
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 1d68983fb53..a0b3bd35b61 100644
--- a/src/mongo/db/auth/authz_manager_external_state_s.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp
@@ -126,6 +126,35 @@ namespace {
}
}
+ Status AuthzManagerExternalStateMongos::removePrivilegeDocuments(const string& dbname,
+ const BSONObj& query) const {
+ try {
+ string userNS = dbname + ".system.users";
+ scoped_ptr<ScopedDbConnection> conn(getConnectionForUsersCollection(userNS));
+
+ conn->get()->remove(userNS, query);
+
+ // 30 second timeout for w:majority
+ BSONObj res = conn->get()->getLastErrorDetailed(false, false, -1, 30*1000);
+ string err = conn->get()->getLastErrorString(res);
+ conn->done();
+
+ if (!err.empty()) {
+ return Status(ErrorCodes::UserModificationFailed, err);
+ }
+
+ int numUpdated = res["n"].numberInt();
+ if (numUpdated == 0) {
+ return Status(ErrorCodes::UserNotFound,
+ mongoutils::str::stream() << "No users found on database \"" << dbname
+ << "\" matching query: " << query.toString());
+ }
+ return Status::OK();
+ } catch (const DBException& e) {
+ return e.toStatus();
+ }
+ }
+
Status AuthzManagerExternalStateMongos::getAllDatabaseNames(
std::vector<std::string>* dbnames) const {
try {
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 7a80b80d124..4a9f72ded7f 100644
--- a/src/mongo/db/auth/authz_manager_external_state_s.h
+++ b/src/mongo/db/auth/authz_manager_external_state_s.h
@@ -41,6 +41,9 @@ namespace mongo {
virtual Status updatePrivilegeDocument(const UserName& user,
const BSONObj& updateObj) const;
+ virtual Status removePrivilegeDocuments(const std::string& dbname,
+ const BSONObj& query) const;
+
virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames) const;
virtual Status getAllV1PrivilegeDocsForDB(const std::string& dbname,
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index fe53db02fda..2a40a3a4e71 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -429,4 +429,78 @@ namespace mongo {
return Status::OK();
}
} cmdUpdateUser;
+
+ class CmdRemoveUsers : public Command {
+ public:
+
+ virtual bool logTheOp() {
+ return false;
+ }
+
+ virtual bool slaveOk() const {
+ return false;
+ }
+
+ virtual LockType locktype() const {
+ return NONE;
+ }
+
+ CmdRemoveUsers() : Command("removeUsers") {}
+
+ virtual void help(stringstream& ss) const {
+ ss << "By default, removes all users for this database. If given a \"user\""
+ " argument, removes only that user."<< endl;
+ }
+
+ virtual void addRequiredPrivileges(const std::string& dbname,
+ const BSONObj& cmdObj,
+ std::vector<Privilege>* 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));
+ }
+
+ // TODO: The bulk of the implementation of this will need to change once we're using the
+ // new v2 authorization storage format.
+ bool run(const string& dbname,
+ BSONObj& cmdObj,
+ int options,
+ string& errmsg,
+ BSONObjBuilder& result,
+ bool fromRepl) {
+ std::string user;
+
+ if (cmdObj.hasField("user")) {
+ Status status = bsonExtractStringField(cmdObj, "user", &user);
+ if (!status.isOK()) {
+ addStatus(status, result);
+ return false;
+ }
+ }
+
+ BSONObj query;
+ if (!user.empty()) {
+ query = BSON("user" << user);
+ }
+ AuthorizationManager* authzManager = getGlobalAuthorizationManager();
+ Status status = authzManager->removePrivilegeDocuments(dbname, query);
+ if (!status.isOK()) {
+ addStatus(status, result);
+ return false;
+ }
+
+ // Rebuild full user cache on every user modification.
+ // TODO(spencer): Remove this once we update user cache on-demand for each user
+ // modification.
+ status = authzManager->initializeAllV1UserData();
+ if (!status.isOK()) {
+ addStatus(status, result);
+ return false;
+ }
+
+ return true;
+ }
+
+ } cmdRemoveUser;
}