summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorSpencer T Brody <spencer@10gen.com>2013-10-25 15:03:59 -0400
committerSpencer T Brody <spencer@10gen.com>2013-10-28 14:57:51 -0400
commit0e35f9154fe51586d4bbc30267772a664b8df907 (patch)
treeea957c71863f019d40933c3561e593aac67f24e0 /src/mongo/db
parent38b665b22722ab442a9c022b54558e3cd7a9b84f (diff)
downloadmongo-0e35f9154fe51586d4bbc30267772a664b8df907.tar.gz
SERVER-8213 Make copyDB and clone work with auth when using new-style users
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/auth/action_types.txt4
-rw-r--r--src/mongo/db/auth/role_graph_builtin_roles.cpp6
-rw-r--r--src/mongo/db/cloner.cpp59
-rw-r--r--src/mongo/db/commands/copydb.h50
-rw-r--r--src/mongo/db/commands/copydb_common.cpp100
-rw-r--r--src/mongo/db/commands/rename_collection.cpp8
-rw-r--r--src/mongo/db/commands/rename_collection.h8
-rw-r--r--src/mongo/db/commands/rename_collection_common.cpp59
8 files changed, 233 insertions, 61 deletions
diff --git a/src/mongo/db/auth/action_types.txt b/src/mongo/db/auth/action_types.txt
index 8a2896719cc..f6115dfa060 100644
--- a/src/mongo/db/auth/action_types.txt
+++ b/src/mongo/db/auth/action_types.txt
@@ -17,9 +17,6 @@
"changeOwnCustomData",
"clean",
"cleanupOrphaned",
-"clone",
-"cloneCollectionLocalSource",
-"cloneCollectionTarget",
"closeAllDatabases",
"collMod",
"collStats",
@@ -27,7 +24,6 @@
"connPoolStats",
"connPoolSync",
"convertToCapped",
-"copyDBTarget",
"cpuProfiler",
"createCollection",
"createDatabase", # Not used for permissions checks, but to id the event in logs.
diff --git a/src/mongo/db/auth/role_graph_builtin_roles.cpp b/src/mongo/db/auth/role_graph_builtin_roles.cpp
index 1a6e5ba5b5b..b714fa7e9ec 100644
--- a/src/mongo/db/auth/role_graph_builtin_roles.cpp
+++ b/src/mongo/db/auth/role_graph_builtin_roles.cpp
@@ -93,7 +93,6 @@ namespace {
MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) {
// Read role
readRoleActions
- << ActionType::cloneCollectionLocalSource
<< ActionType::collStats
<< ActionType::dbHash
<< ActionType::dbStats
@@ -103,7 +102,6 @@ namespace {
// Read-write role
readWriteRoleActions += readRoleActions;
readWriteRoleActions
- << ActionType::cloneCollectionTarget
<< ActionType::convertToCapped // db admin gets this also
<< ActionType::createCollection // db admin gets this also
<< ActionType::dropCollection
@@ -134,7 +132,6 @@ namespace {
// DB admin role
dbAdminRoleActions
<< ActionType::clean
- << ActionType::cloneCollectionLocalSource
<< ActionType::collMod
<< ActionType::collStats // clusterMonitor gets this also
<< ActionType::compact
@@ -226,9 +223,6 @@ namespace {
dbOwnerRoleActions += readWriteRoleActions;
dbOwnerRoleActions += dbAdminRoleActions;
dbOwnerRoleActions += userAdminRoleActions;
- dbOwnerRoleActions
- << ActionType::clone
- << ActionType::copyDBTarget;
return Status::OK();
}
diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp
index 1e0b8c5a257..bd9ac2d66c2 100644
--- a/src/mongo/db/cloner.cpp
+++ b/src/mongo/db/cloner.cpp
@@ -33,8 +33,12 @@
#include "mongo/base/init.h"
#include "mongo/base/status.h"
#include "mongo/bson/util/builder.h"
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/resource_pattern.h"
+#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/cloner.h"
#include "mongo/db/commands.h"
+#include "mongo/db/commands/copydb.h"
#include "mongo/db/commands/rename_collection.h"
#include "mongo/db/db.h"
#include "mongo/db/dbhelpers.h"
@@ -318,7 +322,7 @@ namespace mongo {
opts.fromDB = fromdb;
opts.logForRepl = logForRepl;
opts.slaveOk = slaveOk;
- opts.useReplAuth = useReplAuth;
+ opts.useReplAuth = useReplAuth; // TODO(spencer): Remove this. SERVER-11423
opts.snapshot = snapshot;
opts.mayYield = mayYield;
opts.mayBeInterrupted = mayBeInterrupted;
@@ -549,14 +553,17 @@ namespace mongo {
help << "clone this database from an instance of the db on another host\n";
help << "{ clone : \"host13\" }";
}
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) {
- // Note: privileges required are currently only granted to old-style users for backwards
- // compatibility, and to internal connections (used in movePrimary).
+ virtual Status checkAuthForCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
ActionSet actions;
- actions.addAction(ActionType::clone);
- out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
+ actions.addAction(ActionType::insert);
+ actions.addAction(ActionType::createIndex);
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(dbname), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ return Status::OK();
}
CmdClone() : Command("clone") { }
virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
@@ -605,17 +612,20 @@ namespace mongo {
virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
return parseNsFullyQualified(dbname, cmdObj);
}
-
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) {
- // Will fail if source instance has auth on.
- NamespaceString ns(parseNs(dbname, cmdObj));
- uassert(16709, "bad 'cloneCollection' value '" + ns.ns() + "'", ns.isValid());
+ virtual Status checkAuthForCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
+ std::string ns = parseNs(dbname, cmdObj);
ActionSet actions;
- actions.addAction(ActionType::cloneCollectionTarget);
- out->push_back(Privilege(ResourcePattern::forExactNamespace(ns), actions));
+ actions.addAction(ActionType::insert);
+ actions.addAction(ActionType::createIndex); // SERVER-11418
+
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forExactNamespace(NamespaceString(ns)), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ return Status::OK();
}
virtual void help( stringstream &help ) const {
help << "{ cloneCollection: <collection>, from: <host> [,query: <query_filter>] [,copyIndexes:<bool>] }"
@@ -724,17 +734,10 @@ namespace mongo {
return false;
}
virtual LockType locktype() const { return NONE; }
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) {
- // Note: privileges required are currently only granted to old-style users for backwards
- // compatibility, since we can't properly handle auth checking for the read from the
- // source DB.
- ActionSet actions;
- // TODO: Should this become remove, insert, dropIndex,createIndex, etc., on "todb"?
- actions.addAction(ActionType::copyDBTarget);
- out->push_back(Privilege(ResourcePattern::forDatabaseName(cmdObj["todb"].str()),
- actions));
+ virtual Status checkAuthForCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
+ return copydb::checkAuthForCopydbCommand(client, dbname, cmdObj);
}
virtual void help( stringstream &help ) const {
help << "copy a database from another host to this host\n";
diff --git a/src/mongo/db/commands/copydb.h b/src/mongo/db/commands/copydb.h
new file mode 100644
index 00000000000..f7b2adfbe6d
--- /dev/null
+++ b/src/mongo/db/commands/copydb.h
@@ -0,0 +1,50 @@
+/**
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "mongo/db/auth/privilege.h"
+#include "mongo/db/jsobj.h"
+
+namespace mongo {
+
+ class ClientBasic;
+
+namespace copydb {
+
+ Status checkAuthForCopydbCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj);
+
+} // namespace copydb
+} // namespace mongo
+
+
diff --git a/src/mongo/db/commands/copydb_common.cpp b/src/mongo/db/commands/copydb_common.cpp
new file mode 100644
index 00000000000..5cebb8db021
--- /dev/null
+++ b/src/mongo/db/commands/copydb_common.cpp
@@ -0,0 +1,100 @@
+/**
+* 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 <http://www.gnu.org/licenses/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects for
+* all of the code used other than as permitted herein. If you modify file(s)
+* with this exception, you may extend this exception to your version of the
+* file(s), but you are not obligated to do so. If you do not wish to do so,
+* delete this exception statement from your version. If you delete this
+* exception statement from all source files in the program, then also delete
+* it in the license file.
+*/
+
+#include "mongo/db/commands/copydb.h"
+
+#include <string>
+#include <vector>
+
+#include "mongo/db/auth/action_set.h"
+#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/auth/privilege.h"
+#include "mongo/db/client_basic.h"
+#include "mongo/db/jsobj.h"
+#include "mongo/db/namespace_string.h"
+
+namespace mongo {
+namespace copydb {
+
+ Status checkAuthForCopydbCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
+ bool fromSelf = StringData(cmdObj.getStringField("fromhost")).empty();
+ StringData fromdb = cmdObj.getStringField("fromdb");
+ StringData todb = cmdObj.getStringField("todb");
+
+ // get system collections
+ std::vector<std::string> legalClientSystemCollections;
+ legalClientSystemCollections.push_back("system.js");
+ if (fromdb == "admin") {
+ legalClientSystemCollections.push_back("system.users");
+ legalClientSystemCollections.push_back("system.roles");
+ legalClientSystemCollections.push_back("system.version");
+ } else if (fromdb == "local") { // TODO(spencer): shouldn't be possible. See SERVER-11383
+ legalClientSystemCollections.push_back("system.replset");
+ }
+
+ // Check authorization on destination db
+ ActionSet actions;
+ actions.addAction(ActionType::insert);
+ actions.addAction(ActionType::createIndex);
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(todb), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+
+ actions.removeAllActions();
+ actions.addAction(ActionType::insert);
+ for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) {
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnNamespace(
+ NamespaceString(todb, legalClientSystemCollections[i]), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ }
+
+ if (fromSelf) {
+ // If copying from self, also require privileges on source db
+ actions.removeAllActions();
+ actions.addAction(ActionType::find);
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(fromdb), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) {
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnNamespace(
+ NamespaceString(fromdb, legalClientSystemCollections[i]), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ }
+ }
+ return Status::OK();
+ }
+
+} // namespace copydb
+} // namespace mongo
diff --git a/src/mongo/db/commands/rename_collection.cpp b/src/mongo/db/commands/rename_collection.cpp
index a81d02cb148..39fb0d29a1c 100644
--- a/src/mongo/db/commands/rename_collection.cpp
+++ b/src/mongo/db/commands/rename_collection.cpp
@@ -55,10 +55,10 @@ namespace mongo {
virtual bool logTheOp() {
return true; // can't log steps when doing fast rename within a db, so always log the op rather than individual steps comprising it.
}
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) {
- rename_collection::addPrivilegesRequiredForRenameCollection(cmdObj, out);
+ virtual Status checkAuthForCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
+ return rename_collection::checkAuthForRenameCollectionCommand(client, dbname, cmdObj);
}
virtual void help( stringstream &help ) const {
help << " example: { renameCollection: foo.a, to: bar.b }";
diff --git a/src/mongo/db/commands/rename_collection.h b/src/mongo/db/commands/rename_collection.h
index f58376fc6c5..f8651bccd4c 100644
--- a/src/mongo/db/commands/rename_collection.h
+++ b/src/mongo/db/commands/rename_collection.h
@@ -35,10 +35,14 @@
#include "mongo/db/jsobj.h"
namespace mongo {
+
+ class ClientBasic;
+
namespace rename_collection {
- void addPrivilegesRequiredForRenameCollection(const BSONObj& cmdObj,
- std::vector<Privilege>* out);
+ Status checkAuthForRenameCollectionCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj);
} // namespace rename_collection
} // namespace mongo
diff --git a/src/mongo/db/commands/rename_collection_common.cpp b/src/mongo/db/commands/rename_collection_common.cpp
index 33931b19547..fca7c97ba7f 100644
--- a/src/mongo/db/commands/rename_collection_common.cpp
+++ b/src/mongo/db/commands/rename_collection_common.cpp
@@ -33,35 +33,60 @@
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/privilege.h"
+#include "mongo/db/client_basic.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/namespace_string.h"
namespace mongo {
namespace rename_collection {
- void addPrivilegesRequiredForRenameCollection(const BSONObj& cmdObj,
- std::vector<Privilege>* out) {
+ Status checkAuthForRenameCollectionCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
NamespaceString sourceNS = NamespaceString(cmdObj.getStringField("renameCollection"));
NamespaceString targetNS = NamespaceString(cmdObj.getStringField("to"));
- uassert(17140, "Invalid source namespace " + sourceNS.ns(), sourceNS.isValid());
- uassert(17141, "Invalid target namespace " + targetNS.ns(), targetNS.isValid());
- ActionSet sourceActions;
- ActionSet targetActions;
+ bool dropTarget = cmdObj["dropTarget"].trueValue();
- if (sourceNS.db() == targetNS.db()) {
- sourceActions.addAction(ActionType::renameCollectionSameDB);
- targetActions.addAction(ActionType::renameCollectionSameDB);
- } else {
- sourceActions.addAction(ActionType::cloneCollectionLocalSource);
- sourceActions.addAction(ActionType::dropCollection);
- targetActions.addAction(ActionType::createCollection);
- targetActions.addAction(ActionType::cloneCollectionTarget);
- targetActions.addAction(ActionType::createIndex);
+ if (sourceNS.db() == targetNS.db() && !sourceNS.isSystem() && !targetNS.isSystem()) {
+ bool authed1 = client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forDatabaseName(sourceNS.db()),
+ ActionType::renameCollectionSameDB);
+
+ bool authed2 = true;
+ if (dropTarget) {
+ authed2 = client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forExactNamespace(targetNS), ActionType::dropCollection);
+ }
+
+ if (authed1 && authed2) {
+ return Status::OK();
+ }
+ }
+
+ // Check privileges on source collection
+ ActionSet actions;
+ actions.addAction(ActionType::find);
+ actions.addAction(ActionType::dropCollection);
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forExactNamespace(sourceNS), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+
+ // Check privileges on dest collection
+ actions.removeAllActions();
+ actions.addAction(ActionType::insert);
+ actions.addAction(ActionType::createIndex);
+ if (dropTarget) {
+ actions.addAction(ActionType::dropCollection);
+ }
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forExactNamespace(targetNS), actions)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
}
- out->push_back(Privilege(ResourcePattern::forExactNamespace(sourceNS), sourceActions));
- out->push_back(Privilege(ResourcePattern::forExactNamespace(targetNS), targetActions));
+ return Status::OK();
}
} // namespace rename_collection