diff options
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/auth/action_types.txt | 4 | ||||
-rw-r--r-- | src/mongo/db/auth/role_graph_builtin_roles.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/cloner.cpp | 59 | ||||
-rw-r--r-- | src/mongo/db/commands/copydb.h | 50 | ||||
-rw-r--r-- | src/mongo/db/commands/copydb_common.cpp | 100 | ||||
-rw-r--r-- | src/mongo/db/commands/rename_collection.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/commands/rename_collection.h | 8 | ||||
-rw-r--r-- | src/mongo/db/commands/rename_collection_common.cpp | 59 |
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 |