summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@10gen.com>2013-09-20 10:36:01 -0400
committerAndy Schwerin <schwerin@10gen.com>2013-09-23 16:20:12 -0400
commita7f7c028c4cdda1ab0939c6c7788bb39bd94cc5f (patch)
tree270b9930bff0f280252850cd90ef0bf8e7de0a17
parent234f50a33cd6d2a2e0a30c4b1bddb1c7de176799 (diff)
downloadmongo-a7f7c028c4cdda1ab0939c6c7788bb39bd94cc5f.tar.gz
SERVER-1105 Use ResourcePattern type when identifying the resource component of required privileges.
This patch has two principal components. First, it changes the interface to Privilege and AuthorizationSession to use ResourcePattern in place of std::string for identifying resources. Second, it examines all call sites of the authorization session interface in commands and other code to ensure that the correct resource requirements are conveyed to the authorization_session.
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp2
-rw-r--r--src/mongo/db/auth/authorization_session.cpp181
-rw-r--r--src/mongo/db/auth/authorization_session.h70
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp372
-rw-r--r--src/mongo/db/auth/privilege.cpp6
-rw-r--r--src/mongo/db/auth/privilege.h12
-rw-r--r--src/mongo/db/auth/role_graph.cpp10
-rw-r--r--src/mongo/db/auth/role_graph_builtin_roles.cpp31
-rw-r--r--src/mongo/db/auth/role_graph_test.cpp112
-rw-r--r--src/mongo/db/auth/user.cpp12
-rw-r--r--src/mongo/db/auth/user.h6
-rw-r--r--src/mongo/db/client.cpp2
-rw-r--r--src/mongo/db/clientcursor.cpp14
-rw-r--r--src/mongo/db/cloner.cpp19
-rw-r--r--src/mongo/db/commands.cpp19
-rw-r--r--src/mongo/db/commands.h9
-rw-r--r--src/mongo/db/commands/apply_ops.cpp3
-rw-r--r--src/mongo/db/commands/cleanup_orphaned_cmd.cpp9
-rw-r--r--src/mongo/db/commands/cpuprofile.cpp2
-rw-r--r--src/mongo/db/commands/distinct.cpp2
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp2
-rw-r--r--src/mongo/db/commands/find_and_modify.h10
-rw-r--r--src/mongo/db/commands/find_and_modify_common.cpp11
-rw-r--r--src/mongo/db/commands/fsync.cpp2
-rw-r--r--src/mongo/db/commands/group.cpp2
-rw-r--r--src/mongo/db/commands/index_stats.cpp2
-rw-r--r--src/mongo/db/commands/merge_chunks_cmd.cpp9
-rw-r--r--src/mongo/db/commands/mr.cpp4
-rw-r--r--src/mongo/db/commands/mr.h3
-rw-r--r--src/mongo/db/commands/mr_common.cpp24
-rw-r--r--src/mongo/db/commands/parameters.cpp4
-rw-r--r--src/mongo/db/commands/pipeline_command.cpp2
-rw-r--r--src/mongo/db/commands/rename_collection_common.cpp6
-rw-r--r--src/mongo/db/commands/server_status.cpp4
-rw-r--r--src/mongo/db/commands/shutdown.cpp2
-rw-r--r--src/mongo/db/commands/storage_details.cpp2
-rw-r--r--src/mongo/db/commands/touch.cpp2
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp18
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp2
-rw-r--r--src/mongo/db/compact.cpp2
-rw-r--r--src/mongo/db/dbcommands.cpp66
-rw-r--r--src/mongo/db/dbcommands_admin.cpp2
-rw-r--r--src/mongo/db/dbcommands_generic.cpp8
-rw-r--r--src/mongo/db/dbeval.cpp4
-rw-r--r--src/mongo/db/exec/stagedebug_cmd.cpp2
-rw-r--r--src/mongo/db/fts/fts_command.cpp2
-rw-r--r--src/mongo/db/geo/geonear.cpp2
-rw-r--r--src/mongo/db/geo/haystack.cpp2
-rw-r--r--src/mongo/db/instance.cpp54
-rw-r--r--src/mongo/db/pipeline/pipeline.cpp27
-rw-r--r--src/mongo/db/pipeline/pipeline.h4
-rw-r--r--src/mongo/db/repl/consensus.cpp4
-rw-r--r--src/mongo/db/repl/heartbeat.cpp2
-rw-r--r--src/mongo/db/repl/master_slave.cpp2
-rw-r--r--src/mongo/db/repl/replset_commands.cpp16
-rw-r--r--src/mongo/db/repl/rs_initiate.cpp2
-rw-r--r--src/mongo/db/stats/top.cpp2
-rw-r--r--src/mongo/s/commands_admin.cpp30
-rw-r--r--src/mongo/s/commands_public.cpp77
-rw-r--r--src/mongo/s/cursors.cpp10
-rw-r--r--src/mongo/s/d_migrate.cpp14
-rw-r--r--src/mongo/s/d_split.cpp6
-rw-r--r--src/mongo/s/d_state.cpp8
-rw-r--r--src/mongo/s/d_writeback.cpp4
-rw-r--r--src/mongo/s/merge_chunks_cmd.cpp8
-rw-r--r--src/mongo/s/shard.cpp2
-rw-r--r--src/mongo/s/shardconnection.cpp2
-rw-r--r--src/mongo/s/strategy_shard.cpp27
-rw-r--r--src/mongo/s/strategy_single.cpp8
69 files changed, 872 insertions, 531 deletions
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp
index 71e10b9f0ff..7c0759c0807 100644
--- a/src/mongo/db/auth/authorization_manager.cpp
+++ b/src/mongo/db/auth/authorization_manager.cpp
@@ -61,7 +61,7 @@ namespace mongo {
user->incrementRefCount(); // Pin this user so the ref count never drops below 1.
ActionSet allActions;
allActions.addAllActions();
- user->addPrivilege(Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, allActions));
+ user->addPrivilege(Privilege(ResourcePattern::forAnyResource(), allActions));
internalSecurity.user = user;
diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp
index 01a5aee14f7..0c446fdd6f1 100644
--- a/src/mongo/db/auth/authorization_session.cpp
+++ b/src/mongo/db/auth/authorization_session.cpp
@@ -118,99 +118,140 @@ namespace {
_authenticatedUsers.add(internalSecurity.user);
}
- bool AuthorizationSession::checkAuthorization(const std::string& resource,
- ActionType action) {
- return checkAuthForPrivilege(Privilege(resource, action)).isOK();
- }
-
- bool AuthorizationSession::checkAuthorization(const std::string& resource,
- ActionSet actions) {
- return checkAuthForPrivilege(Privilege(resource, actions)).isOK();
- }
-
- Status AuthorizationSession::checkAuthForQuery(const std::string& ns, const BSONObj& query) {
- NamespaceString namespaceString(ns);
- verify(!namespaceString.isCommand());
- if (!checkAuthorization(ns, ActionType::find)) {
+ Status AuthorizationSession::checkAuthForQuery(const NamespaceString& ns,
+ const BSONObj& query) {
+ if (MONGO_unlikely(ns.isCommand())) {
+ return Status(ErrorCodes::InternalError, mongoutils::str::stream() <<
+ "Checking query auth on command namespace " << ns.ns());
+ }
+ if (!isAuthorizedForActionsOnNamespace(ns, ActionType::find)) {
return Status(ErrorCodes::Unauthorized,
- mongoutils::str::stream() << "not authorized for query on " << ns,
- 0);
+ mongoutils::str::stream() << "not authorized for query on " << ns.ns());
}
return Status::OK();
}
- Status AuthorizationSession::checkAuthForGetMore(const std::string& ns, long long cursorID) {
- if (!checkAuthorization(ns, ActionType::find)) {
+ Status AuthorizationSession::checkAuthForGetMore(const NamespaceString& ns,
+ long long cursorID) {
+ if (!isAuthorizedForActionsOnNamespace(ns, ActionType::find)) {
return Status(ErrorCodes::Unauthorized,
- mongoutils::str::stream() << "not authorized for getmore on " << ns,
- 0);
+ mongoutils::str::stream() << "not authorized for getmore on " << ns.ns());
}
return Status::OK();
}
- Status AuthorizationSession::checkAuthForInsert(const std::string& ns,
+ Status AuthorizationSession::checkAuthForInsert(const NamespaceString& ns,
const BSONObj& document) {
- NamespaceString namespaceString(ns);
- if (namespaceString.coll() == StringData("system.indexes", StringData::LiteralTag())) {
- std::string indexNS = document["ns"].String();
- if (!checkAuthorization(indexNS, ActionType::ensureIndex)) {
+ if (ns.coll() == StringData("system.indexes", StringData::LiteralTag())) {
+ BSONElement nsElement = document["ns"];
+ if (nsElement.type() != String) {
+ return Status(ErrorCodes::Unauthorized, "Cannot authorize inserting into "
+ "system.indexes documents without a string-typed \"ns\" field.");
+ }
+ NamespaceString indexNS(nsElement.str());
+ if (!isAuthorizedForActionsOnNamespace(indexNS, ActionType::ensureIndex)) {
return Status(ErrorCodes::Unauthorized,
mongoutils::str::stream() << "not authorized to create index on " <<
- indexNS,
- 0);
+ indexNS.ns());
}
} else {
- if (!checkAuthorization(ns, ActionType::insert)) {
+ if (!isAuthorizedForActionsOnNamespace(ns, ActionType::insert)) {
return Status(ErrorCodes::Unauthorized,
- mongoutils::str::stream() << "not authorized for insert on " << ns,
- 0);
+ mongoutils::str::stream() << "not authorized for insert on " <<
+ ns.ns());
}
}
return Status::OK();
}
- Status AuthorizationSession::checkAuthForUpdate(const std::string& ns,
+ Status AuthorizationSession::checkAuthForUpdate(const NamespaceString& ns,
const BSONObj& query,
const BSONObj& update,
bool upsert) {
- NamespaceString namespaceString(ns);
if (!upsert) {
- if (!checkAuthorization(ns, ActionType::update)) {
+ if (!isAuthorizedForActionsOnNamespace(ns, ActionType::update)) {
return Status(ErrorCodes::Unauthorized,
- mongoutils::str::stream() << "not authorized for update on " << ns,
- 0);
+ mongoutils::str::stream() << "not authorized for update on " <<
+ ns.ns());
}
}
else {
ActionSet required;
required.addAction(ActionType::update);
required.addAction(ActionType::insert);
- if (!checkAuthorization(ns, required)) {
+ if (!isAuthorizedForActionsOnNamespace(ns, required)) {
return Status(ErrorCodes::Unauthorized,
- mongoutils::str::stream() << "not authorized for upsert on " << ns,
- 0);
+ mongoutils::str::stream() << "not authorized for upsert on " <<
+ ns.ns());
}
}
return Status::OK();
}
- Status AuthorizationSession::checkAuthForDelete(const std::string& ns, const BSONObj& query) {
- NamespaceString namespaceString(ns);
- if (!checkAuthorization(ns, ActionType::remove)) {
+ Status AuthorizationSession::checkAuthForDelete(const NamespaceString& ns,
+ const BSONObj& query) {
+ if (!isAuthorizedForActionsOnNamespace(ns, ActionType::remove)) {
return Status(ErrorCodes::Unauthorized,
- mongoutils::str::stream() << "not authorized to remove from " << ns,
- 0);
+ mongoutils::str::stream() << "not authorized to remove from " << ns.ns());
}
return Status::OK();
}
- Privilege AuthorizationSession::_modifyPrivilegeForSpecialCases(const Privilege& privilege) {
- ActionSet newActions;
- newActions.addAllActionsFromSet(privilege.getActions());
- NamespaceString ns( privilege.getResource() );
- if (ns.coll() == "system.users") {
+ bool AuthorizationSession::isAuthorizedForPrivilege(const Privilege& privilege) {
+ if (_externalState->shouldIgnoreAuthChecks())
+ return true;
+
+ return _isAuthorizedForPrivilege(privilege);
+ }
+
+ bool AuthorizationSession::isAuthorizedForPrivileges(const vector<Privilege>& privileges) {
+ if (_externalState->shouldIgnoreAuthChecks())
+ return true;
+
+ for (size_t i = 0; i < privileges.size(); ++i) {
+ if (!_isAuthorizedForPrivilege(privileges[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool AuthorizationSession::isAuthorizedForActionsOnResource(const ResourcePattern& resource,
+ ActionType action) {
+ return isAuthorizedForPrivilege(Privilege(resource, action));
+ }
+
+ bool AuthorizationSession::isAuthorizedForActionsOnResource(const ResourcePattern& resource,
+ const ActionSet& actions) {
+ return isAuthorizedForPrivilege(Privilege(resource, actions));
+ }
+
+ bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns,
+ ActionType action) {
+ return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), action));
+ }
+
+ bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns,
+ const ActionSet& actions) {
+ return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), actions));
+ }
+
+ static const ResourcePattern anyUsersCollectionPattern = ResourcePattern::forCollectionName(
+ "system.users");
+ static const ResourcePattern anyProfileCollectionPattern = ResourcePattern::forCollectionName(
+ "system.profile");
+ static const ResourcePattern anyIndexesCollectionPattern = ResourcePattern::forCollectionName(
+ "system.indexes");
+
+ // Returns a new privilege that has replaced the actions needed to handle special casing
+ // certain namespaces like system.users and system.profile. Note that the special handling
+ // of system.indexes takes place in checkAuthForInsert, not here.
+ static Privilege _modifyPrivilegeForSpecialCases(Privilege privilege) {
+ ActionSet newActions(privilege.getActions());
+ const ResourcePattern& target(privilege.getResourcePattern());
+ if (anyUsersCollectionPattern.matchesResourcePattern(target)) {
if (newActions.contains(ActionType::insert) ||
newActions.contains(ActionType::update) ||
newActions.contains(ActionType::remove)) {
@@ -223,47 +264,31 @@ namespace {
newActions.removeAction(ActionType::insert);
newActions.removeAction(ActionType::update);
newActions.removeAction(ActionType::remove);
- } else if (ns.coll() == "system.profile") {
+ } else if (anyProfileCollectionPattern.matchesResourcePattern(target)) {
newActions.removeAction(ActionType::find);
newActions.addAction(ActionType::profileRead);
- } else if (ns.coll() == "system.indexes" && newActions.contains(ActionType::find)) {
+ } else if (anyIndexesCollectionPattern.matchesResourcePattern(target)
+ && newActions.contains(ActionType::find)) {
newActions.removeAction(ActionType::find);
newActions.addAction(ActionType::indexRead);
}
- return Privilege(privilege.getResource(), newActions);
- }
-
- Status AuthorizationSession::checkAuthForPrivilege(const Privilege& privilege) {
- if (_externalState->shouldIgnoreAuthChecks())
- return Status::OK();
-
- return _checkAuthForPrivilegeHelper(privilege);
+ return Privilege(privilege.getResourcePattern(), newActions);
}
- Status AuthorizationSession::checkAuthForPrivileges(const vector<Privilege>& privileges) {
- if (_externalState->shouldIgnoreAuthChecks())
- return Status::OK();
-
- for (size_t i = 0; i < privileges.size(); ++i) {
- Status status = _checkAuthForPrivilegeHelper(privileges[i]);
- if (!status.isOK())
- return status;
- }
-
- return Status::OK();
- }
-
- Status AuthorizationSession::_checkAuthForPrivilegeHelper(const Privilege& privilege) {
+ bool AuthorizationSession::_isAuthorizedForPrivilege(const Privilege& privilege) {
AuthorizationManager& authMan = getAuthorizationManager();
Privilege modifiedPrivilege = _modifyPrivilegeForSpecialCases(privilege);
// Need to check not just the resource of the privilege, but also just the database
// component and the "*" resource.
- std::string resourceSearchList[3];
- resourceSearchList[0] = AuthorizationManager::WILDCARD_RESOURCE_NAME;
- resourceSearchList[1] = nsToDatabase(modifiedPrivilege.getResource());
- resourceSearchList[2] = modifiedPrivilege.getResource();
+ ResourcePattern resourceSearchList[3];
+ resourceSearchList[0] = ResourcePattern::forAnyResource();
+ resourceSearchList[1] = modifiedPrivilege.getResourcePattern();
+ if (modifiedPrivilege.getResourcePattern().isExactNamespacePattern()) {
+ resourceSearchList[2] =
+ ResourcePattern::forDatabaseName(modifiedPrivilege.getResourcePattern().ns().db());
+ }
ActionSet unmetRequirements = modifiedPrivilege.getActions();
@@ -309,12 +334,12 @@ namespace {
unmetRequirements.removeAllActionsFromSet(userActions);
if (unmetRequirements.empty())
- return Status::OK();
+ return true;
}
++it;
}
- return Status(ErrorCodes::Unauthorized, "unauthorized");
+ return false;
}
} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h
index 7bb5947b432..ccd5cf28fd5 100644
--- a/src/mongo/db/auth/authorization_session.h
+++ b/src/mongo/db/auth/authorization_session.h
@@ -40,15 +40,19 @@
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/user_name.h"
#include "mongo/db/auth/user_set.h"
+#include "mongo/db/namespace_string.h"
namespace mongo {
/**
* Contains all the authorization logic for a single client connection. It contains a set of
- * the principals which have been authenticated, as well as a set of privileges that have been
- * granted by those principals to perform various actions.
- * An AuthorizationSession object is present within every mongo::Client object, therefore there
- * is one per thread that corresponds to an incoming client connection.
+ * the users which have been authenticated, as well as a set of privileges that have been
+ * granted to those users to perform various actions.
+ *
+ * An AuthorizationSession object is present within every mongo::ClientBasic object.
+ *
+ * Predicate methods for checking authorization may in the worst case acquire read locks
+ * on the admin database.
*/
class AuthorizationSession {
MONGO_DISALLOW_COPYING(AuthorizationSession);
@@ -92,27 +96,17 @@ namespace mongo {
// Used to grant internal threads full access.
void grantInternalAuthorization();
- // Checks if this connection has the privileges required to perform the given action
- // on the given resource. Contains all the authorization logic including handling things
- // like the localhost exception. Returns true if the action may proceed on the resource.
- // Note: this may acquire a database read lock (for automatic privilege acquisition).
- bool checkAuthorization(const std::string& resource, ActionType action);
-
- // Same as above but takes an ActionSet instead of a single ActionType. Returns true if
- // all of the actions may proceed on the resource.
- bool checkAuthorization(const std::string& resource, ActionSet actions);
-
// Checks if this connection has the privileges necessary to perform the given query on the
// given namespace.
- Status checkAuthForQuery(const std::string& ns, const BSONObj& query);
+ Status checkAuthForQuery(const NamespaceString& ns, const BSONObj& query);
// Checks if this connection has the privileges necessary to perform a getMore on the given
// cursor in the given namespace.
- Status checkAuthForGetMore(const std::string& ns, long long cursorID);
+ Status checkAuthForGetMore(const NamespaceString& ns, long long cursorID);
// Checks if this connection has the privileges necessary to perform the given update on the
// given namespace.
- Status checkAuthForUpdate(const std::string& ns,
+ Status checkAuthForUpdate(const NamespaceString& ns,
const BSONObj& query,
const BSONObj& update,
bool upsert);
@@ -120,29 +114,43 @@ namespace mongo {
// Checks if this connection has the privileges necessary to insert the given document
// to the given namespace. Correctly interprets inserts to system.indexes and performs
// the proper auth checks for index building.
- Status checkAuthForInsert(const std::string& ns, const BSONObj& document);
+ Status checkAuthForInsert(const NamespaceString& ns, const BSONObj& document);
// Checks if this connection has the privileges necessary to perform a delete on the given
// namespace.
- Status checkAuthForDelete(const std::string& ns, const BSONObj& query);
+ Status checkAuthForDelete(const NamespaceString& ns, const BSONObj& query);
- // Checks if this connection is authorized for the given Privilege.
- Status checkAuthForPrivilege(const Privilege& privilege);
+ // Returns true if this session is authorized for the given Privilege.
+ //
+ // Contains all the authorization logic including handling things like the localhost
+ // exception.
+ bool isAuthorizedForPrivilege(const Privilege& privilege);
- // Checks if this connection is authorized for all the given Privileges.
- Status checkAuthForPrivileges(const vector<Privilege>& privileges);
+ // Like isAuthorizedForPrivilege, above, except returns true if the session is authorized
+ // for all of the listed privileges.
+ bool isAuthorizedForPrivileges(const vector<Privilege>& privileges);
- private:
+ // Utility function for isAuthorizedForPrivilege(Privilege(resource, action)).
+ bool isAuthorizedForActionsOnResource(const ResourcePattern& resource, ActionType action);
- // Checks if this connection is authorized for the given Privilege, ignoring whether or not
- // we should even be doing authorization checks in general.
- Status _checkAuthForPrivilegeHelper(const Privilege& privilege);
+ // Utility function for isAuthorizedForPrivilege(Privilege(resource, actions)).
+ bool isAuthorizedForActionsOnResource(const ResourcePattern& resource,
+ const ActionSet& actions);
- // Returns a new privilege that has replaced the actions needed to handle special casing
- // certain namespaces like system.users and system.profile. Note that the special handling
- // of system.indexes takes place in checkAuthForInsert, not here.
- Privilege _modifyPrivilegeForSpecialCases(const Privilege& privilege);
+ // Utility function for
+ // isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), action).
+ bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, ActionType action);
+ // Utility function for
+ // isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), actions).
+ bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, const ActionSet& actions);
+
+ private:
+
+ // Checks if this connection is authorized for the given Privilege, ignoring whether or not
+ // we should even be doing authorization checks in general. Note: this may acquire a read
+ // lock on the admin database (to update out-of-date user privilege information).
+ bool _isAuthorizedForPrivilege(const Privilege& privilege);
scoped_ptr<AuthzSessionExternalState> _externalState;
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp
index 837db1fb1f0..e2391670501 100644
--- a/src/mongo/db/auth/authorization_session_test.cpp
+++ b/src/mongo/db/auth/authorization_session_test.cpp
@@ -72,13 +72,46 @@ namespace {
}
};
+ const ResourcePattern testDBResource(ResourcePattern::forDatabaseName("test"));
+ const ResourcePattern otherDBResource(ResourcePattern::forDatabaseName("other"));
+ const ResourcePattern adminDBResource(ResourcePattern::forDatabaseName("admin"));
+ const ResourcePattern testFooCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("test.foo")));
+ const ResourcePattern otherFooCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("other.foo")));
+ const ResourcePattern thirdFooCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("third.foo")));
+ const ResourcePattern adminFooCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("admin.foo")));
+ const ResourcePattern testUsersCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("test.system.users")));
+ const ResourcePattern otherUsersCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("other.system.users")));
+ const ResourcePattern thirdUsersCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("third.system.users")));
+ const ResourcePattern testIndexesCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("test.system.indexes")));
+ const ResourcePattern otherIndexesCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("other.system.indexes")));
+ const ResourcePattern thirdIndexesCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("third.system.indexes")));
+ const ResourcePattern testProfileCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("test.system.profile")));
+ const ResourcePattern otherProfileCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("other.system.profile")));
+ const ResourcePattern thirdProfileCollResource(
+ ResourcePattern::forExactNamespace(NamespaceString("third.system.profile")));
+
TEST_F(AuthorizationSessionTest, AddUserAndCheckAuthorization) {
// Check that disabling auth checks works
- ASSERT_FALSE(authzSession->checkAuthorization("test", ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
sessionState->setReturnValueForShouldIgnoreAuthChecks(true);
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
sessionState->setReturnValueForShouldIgnoreAuthChecks(false);
- ASSERT_FALSE(authzSession->checkAuthorization("test", ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
// Check that you can't authorize a user that doesn't exist.
ASSERT_EQUALS(ErrorCodes::UserNotFound,
@@ -100,11 +133,12 @@ namespace {
BSONObj()));
ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test")));
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::insert));
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::collMod));
- // Auth checks on a collection should be applied to the database name.
- ASSERT_TRUE(authzSession->checkAuthorization("test.foo", ActionType::insert));
- ASSERT_FALSE(authzSession->checkAuthorization("otherDb", ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testDBResource, ActionType::dbStats));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::insert));
// Add an admin user with readWriteAnyDatabase
ASSERT_OK(managerState->insertPrivilegeDocument("admin",
@@ -118,21 +152,157 @@ namespace {
BSONObj()));
ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("admin", "admin")));
- ASSERT_TRUE(authzSession->checkAuthorization("*", ActionType::insert));
- ASSERT_TRUE(authzSession->checkAuthorization("otherDb", ActionType::insert));
- ASSERT_TRUE(authzSession->checkAuthorization("otherDb.foo", ActionType::insert));
- ASSERT_FALSE(authzSession->checkAuthorization("otherDb.foo", ActionType::collMod));
- ASSERT_TRUE(authzSession->checkAuthorization("test.foo", ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ ResourcePattern::forAnyNormalResource(), ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ otherDBResource, ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::collMod));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
authzSession->logoutDatabase("test");
- ASSERT_TRUE(authzSession->checkAuthorization("otherDb", ActionType::insert));
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::insert));
- ASSERT_FALSE(authzSession->checkAuthorization("test.foo", ActionType::collMod));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::collMod));
authzSession->logoutDatabase("admin");
- ASSERT_FALSE(authzSession->checkAuthorization("otherDb", ActionType::insert));
- ASSERT_FALSE(authzSession->checkAuthorization("test", ActionType::insert));
- ASSERT_FALSE(authzSession->checkAuthorization("test.foo", ActionType::collMod));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::collMod));
+ }
+
+ TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) {
+ ASSERT_OK(managerState->insertPrivilegeDocument("admin",
+ BSON("name" << "rw" <<
+ "source" << "test" <<
+ "credentials" << BSON("MONGODB-CR" << "a") <<
+ "roles" << BSON_ARRAY(BSON("name" << "readWrite" <<
+ "source" << "test" <<
+ "hasRole" << true <<
+ "canDelegate" << false) <<
+ BSON("name" << "dbAdmin" <<
+ "source" << "test" <<
+ "hasRole" << true <<
+ "canDelegate" << false))),
+ BSONObj()));
+ ASSERT_OK(managerState->insertPrivilegeDocument("admin",
+ BSON("name" << "useradmin" <<
+ "source" << "test" <<
+ "credentials" << BSON("MONGODB-CR" << "a") <<
+ "roles" << BSON_ARRAY(BSON("name" << "userAdmin" <<
+ "source" << "test" <<
+ "hasRole" << true <<
+ "canDelegate" << false))),
+ BSONObj()));
+ ASSERT_OK(managerState->insertPrivilegeDocument("admin",
+ BSON("name" << "rwany" <<
+ "source" << "test" <<
+ "credentials" << BSON("MONGODB-CR" << "a") <<
+ "roles" << BSON_ARRAY(BSON("name" << "readWriteAnyDatabase" <<
+ "source" << "admin" <<
+ "hasRole" << true <<
+ "canDelegate" << false) <<
+ BSON("name" << "dbAdminAnyDatabase" <<
+ "source" << "admin" <<
+ "hasRole" << true <<
+ "canDelegate" << false))),
+ BSONObj()));
+ ASSERT_OK(managerState->insertPrivilegeDocument("admin",
+ BSON("name" << "useradminany" <<
+ "source" << "test" <<
+ "credentials" << BSON("MONGODB-CR" << "a") <<
+ "roles" << BSON_ARRAY(BSON("name" << "userAdminAnyDatabase" <<
+ "source" << "admin" <<
+ "hasRole" << true <<
+ "canDelegate" << false))),
+ BSONObj()));
+
+ ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("rwany", "test")));
+
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testUsersCollResource, ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testUsersCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherUsersCollResource, ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherUsersCollResource, ActionType::find));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testIndexesCollResource, ActionType::find));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testProfileCollResource, ActionType::find));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ otherIndexesCollResource, ActionType::find));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ otherProfileCollResource, ActionType::find));
+
+ // Logging in as useradminany@test implicitly logs out rwany@test.
+ ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("useradminany", "test")));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testUsersCollResource, ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testUsersCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherUsersCollResource, ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ otherUsersCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testIndexesCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testProfileCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherIndexesCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherProfileCollResource, ActionType::find));
+
+ // Logging in as rw@test implicitly logs out useradminany@test.
+ ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("rw", "test")));
+
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testUsersCollResource, ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testUsersCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherUsersCollResource, ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherUsersCollResource, ActionType::find));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testIndexesCollResource, ActionType::find));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testProfileCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherIndexesCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherProfileCollResource, ActionType::find));
+
+
+ // Logging in as useradmin@test implicitly logs out rw@test.
+ ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("useradmin", "test")));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testUsersCollResource, ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testUsersCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherUsersCollResource, ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherUsersCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testIndexesCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testProfileCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherIndexesCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ otherProfileCollResource, ActionType::find));
}
TEST_F(AuthorizationSessionTest, InvalidateUser) {
@@ -148,8 +318,10 @@ namespace {
BSONObj()));
ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test")));
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::find));
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::find));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
User* user = authzSession->lookupUser(UserName("spencer", "test"));
ASSERT(user->isValid());
@@ -168,8 +340,10 @@ namespace {
// Make sure that invalidating the user causes the session to reload its privileges.
authzManager->invalidateUser(user);
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::find));
- ASSERT_FALSE(authzSession->checkAuthorization("test", ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
user = authzSession->lookupUser(UserName("spencer", "test"));
ASSERT(user->isValid());
@@ -178,8 +352,10 @@ namespace {
managerState->clearPrivilegeDocuments();
// Make sure that invalidating the user causes the session to reload its privileges.
authzManager->invalidateUser(user);
- ASSERT_FALSE(authzSession->checkAuthorization("test", ActionType::find));
- ASSERT_FALSE(authzSession->checkAuthorization("test", ActionType::insert));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
ASSERT_FALSE(authzSession->lookupUser(UserName("spencer", "test")));
}
@@ -196,8 +372,10 @@ namespace {
BSONObj()));
ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test")));
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::find));
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::find));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
User* user = authzSession->lookupUser(UserName("spencer", "test"));
ASSERT(user->isValid());
@@ -219,8 +397,18 @@ namespace {
// document lookup to fail, the authz session should continue to use its known out-of-date
// privilege data.
authzManager->invalidateUser(user);
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::find));
- ASSERT_TRUE(authzSession->checkAuthorization("test", ActionType::insert));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::find));
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
+
+ // Once we configure document lookup to succeed again, authorization checks should
+ // observe the new values.
+ managerState->setFindsShouldFail(false);
+ ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::find));
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
}
@@ -232,7 +420,7 @@ namespace {
"pwd" << "a" <<
"roles" << BSON_ARRAY("readWrite")),
BSONObj());
- managerState->insert(NamespaceString("test2.system.users"),
+ managerState->insert(NamespaceString("other.system.users"),
BSON("user" << "andy" <<
"userSource" << "test" <<
"roles" << BSON_ARRAY("read")),
@@ -241,62 +429,98 @@ namespace {
BSON("user" << "andy" <<
"userSource" << "test" <<
"roles" << BSON_ARRAY("clusterAdmin") <<
- "otherDBRoles" << BSON("test3" << BSON_ARRAY("dbAdmin"))),
+ "otherDBRoles" << BSON("third" << BSON_ARRAY("dbAdmin"))),
BSONObj());
ASSERT_OK(authzManager->initialize());
- ASSERT(!authzSession->checkAuthorization("test.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("test.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("test.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("test2.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("test2.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("test2.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("test3.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("test3.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("test3.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("admin.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("admin.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("admin.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("$SERVER", ActionType::shutdown));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ thirdFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ thirdFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ thirdFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ adminFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ adminFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ adminFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::shutdown));
ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("andy", "test")));
User* user = authzSession->lookupUser(UserName("andy", "test"));
ASSERT(UserName("andy", "test") == user->getName());
+ authzManager->releaseUser(user);
- ASSERT(authzSession->checkAuthorization("test.foo", ActionType::find));
- ASSERT(authzSession->checkAuthorization("test.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("test.foo", ActionType::collMod));
- ASSERT(authzSession->checkAuthorization("test2.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("test2.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("test2.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("test3.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("test3.foo", ActionType::insert));
- ASSERT(authzSession->checkAuthorization("test3.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("admin.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("admin.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("admin.foo", ActionType::collMod));
- ASSERT(authzSession->checkAuthorization("$SERVER", ActionType::shutdown));
+ ASSERT(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::find));
+ ASSERT(authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::collMod));
+ ASSERT(authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ thirdFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ thirdFooCollResource, ActionType::insert));
+ ASSERT(authzSession->isAuthorizedForActionsOnResource(
+ thirdFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ adminFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ adminFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ adminFooCollResource, ActionType::collMod));
+ ASSERT(authzSession->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::shutdown));
authzSession->logoutDatabase("test");
- ASSERT(!authzSession->checkAuthorization("test.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("test.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("test.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("test2.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("test2.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("test2.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("test3.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("test3.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("test3.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("admin.foo", ActionType::find));
- ASSERT(!authzSession->checkAuthorization("admin.foo", ActionType::insert));
- ASSERT(!authzSession->checkAuthorization("admin.foo", ActionType::collMod));
- ASSERT(!authzSession->checkAuthorization("$SERVER", ActionType::shutdown));
-
- // initializeAllV1UserData() pins the users by adding 1 to their refCount, so need to
- // release the user an extra time to bring its refCount to 0.
- authzManager->releaseUser(user);
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ testFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ otherFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ thirdFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ thirdFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ thirdFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ adminFooCollResource, ActionType::find));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ adminFooCollResource, ActionType::insert));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ adminFooCollResource, ActionType::collMod));
+ ASSERT(!authzSession->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::shutdown));
}
} // namespace
diff --git a/src/mongo/db/auth/privilege.cpp b/src/mongo/db/auth/privilege.cpp
index b048af41777..89261791f98 100644
--- a/src/mongo/db/auth/privilege.cpp
+++ b/src/mongo/db/auth/privilege.cpp
@@ -15,19 +15,17 @@
#include "mongo/db/auth/privilege.h"
-#include <string>
-
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
namespace mongo {
- Privilege::Privilege(const std::string& resource, const ActionType& action) :
+ Privilege::Privilege(const ResourcePattern& resource, const ActionType& action) :
_resource(resource) {
_actions.addAction(action);
}
- Privilege::Privilege(const std::string& resource, const ActionSet& actions) :
+ Privilege::Privilege(const ResourcePattern& resource, const ActionSet& actions) :
_resource(resource), _actions(actions) {}
void Privilege::addActions(const ActionSet& actionsToAdd) {
diff --git a/src/mongo/db/auth/privilege.h b/src/mongo/db/auth/privilege.h
index 114e5315da2..d9370705ffa 100644
--- a/src/mongo/db/auth/privilege.h
+++ b/src/mongo/db/auth/privilege.h
@@ -15,25 +15,25 @@
#pragma once
-#include <string>
#include <vector>
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
+#include "mongo/db/auth/resource_pattern.h"
namespace mongo {
/**
- * A representation of the permission to perform a set of actions on a specific resource.
+ * A representation of the permission to perform a set of actions on a resource.
*/
class Privilege {
public:
- Privilege(const std::string& resource, const ActionType& action);
- Privilege(const std::string& resource, const ActionSet& actions);
+ Privilege(const ResourcePattern& resource, const ActionType& action);
+ Privilege(const ResourcePattern& resource, const ActionSet& actions);
~Privilege() {}
- const std::string& getResource() const { return _resource; }
+ const ResourcePattern& getResourcePattern() const { return _resource; }
const ActionSet& getActions() const { return _actions; }
@@ -47,7 +47,7 @@ namespace mongo {
private:
- std::string _resource;
+ ResourcePattern _resource;
ActionSet _actions; // bitmask of actions this privilege grants
};
diff --git a/src/mongo/db/auth/role_graph.cpp b/src/mongo/db/auth/role_graph.cpp
index bbec7731e60..9a76da37223 100644
--- a/src/mongo/db/auth/role_graph.cpp
+++ b/src/mongo/db/auth/role_graph.cpp
@@ -231,7 +231,7 @@ namespace {
for (PrivilegeVector::iterator it = currentPrivileges.begin();
it != currentPrivileges.end(); ++it) {
Privilege& curPrivilege = *it;
- if (curPrivilege.getResource() == privilegeToAdd.getResource()) {
+ if (curPrivilege.getResourcePattern() == privilegeToAdd.getResourcePattern()) {
curPrivilege.addActions(privilegeToAdd.getActions());
return;
}
@@ -300,7 +300,7 @@ namespace {
it != currentPrivileges.end(); ++it) {
Privilege& curPrivilege = *it;
- if (curPrivilege.getResource() == privilegeToRemove.getResource()) {
+ if (curPrivilege.getResourcePattern() == privilegeToRemove.getResourcePattern()) {
ActionSet curActions = curPrivilege.getActions();
if (!curActions.isSupersetOf(privilegeToRemove.getActions())) {
@@ -308,7 +308,8 @@ namespace {
return Status(ErrorCodes::PrivilegeNotFound,
mongoutils::str::stream() << "Role: " << role.getFullName() <<
" does not contain a privilege on " <<
- privilegeToRemove.getResource() << " with actions: " <<
+ privilegeToRemove.getResourcePattern().toString() <<
+ " with actions: " <<
privilegeToRemove.getActions().toString(),
0);
}
@@ -322,7 +323,8 @@ namespace {
}
return Status(ErrorCodes::PrivilegeNotFound,
mongoutils::str::stream() << "Role: " << role.getFullName() << " does not "
- "contain any privileges on " << privilegeToRemove.getResource(),
+ "contain any privileges on " <<
+ privilegeToRemove.getResourcePattern().toString(),
0);
}
diff --git a/src/mongo/db/auth/role_graph_builtin_roles.cpp b/src/mongo/db/auth/role_graph_builtin_roles.cpp
index 4656cdc8e2e..2ca5544c79c 100644
--- a/src/mongo/db/auth/role_graph_builtin_roles.cpp
+++ b/src/mongo/db/auth/role_graph_builtin_roles.cpp
@@ -220,44 +220,49 @@ namespace {
const bool isAdminDB = (roleName.getDB() == ADMIN_DBNAME);
if (roleName.getRole() == BUILTIN_ROLE_READ) {
- return Privilege(roleName.getDB().toString(), readRoleActions);
+ return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()), readRoleActions);
}
if (roleName.getRole() == BUILTIN_ROLE_READ_WRITE) {
- return Privilege(roleName.getDB().toString(), readWriteRoleActions);
+ return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
+ readWriteRoleActions);
}
if (roleName.getRole() == BUILTIN_ROLE_USER_ADMIN) {
- return Privilege(roleName.getDB().toString(), userAdminRoleActions);
+ return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
+ userAdminRoleActions);
}
if (roleName.getRole() == BUILTIN_ROLE_DB_ADMIN) {
- return Privilege(roleName.getDB().toString(), dbAdminRoleActions);
+ return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
+ dbAdminRoleActions);
}
if (roleName.getRole() == RoleGraph::BUILTIN_ROLE_V0_READ) {
- return Privilege(roleName.getDB().toString(), compatibilityReadOnlyActions);
+ return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
+ compatibilityReadOnlyActions);
}
if (roleName.getRole() == RoleGraph::BUILTIN_ROLE_V0_READ_WRITE) {
- return Privilege(roleName.getDB().toString(), compatibilityReadWriteActions);
+ return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
+ compatibilityReadWriteActions);
}
if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_READ_ANY_DB) {
- return Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, readRoleActions);
+ return Privilege(ResourcePattern::forAnyResource(), readRoleActions);
}
if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_READ_WRITE_ANY_DB) {
- return Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, readWriteRoleActions);
+ return Privilege(ResourcePattern::forAnyResource(), readWriteRoleActions);
}
if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_USER_ADMIN_ANY_DB) {
- return Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, userAdminRoleActions);
+ return Privilege(ResourcePattern::forAnyResource(), userAdminRoleActions);
}
if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_DB_ADMIN_ANY_DB) {
- return Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, dbAdminRoleActions);
+ return Privilege(ResourcePattern::forAnyResource(), dbAdminRoleActions);
}
if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_CLUSTER_ADMIN) {
- return Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, clusterAdminRoleActions);
+ return Privilege(ResourcePattern::forAnyResource(), clusterAdminRoleActions);
}
if (isAdminDB && roleName.getRole() == RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ) {
- return Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME,
+ return Privilege(ResourcePattern::forAnyResource(),
compatibilityReadOnlyAdminActions);
}
if (isAdminDB && roleName.getRole() == RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ_WRITE) {
- return Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME,
+ return Privilege(ResourcePattern::forAnyResource(),
compatibilityReadWriteAdminActions);
}
diff --git a/src/mongo/db/auth/role_graph_test.cpp b/src/mongo/db/auth/role_graph_test.cpp
index e616db2d2b0..27afc61b7ac 100644
--- a/src/mongo/db/auth/role_graph_test.cpp
+++ b/src/mongo/db/auth/role_graph_test.cpp
@@ -178,20 +178,20 @@ namespace {
// Test adding a single privilege
ActionSet actions;
actions.addAction(ActionType::find);
- ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege("dbA", actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(ResourcePattern::forDatabaseName("dbA"), actions)));
PrivilegeVector privileges = graph.getDirectPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
ASSERT_EQUALS(actions.toString(), privileges[0].getActions().toString());
// Add a privilege on a different resource
- ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege("dbA.foo", actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(ResourcePattern::forExactNamespace(NamespaceString("dbA.foo")), actions)));
privileges = graph.getDirectPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
ASSERT_EQUALS(actions.toString(), privileges[0].getActions().toString());
- ASSERT_EQUALS("dbA.foo", privileges[1].getResource());
+ ASSERT_EQUALS(ResourcePattern::forExactNamespace(NamespaceString("dbA.foo")), privileges[1].getResourcePattern());
ASSERT_EQUALS(actions.toString(), privileges[1].getActions().toString());
@@ -200,24 +200,24 @@ namespace {
actions.addAction(ActionType::insert);
PrivilegeVector privilegesToAdd;
- privilegesToAdd.push_back(Privilege("dbA", actions));
+ privilegesToAdd.push_back(Privilege(ResourcePattern::forDatabaseName("dbA"), actions));
actions.removeAllActions();
actions.addAction(ActionType::update);
- privilegesToAdd.push_back(Privilege("dbA", actions));
+ privilegesToAdd.push_back(Privilege(ResourcePattern::forDatabaseName("dbA"), actions));
ASSERT_OK(graph.addPrivilegesToRole(roleA, privilegesToAdd));
privileges = graph.getDirectPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
ASSERT_NOT_EQUALS(actions.toString(), privileges[0].getActions().toString());
actions.addAction(ActionType::find);
actions.addAction(ActionType::insert);
ASSERT_EQUALS(actions.toString(), privileges[0].getActions().toString());
actions.removeAction(ActionType::insert);
actions.removeAction(ActionType::update);
- ASSERT_EQUALS("dbA.foo", privileges[1].getResource());
+ ASSERT_EQUALS(ResourcePattern::forExactNamespace(NamespaceString("dbA.foo")), privileges[1].getResourcePattern());
ASSERT_EQUALS(actions.toString(), privileges[1].getActions().toString());
}
@@ -283,15 +283,15 @@ namespace {
ASSERT_OK(graph.createRole(roleB));
ASSERT_OK(graph.createRole(roleC));
- ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege("dbA", actions)));
- ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege("dbB", actions)));
- ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege("dbC", actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(ResourcePattern::forDatabaseName("dbA"), actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(ResourcePattern::forDatabaseName("dbB"), actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege(ResourcePattern::forDatabaseName("dbC"), actions)));
ASSERT_OK(graph.recomputePrivilegeData());
PrivilegeVector privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
// At this point we have all 4 roles set up, each with their own privilege, but no
// roles have been granted to each other.
@@ -301,8 +301,8 @@ namespace {
ASSERT_OK(graph.recomputePrivilegeData());
privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
- ASSERT_EQUALS("dbB", privileges[1].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[1].getResourcePattern());
// Add's roleC's privileges to roleB and make sure roleA gets them as well.
ASSERT_OK(graph.addRoleToRole(roleB, roleC));
@@ -310,13 +310,13 @@ namespace {
ASSERT_OK(graph.recomputePrivilegeData());
privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(3), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
- ASSERT_EQUALS("dbB", privileges[1].getResource());
- ASSERT_EQUALS("dbC", privileges[2].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[2].getResourcePattern());
privileges = graph.getAllPrivileges(roleB);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS("dbB", privileges[0].getResource());
- ASSERT_EQUALS("dbC", privileges[1].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[1].getResourcePattern());
// Add's roleD's privileges to roleC and make sure that roleA and roleB get them as well.
ASSERT_OK(graph.addRoleToRole(roleC, roleD));
@@ -324,22 +324,22 @@ namespace {
ASSERT_OK(graph.recomputePrivilegeData());
privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(4), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
- ASSERT_EQUALS("dbB", privileges[1].getResource());
- ASSERT_EQUALS("dbC", privileges[2].getResource());
- ASSERT_EQUALS("dbD", privileges[3].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[2].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[3].getResourcePattern());
privileges = graph.getAllPrivileges(roleB);
ASSERT_EQUALS(static_cast<size_t>(3), privileges.size());
- ASSERT_EQUALS("dbB", privileges[0].getResource());
- ASSERT_EQUALS("dbC", privileges[1].getResource());
- ASSERT_EQUALS("dbD", privileges[2].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[2].getResourcePattern());
privileges = graph.getAllPrivileges(roleC);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS("dbC", privileges[0].getResource());
- ASSERT_EQUALS("dbD", privileges[1].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[1].getResourcePattern());
privileges = graph.getAllPrivileges(roleD);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS("dbD", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[0].getResourcePattern());
// Remove roleC from roleB, make sure that roleA then loses both roleC's and roleD's
// privileges
@@ -348,32 +348,32 @@ namespace {
ASSERT_OK(graph.recomputePrivilegeData());
privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
- ASSERT_EQUALS("dbB", privileges[1].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[1].getResourcePattern());
privileges = graph.getAllPrivileges(roleB);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS("dbB", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[0].getResourcePattern());
privileges = graph.getAllPrivileges(roleC);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS("dbC", privileges[0].getResource());
- ASSERT_EQUALS("dbD", privileges[1].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[1].getResourcePattern());
privileges = graph.getAllPrivileges(roleD);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS("dbD", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[0].getResourcePattern());
// Make sure direct privileges were untouched
privileges = graph.getDirectPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
privileges = graph.getDirectPrivileges(roleB);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS("dbB", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[0].getResourcePattern());
privileges = graph.getDirectPrivileges(roleC);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS("dbC", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[0].getResourcePattern());
privileges = graph.getDirectPrivileges(roleD);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS("dbD", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[0].getResourcePattern());
}
// Test that if you grant 1 role to another, then remove it and change it's privileges, then
@@ -393,9 +393,9 @@ namespace {
ASSERT_OK(graph.createRole(roleB));
ASSERT_OK(graph.createRole(roleC));
- ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege("db", actionsA)));
- ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege("db", actionsB)));
- ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege("db", actionsC)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(ResourcePattern::forDatabaseName("db"), actionsA)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(ResourcePattern::forDatabaseName("db"), actionsB)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege(ResourcePattern::forDatabaseName("db"), actionsC)));
ASSERT_OK(graph.addRoleToRole(roleA, roleB));
ASSERT_OK(graph.addRoleToRole(roleB, roleC)); // graph: A <- B <- C
@@ -425,7 +425,7 @@ namespace {
ASSERT_OK(graph.removeAllPrivilegesFromRole(roleB));
ActionSet newActionsB;
newActionsB.addAction(ActionType::remove);
- ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege("db", newActionsB)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(ResourcePattern::forDatabaseName("db"), newActionsB)));
// Grant roleB back to roleA, make sure roleA has roleB's new privilege but not its old one.
ASSERT_OK(graph.addRoleToRole(roleA, roleB));
@@ -456,7 +456,7 @@ namespace {
ASSERT_OK(graph.createRole(roleB));
actionsB.removeAllActions();
actionsB.addAction(ActionType::shutdown);
- ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege("db", actionsB)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(ResourcePattern::forDatabaseName("db"), actionsB)));
ASSERT_OK(graph.addRoleToRole(roleA, roleB));
ASSERT_OK(graph.recomputePrivilegeData());
@@ -482,9 +482,9 @@ namespace {
ActionSet actions;
actions.addAction(ActionType::find);
- ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege("dbA", actions)));
- ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege("dbB", actions)));
- ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege("dbC", actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(ResourcePattern::forDatabaseName("dbA"), actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(ResourcePattern::forDatabaseName("dbB"), actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege(ResourcePattern::forDatabaseName("dbC"), actions)));
ASSERT_OK(graph.addRoleToRole(roleA, roleB));
@@ -505,9 +505,9 @@ namespace {
graph.getAllPrivileges(roleA); // should have privileges from roleB *and* role C
PrivilegeVector privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(3), privileges.size());
- ASSERT_EQUALS("dbA", privileges[0].getResource());
- ASSERT_EQUALS("dbB", privileges[1].getResource());
- ASSERT_EQUALS("dbC", privileges[2].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[2].getResourcePattern());
}
// Tests error handling
@@ -518,8 +518,8 @@ namespace {
ActionSet actions;
actions.addAction(ActionType::find);
- Privilege privilege1("db1", actions);
- Privilege privilege2("db2", actions);
+ Privilege privilege1(ResourcePattern::forDatabaseName("db1"), actions);
+ Privilege privilege2(ResourcePattern::forDatabaseName("db2"), actions);
PrivilegeVector privileges;
privileges.push_back(privilege1);
privileges.push_back(privilege2);
@@ -570,7 +570,7 @@ namespace {
ActionSet actions;
actions.addAction(ActionType::insert);
- Privilege privilege("dbA", actions);
+ Privilege privilege(ResourcePattern::forDatabaseName("dbA"), actions);
RoleGraph graph;
@@ -595,14 +595,14 @@ namespace {
ASSERT_EQUALS(1U, privileges.size());
ASSERT(privileges[0].getActions().equals(actions));
ASSERT(!privileges[0].getActions().contains(ActionType::find));
- ASSERT_EQUALS("dbA", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
privileges = graph.getAllPrivileges(userRole);
ASSERT_EQUALS(1U, privileges.size());
ASSERT(privileges[0].getActions().isSupersetOf(actions));
ASSERT(privileges[0].getActions().contains(ActionType::insert));
ASSERT(privileges[0].getActions().contains(ActionType::find));
- ASSERT_EQUALS("dbA", privileges[0].getResource());
+ ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
ASSERT_OK(graph.deleteRole(userRole));
ASSERT(!graph.roleExists(userRole));
diff --git a/src/mongo/db/auth/user.cpp b/src/mongo/db/auth/user.cpp
index adaae0f1313..0dcc7d3ff76 100644
--- a/src/mongo/db/auth/user.cpp
+++ b/src/mongo/db/auth/user.cpp
@@ -19,11 +19,11 @@
#include <vector>
#include "mongo/db/auth/privilege.h"
+#include "mongo/db/auth/resource_pattern.h"
#include "mongo/db/auth/role_name.h"
#include "mongo/db/auth/user_name.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/util/assert_util.h"
-#include "db/auth/role_name.h"
namespace mongo {
@@ -52,8 +52,8 @@ namespace mongo {
return _refCount;
}
- const ActionSet User::getActionsForResource(const std::string& resource) const {
- unordered_map<string, Privilege>::const_iterator it = _privileges.find(resource);
+ const ActionSet User::getActionsForResource(const ResourcePattern& resource) const {
+ unordered_map<ResourcePattern, Privilege>::const_iterator it = _privileges.find(resource);
if (it == _privileges.end()) {
return ActionSet();
}
@@ -102,12 +102,12 @@ namespace mongo {
}
void User::addPrivilege(const Privilege& privilegeToAdd) {
- ResourcePrivilegeMap::iterator it = _privileges.find(privilegeToAdd.getResource());
+ ResourcePrivilegeMap::iterator it = _privileges.find(privilegeToAdd.getResourcePattern());
if (it == _privileges.end()) {
// No privilege exists yet for this resource
- _privileges.insert(std::make_pair(privilegeToAdd.getResource(), privilegeToAdd));
+ _privileges.insert(std::make_pair(privilegeToAdd.getResourcePattern(), privilegeToAdd));
} else {
- dassert(it->first == privilegeToAdd.getResource());
+ dassert(it->first == privilegeToAdd.getResourcePattern());
it->second.addActions(privilegeToAdd.getActions());
}
}
diff --git a/src/mongo/db/auth/user.h b/src/mongo/db/auth/user.h
index 9d5239d0a7b..2d6e895b500 100644
--- a/src/mongo/db/auth/user.h
+++ b/src/mongo/db/auth/user.h
@@ -15,10 +15,12 @@
#pragma once
+#include <string>
#include <vector>
#include "mongo/base/disallow_copying.h"
#include "mongo/db/auth/privilege.h"
+#include "mongo/db/auth/resource_pattern.h"
#include "mongo/db/auth/role_name.h"
#include "mongo/db/auth/user_name.h"
#include "mongo/platform/atomic_word.h"
@@ -78,7 +80,7 @@ namespace mongo {
/**
* Gets the set of actions this user is allowed to perform on the given resource.
*/
- const ActionSet getActionsForResource(const std::string& resource) const;
+ const ActionSet getActionsForResource(const ResourcePattern& resource) const;
/**
* Returns true if this copy of information about this user is still valid. If this returns
@@ -166,7 +168,7 @@ namespace mongo {
UserName _name;
- typedef unordered_map<std::string, Privilege> ResourcePrivilegeMap;
+ typedef unordered_map<ResourcePattern, Privilege> ResourcePrivilegeMap;
// Maps resource name to privilege on that resource
ResourcePrivilegeMap _privileges;
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index 3c82d7a415a..fc6c49e98c6 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -461,7 +461,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::handshake);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
Client& c = cc();
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index edfa10658b1..22d04a5ebad 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -629,27 +629,27 @@ namespace mongo {
}
bool ClientCursor::eraseIfAuthorized(CursorId id) {
- std::string ns;
+ NamespaceString ns;
{
recursive_scoped_lock lock(ccmutex);
ClientCursor* cursor = find_inlock(id);
if (!cursor) {
audit::logKillCursorsAuthzCheck(
&cc(),
- NamespaceString(""),
+ NamespaceString(),
id,
ErrorCodes::CursorNotFound);
return false;
}
- ns = cursor->ns();
+ ns = NamespaceString(cursor->ns());
}
// Can't be in a lock when checking authorization
- const bool isAuthorized = cc().getAuthorizationSession()->checkAuthorization(
+ const bool isAuthorized = cc().getAuthorizationSession()->isAuthorizedForActionsOnNamespace(
ns, ActionType::killCursors);
audit::logKillCursorsAuthzCheck(
&cc(),
- NamespaceString(ns),
+ ns,
id,
isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized);
if (!isAuthorized) {
@@ -665,7 +665,7 @@ namespace mongo {
// Cursor was deleted in another thread since we found it earlier in this function.
return false;
}
- if (cursor->ns() != ns) {
+ if (ns != cursor->ns()) {
warning() << "Cursor namespace changed. Previous ns: " << ns << ", current ns: "
<< cursor->ns() << endl;
return false;
@@ -1009,7 +1009,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::cursorInfo);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result,
bool fromRepl ) {
diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp
index b691f489d4a..4b70b21e082 100644
--- a/src/mongo/db/cloner.cpp
+++ b/src/mongo/db/cloner.cpp
@@ -553,7 +553,7 @@ namespace mongo {
// compatibility, and to internal connections (used in movePrimary).
ActionSet actions;
actions.addAction(ActionType::clone);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
CmdClone() : Command("clone") { }
virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
@@ -598,16 +598,21 @@ namespace mongo {
}
virtual LockType locktype() const { return NONE; }
CmdCloneCollection() : Command("cloneCollection") { }
+
+ 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.
- string collection = cmdObj.getStringField("cloneCollection");
- uassert(16709, "bad 'cloneCollection' value", !collection.empty());
+ NamespaceString ns(parseNs(dbname, cmdObj));
+ uassert(16709, "bad 'cloneCollection' value '" + ns.ns() + "'", ns.isValid());
ActionSet actions;
actions.addAction(ActionType::cloneCollectionTarget);
- out->push_back(Privilege(collection, actions));
+ out->push_back(Privilege(ResourcePattern::forExactNamespace(ns), actions));
}
virtual void help( stringstream &help ) const {
help << "{ cloneCollection: <collection>, from: <host> [,query: <query_filter>] [,copyIndexes:<bool>] }"
@@ -628,7 +633,7 @@ namespace mongo {
return false;
}
}
- string collection = cmdObj.getStringField("cloneCollection");
+ string collection = parseNs(dbname, cmdObj);
if ( collection.empty() ) {
errmsg = "bad 'cloneCollection' value";
return false;
@@ -723,8 +728,10 @@ namespace mongo {
// 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(dbname, actions)); // NOTE: dbname is always admin
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(cmdObj["todb"].str()),
+ actions));
}
virtual void help( stringstream &help ) const {
help << "copy a database from another host to this host\n";
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index 009e1ce3bd6..23288bab1ae 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -84,6 +84,16 @@ namespace mongo {
return dbname + '.' + coll;
}
+ ResourcePattern Command::parseResourcePattern(const std::string& dbname,
+ const BSONObj& cmdObj) const {
+ std::string ns = parseNs(dbname, cmdObj);
+ if (ns.find('.') == std::string::npos) {
+ return ResourcePattern::forDatabaseName(ns);
+ }
+ return ResourcePattern::forExactNamespace(NamespaceString(ns));
+ }
+
+
void Command::htmlHelp(stringstream& ss) const {
string helpStr;
{
@@ -215,7 +225,9 @@ namespace mongo {
const BSONObj& cmdObj) {
std::vector<Privilege> privileges;
this->addRequiredPrivileges(dbname, cmdObj, &privileges);
- return client->getAuthorizationSession()->checkAuthForPrivileges(privileges);
+ if (client->getAuthorizationSession()->isAuthorizedForPrivileges(privileges))
+ return Status::OK();
+ return Status(ErrorCodes::Unauthorized, "unauthorized");
}
void Command::redactForLogging(mutablebson::Document* cmdObj) {}
@@ -304,8 +316,9 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::connPoolSync);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
+
virtual bool run(const string&, mongo::BSONObj&, int, std::string&, mongo::BSONObjBuilder& result, bool) {
pool.flush();
return true;
@@ -326,7 +339,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::connPoolStats);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string&, mongo::BSONObj&, int, std::string&, mongo::BSONObjBuilder& result, bool) {
pool.appendInfo( result );
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index fb114ddc4ed..a897adaca4c 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -17,10 +17,12 @@
#pragma once
+#include <string>
#include <vector>
#include "mongo/base/status.h"
#include "mongo/db/auth/privilege.h"
+#include "mongo/db/auth/resource_pattern.h"
#include "mongo/db/client_basic.h"
#include "mongo/db/jsobj.h"
@@ -51,6 +53,13 @@ namespace mutablebson {
// mongo::String, then 'dbname' is returned unmodified.
virtual string parseNs(const string& dbname, const BSONObj& cmdObj) const;
+ // Utility that returns a ResourcePattern for the namespace returned from
+ // parseNs(dbname, cmdObj). This will be either an exact namespace resource pattern
+ // or a database resource pattern, depending on whether parseNs returns a fully qualifed
+ // collection name or just a database name.
+ ResourcePattern parseResourcePattern(const std::string& dbname,
+ const BSONObj& cmdObj) const;
+
// warning: isAuthorized uses the lockType() return values, and values are being passed
// around as ints so be careful as it isn't really typesafe and will need cleanup later
enum LockType { READ = -1 , NONE = 0 , WRITE = 1 };
diff --git a/src/mongo/db/commands/apply_ops.cpp b/src/mongo/db/commands/apply_ops.cpp
index 48af61d3153..0b207c529f3 100644
--- a/src/mongo/db/commands/apply_ops.cpp
+++ b/src/mongo/db/commands/apply_ops.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/auth/authorization_manager_global.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/privilege.h"
+#include "mongo/db/auth/resource_pattern.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/commands.h"
#include "mongo/db/instance.h"
@@ -54,7 +55,7 @@ namespace mongo {
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
// applyOps can do pretty much anything, so require all privileges.
- out->push_back(Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME,
+ out->push_back(Privilege(ResourcePattern::forAnyResource(),
getGlobalAuthorizationManager()->getAllUserActions()));
}
virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
diff --git a/src/mongo/db/commands/cleanup_orphaned_cmd.cpp b/src/mongo/db/commands/cleanup_orphaned_cmd.cpp
index 05ad3680ffc..ced249d508b 100644
--- a/src/mongo/db/commands/cleanup_orphaned_cmd.cpp
+++ b/src/mongo/db/commands/cleanup_orphaned_cmd.cpp
@@ -159,9 +159,12 @@ namespace mongo {
virtual Status checkAuthForCommand( ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj ) {
- return client->getAuthorizationSession()->checkAuthForPrivilege(
- Privilege( AuthorizationManager::CLUSTER_RESOURCE_NAME,
- ActionType::cleanupOrphaned ) );
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::cleanupOrphaned)) {
+ return Status(ErrorCodes::Unauthorized,
+ "Not authorized for cleanupOrphaned command.");
+ }
+ return Status::OK();
}
virtual LockType locktype() const { return NONE; }
diff --git a/src/mongo/db/commands/cpuprofile.cpp b/src/mongo/db/commands/cpuprofile.cpp
index ff9e2e294d3..4a1605d3929 100644
--- a/src/mongo/db/commands/cpuprofile.cpp
+++ b/src/mongo/db/commands/cpuprofile.cpp
@@ -79,7 +79,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::cpuProfiler);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
// This is an abuse of the global dbmutex. We only really need to
diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp
index 68a6ba306d6..ff319da34f6 100644
--- a/src/mongo/db/commands/distinct.cpp
+++ b/src/mongo/db/commands/distinct.cpp
@@ -55,7 +55,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual void help( stringstream &help ) const {
help << "{ distinct : 'collection name' , key : 'a.b' , query : {} }";
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index 4f9c7a29294..0c18cc1a816 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -61,7 +61,7 @@ namespace mongo {
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- find_and_modify::addPrivilegesRequiredForFindAndModify(dbname, cmdObj, out);
+ find_and_modify::addPrivilegesRequiredForFindAndModify(this, dbname, cmdObj, out);
}
/* this will eventually replace run, once sort is handled */
bool runNoDirectClient( const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
diff --git a/src/mongo/db/commands/find_and_modify.h b/src/mongo/db/commands/find_and_modify.h
index 56c7cda4a77..ab1a6eff18c 100644
--- a/src/mongo/db/commands/find_and_modify.h
+++ b/src/mongo/db/commands/find_and_modify.h
@@ -35,11 +35,15 @@
#include "mongo/db/jsobj.h"
namespace mongo {
+
+ class Command;
+
namespace find_and_modify {
- void addPrivilegesRequiredForFindAndModify(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out);
+ void addPrivilegesRequiredForFindAndModify(Command* commandTemplate,
+ const std::string& dbname,
+ const BSONObj& cmdObj,
+ std::vector<Privilege>* out);
} // namespace find_and_modify
} // namespace mongo
diff --git a/src/mongo/db/commands/find_and_modify_common.cpp b/src/mongo/db/commands/find_and_modify_common.cpp
index 264b625e320..796b6db415a 100644
--- a/src/mongo/db/commands/find_and_modify_common.cpp
+++ b/src/mongo/db/commands/find_and_modify_common.cpp
@@ -36,12 +36,15 @@
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/privilege.h"
+#include "mongo/db/auth/resource_pattern.h"
+#include "mongo/db/commands.h"
#include "mongo/db/jsobj.h"
namespace mongo {
namespace find_and_modify {
- void addPrivilegesRequiredForFindAndModify(const std::string& dbname,
+ void addPrivilegesRequiredForFindAndModify(Command* commandTemplate,
+ const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
bool update = cmdObj["update"].trueValue();
@@ -59,8 +62,10 @@ namespace find_and_modify {
if (remove) {
actions.addAction(ActionType::remove);
}
- std::string ns = dbname + '.' + cmdObj.firstElement().valuestr();
- out->push_back(Privilege(ns, actions));
+ ResourcePattern resource(commandTemplate->parseResourcePattern(dbname, cmdObj));
+ uassert(17137, "Invalid target namespace " + resource.toString(),
+ resource.isExactNamespacePattern());
+ out->push_back(Privilege(resource, actions));
}
} // namespace find_and_modify
diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp
index 2f39551ff33..4da7b007d88 100644
--- a/src/mongo/db/commands/fsync.cpp
+++ b/src/mongo/db/commands/fsync.cpp
@@ -90,7 +90,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::fsync);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
diff --git a/src/mongo/db/commands/group.cpp b/src/mongo/db/commands/group.cpp
index bca945cccc1..0b21a811ec4 100644
--- a/src/mongo/db/commands/group.cpp
+++ b/src/mongo/db/commands/group.cpp
@@ -59,7 +59,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
BSONObj getKey( const BSONObj& obj , const BSONObj& keyPattern , ScriptingFunction func , double avgSize , Scope * s ) {
if ( func ) {
diff --git a/src/mongo/db/commands/index_stats.cpp b/src/mongo/db/commands/index_stats.cpp
index 6a5a6f0cf6a..61224d2579c 100644
--- a/src/mongo/db/commands/index_stats.cpp
+++ b/src/mongo/db/commands/index_stats.cpp
@@ -492,7 +492,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::indexStats);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg,
diff --git a/src/mongo/db/commands/merge_chunks_cmd.cpp b/src/mongo/db/commands/merge_chunks_cmd.cpp
index cb04edcbfa8..bddfd14d0c9 100644
--- a/src/mongo/db/commands/merge_chunks_cmd.cpp
+++ b/src/mongo/db/commands/merge_chunks_cmd.cpp
@@ -55,9 +55,12 @@ namespace mongo {
virtual Status checkAuthForCommand( ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj ) {
- return client->getAuthorizationSession()->checkAuthForPrivilege(
- Privilege( AuthorizationManager::CLUSTER_RESOURCE_NAME,
- ActionType::mergeChunks ) );
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::mergeChunks)) {
+ return Status(ErrorCodes::Unauthorized,
+ "Not authorized to run mergeChunks command.");
+ }
+ return Status::OK();
}
virtual bool slaveOk() const { return false; }
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index f34224a64fc..3a5539348ed 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -1125,7 +1125,7 @@ namespace mongo {
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- addPrivilegesRequiredForMapReduce(dbname, cmdObj, out);
+ addPrivilegesRequiredForMapReduce(this, dbname, cmdObj, out);
}
bool run(const string& dbname , BSONObj& cmd, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
@@ -1365,7 +1365,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::mapReduceShardedFinish);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
ShardedConnectionInfo::addHook();
diff --git a/src/mongo/db/commands/mr.h b/src/mongo/db/commands/mr.h
index d45be3081c8..e00b9d987e6 100644
--- a/src/mongo/db/commands/mr.h
+++ b/src/mongo/db/commands/mr.h
@@ -347,7 +347,8 @@ namespace mongo {
BSONObj fast_emit( const BSONObj& args, void* data );
BSONObj _bailFromJS( const BSONObj& args, void* data );
- void addPrivilegesRequiredForMapReduce(const std::string& dbname,
+ void addPrivilegesRequiredForMapReduce(Command* commandTemplate,
+ const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out);
} // end mr namespace
diff --git a/src/mongo/db/commands/mr_common.cpp b/src/mongo/db/commands/mr_common.cpp
index cdfe4a4cd53..b0d6c9059da 100644
--- a/src/mongo/db/commands/mr_common.cpp
+++ b/src/mongo/db/commands/mr_common.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/privilege.h"
+#include "mongo/db/commands.h"
#include "mongo/db/jsobj.h"
#include "mongo/util/mongoutils/str.h"
@@ -101,17 +102,20 @@ namespace mongo {
return outputOptions;
}
- void addPrivilegesRequiredForMapReduce(const std::string& dbname,
+ void addPrivilegesRequiredForMapReduce(Command* commandTemplate,
+ const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
Config::OutputOptions outputOptions = Config::parseOutputOptions(dbname, cmdObj);
- ActionSet inputActions, outputActions;
- inputActions.addAction(ActionType::find);
- std::string inputNs = dbname + '.' + cmdObj.firstElement().valuestr();
- out->push_back(Privilege(inputNs, inputActions));
+ ResourcePattern inputResource(commandTemplate->parseResourcePattern(dbname, cmdObj));
+ uassert(17142, mongoutils::str::stream() <<
+ "Invalid input resource " << inputResource.toString(),
+ inputResource.isExactNamespacePattern());
+ out->push_back(Privilege(inputResource, ActionType::find));
if (outputOptions.outType != Config::INMEMORY) {
+ ActionSet outputActions;
outputActions.addAction(ActionType::insert);
if (outputOptions.outType == Config::REPLACE) {
outputActions.addAction(ActionType::remove);
@@ -120,9 +124,15 @@ namespace mongo {
outputActions.addAction(ActionType::update);
}
- std::string outputNs = outputOptions.finalNamespace;
+ ResourcePattern outputResource(
+ ResourcePattern::forExactNamespace(
+ NamespaceString(outputOptions.finalNamespace)));
+ uassert(17143, mongoutils::str::stream() << "Invalid target namespace " <<
+ outputResource.ns().ns(),
+ outputResource.ns().isValid());
+
// TODO: check if outputNs exists and add createCollection privilege if not
- out->push_back(Privilege(outputNs, outputActions));
+ out->push_back(Privilege(outputResource, outputActions));
}
}
}
diff --git a/src/mongo/db/commands/parameters.cpp b/src/mongo/db/commands/parameters.cpp
index f4bf6d0e427..8341d758167 100644
--- a/src/mongo/db/commands/parameters.cpp
+++ b/src/mongo/db/commands/parameters.cpp
@@ -60,7 +60,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::getParameter);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual void help( stringstream &help ) const {
help << "get administrative option(s)\nexample:\n";
@@ -114,7 +114,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::setParameter);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual void help( stringstream &help ) const {
help << "set administrative option(s)\n";
diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp
index f7b21859678..aeb7e547ef5 100644
--- a/src/mongo/db/commands/pipeline_command.cpp
+++ b/src/mongo/db/commands/pipeline_command.cpp
@@ -217,7 +217,7 @@ namespace mongo {
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- Pipeline::addRequiredPrivileges(dbname, cmdObj, out);
+ Pipeline::addRequiredPrivileges(this, dbname, cmdObj, out);
}
virtual bool run(const string &db, BSONObj &cmdObj, int options, string &errmsg,
diff --git a/src/mongo/db/commands/rename_collection_common.cpp b/src/mongo/db/commands/rename_collection_common.cpp
index 8000da5cd85..caf395af353 100644
--- a/src/mongo/db/commands/rename_collection_common.cpp
+++ b/src/mongo/db/commands/rename_collection_common.cpp
@@ -44,6 +44,8 @@ namespace rename_collection {
std::vector<Privilege>* out) {
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;
@@ -58,8 +60,8 @@ namespace rename_collection {
targetActions.addAction(ActionType::ensureIndex);
}
- out->push_back(Privilege(sourceNS.ns(), sourceActions));
- out->push_back(Privilege(targetNS.ns(), targetActions));
+ out->push_back(Privilege(ResourcePattern::forExactNamespace(sourceNS), sourceActions));
+ out->push_back(Privilege(ResourcePattern::forExactNamespace(targetNS), targetActions));
}
} // namespace rename_collection
diff --git a/src/mongo/db/commands/server_status.cpp b/src/mongo/db/commands/server_status.cpp
index b4e3c963d09..8ca074d9f5f 100644
--- a/src/mongo/db/commands/server_status.cpp
+++ b/src/mongo/db/commands/server_status.cpp
@@ -87,7 +87,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::serverStatus);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
@@ -119,7 +119,7 @@ namespace mongo {
std::vector<Privilege> requiredPrivileges;
section->addRequiredPrivileges(&requiredPrivileges);
- if (!authSession->checkAuthForPrivileges(requiredPrivileges).isOK())
+ if (!authSession->isAuthorizedForPrivileges(requiredPrivileges))
continue;
bool include = section->includeByDefault();
diff --git a/src/mongo/db/commands/shutdown.cpp b/src/mongo/db/commands/shutdown.cpp
index 8ae35f9f335..07024583845 100644
--- a/src/mongo/db/commands/shutdown.cpp
+++ b/src/mongo/db/commands/shutdown.cpp
@@ -45,7 +45,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::shutdown);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
} // namespace mongo
diff --git a/src/mongo/db/commands/storage_details.cpp b/src/mongo/db/commands/storage_details.cpp
index 71bfd747b8d..6229dc34625 100644
--- a/src/mongo/db/commands/storage_details.cpp
+++ b/src/mongo/db/commands/storage_details.cpp
@@ -315,7 +315,7 @@ namespace {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::storageDetails);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
private:
diff --git a/src/mongo/db/commands/touch.cpp b/src/mongo/db/commands/touch.cpp
index 1817db78dba..a86aa68884f 100644
--- a/src/mongo/db/commands/touch.cpp
+++ b/src/mongo/db/commands/touch.cpp
@@ -68,7 +68,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::touch);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
TouchCmd() : Command("touch") { }
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index 6dcbfd13e1f..49e65374303 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -122,7 +122,7 @@ namespace mongo {
// 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));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname,
@@ -197,7 +197,7 @@ namespace mongo {
// 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));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname,
@@ -276,7 +276,7 @@ namespace mongo {
// 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));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname,
@@ -359,7 +359,7 @@ namespace mongo {
// 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));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname,
@@ -428,7 +428,7 @@ namespace mongo {
// 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));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname,
@@ -517,7 +517,7 @@ namespace mongo {
// 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));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname,
@@ -614,7 +614,7 @@ namespace mongo {
// 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));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname,
@@ -703,7 +703,7 @@ namespace mongo {
// 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));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname,
@@ -800,7 +800,7 @@ namespace mongo {
// 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));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname,
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp
index 8cf224c3380..3f477e7badb 100644
--- a/src/mongo/db/commands/write_commands/write_commands.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands.cpp
@@ -73,7 +73,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(_action);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
// Write commands are counted towards their corresponding opcounters, not command opcounters.
diff --git a/src/mongo/db/compact.cpp b/src/mongo/db/compact.cpp
index 49e111b2f7d..ceeccde8a47 100644
--- a/src/mongo/db/compact.cpp
+++ b/src/mongo/db/compact.cpp
@@ -296,7 +296,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::compact);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual void help( stringstream& help ) const {
help << "compact collection\n"
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 5ae8219c990..556d1047664 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -278,7 +278,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::dropDatabase);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
// this is suboptimal but syncDataAndTruncateJournal is called from dropDatabase, and that
@@ -337,7 +337,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::repairDatabase);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
CmdRepairDatabase() : Command("repairDatabase") {}
@@ -395,7 +395,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::profileEnable);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
CmdProfile() : Command("profile") {}
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
@@ -465,7 +465,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::diagLogging);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
int was = _diaglog.setLevel( cmdObj.firstElement().numberInt() );
@@ -497,7 +497,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::dropCollection);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual void help( stringstream& help ) const { help << "drop a collection\n{drop : <collectionName>}"; }
virtual LockType locktype() const { return WRITE; }
@@ -563,7 +563,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
@@ -626,7 +626,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::createCollection);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
uassert(15888, "must pass name of collection to create", cmdObj.firstElement().valuestrsafe()[0] != '\0');
@@ -658,7 +658,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::dropIndexes);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual std::vector<BSONObj> stopIndexBuilds(const std::string& dbname,
@@ -749,7 +749,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::reIndex);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
CmdReIndex() : Command("reIndex") { }
@@ -828,7 +828,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::listDatabases);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
CmdListDatabases() : Command("listDatabases" , true ) {}
bool run(const string& dbname , BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
@@ -902,7 +902,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::closeAllDatabases);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
CmdCloseAllDatabases() : Command( "closeAllDatabases" ) {}
bool run(const string& dbname , BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
@@ -932,23 +932,23 @@ namespace mongo {
help << " example: { filemd5 : ObjectId(aaaaaaa) , root : \"fs\" }";
}
virtual LockType locktype() const { return READ; }
+
+ virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
+ std::string collectionName = cmdObj.getStringField("root");
+ if (collectionName.empty())
+ collectionName = "fs";
+ collectionName += ".chunks";
+ return NamespaceString(dbname, collectionName).ns();
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- ActionSet actions;
- actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), ActionType::find));
}
+
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
- string ns = dbname;
- ns += ".";
- {
- string root = jsobj.getStringField( "root" );
- if ( root.size() == 0 )
- root = "fs";
- ns += root;
- }
- ns += ".chunks"; // make this an option in jsobj
+ const std::string ns = parseNs(dbname, jsobj);
// Check shard version at startup.
// This will throw before we've done any work if shard version is outdated
@@ -1089,7 +1089,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
Timer timer;
@@ -1231,7 +1231,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::collStats);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
string ns = dbname + "." + jsobj.firstElement().valuestr();
@@ -1310,7 +1310,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::collMod);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
string ns = dbname + "." + jsobj.firstElement().valuestr();
@@ -1417,7 +1417,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::dbStats);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
int scale = 1;
@@ -1507,7 +1507,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet sourceActions;
sourceActions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), sourceActions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), sourceActions));
ActionSet targetActions;
targetActions.addAction(ActionType::insert);
@@ -1515,9 +1515,9 @@ namespace mongo {
std::string collection = cmdObj.getStringField("toCollection");
uassert(16708, "bad 'toCollection' value", !collection.empty());
- std::string targetNs = dbname + "." + collection;
-
- out->push_back(Privilege(targetNs, targetActions));
+ out->push_back(Privilege(ResourcePattern::forExactNamespace(
+ NamespaceString(dbname, collection)),
+ targetActions));
}
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
string from = jsobj.getStringField( "cloneCollectionAsCapped" );
@@ -1591,7 +1591,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::convertToCapped);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
BackgroundOperation::assertNoBgOpInProgForDb(dbname.c_str());
@@ -1706,7 +1706,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::dbHash);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
Timer timer;
diff --git a/src/mongo/db/dbcommands_admin.cpp b/src/mongo/db/dbcommands_admin.cpp
index d06393a102c..9c1c78bafa8 100644
--- a/src/mongo/db/dbcommands_admin.cpp
+++ b/src/mongo/db/dbcommands_admin.cpp
@@ -168,7 +168,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::validate);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
//{ validate: "collectionnamewithoutthedbpart" [, scandata: <bool>] [, full: <bool> } */
diff --git a/src/mongo/db/dbcommands_generic.cpp b/src/mongo/db/dbcommands_generic.cpp
index 10d8d4ef975..c245b465fb7 100644
--- a/src/mongo/db/dbcommands_generic.cpp
+++ b/src/mongo/db/dbcommands_generic.cpp
@@ -199,7 +199,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::hostInfo);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
ProcessInfo p;
@@ -236,7 +236,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::logRotate);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string& ns, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
return rotateLogs();
@@ -346,7 +346,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::getLog);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual void help( stringstream& help ) const {
help << "{ getLog : '*' } OR { getLog : 'global' }";
@@ -397,7 +397,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::getCmdLineOpts);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string&, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
result.append("argv", CmdLine::getArgvArray());
diff --git a/src/mongo/db/dbeval.cpp b/src/mongo/db/dbeval.cpp
index d2935d9679b..b02ded46776 100644
--- a/src/mongo/db/dbeval.cpp
+++ b/src/mongo/db/dbeval.cpp
@@ -136,8 +136,8 @@ namespace mongo {
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- // $eval can do pretty much anything, so require all privileges.
- out->push_back(Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME,
+
+ out->push_back(Privilege(ResourcePattern::forAnyResource(),
getGlobalAuthorizationManager()->getAllUserActions()));
}
CmdEval() : Command("eval", false, "$eval") { }
diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp
index 57790befdf9..eef8ca11b70 100644
--- a/src/mongo/db/exec/stagedebug_cmd.cpp
+++ b/src/mongo/db/exec/stagedebug_cmd.cpp
@@ -97,7 +97,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result,
diff --git a/src/mongo/db/fts/fts_command.cpp b/src/mongo/db/fts/fts_command.cpp
index 0533219fa5d..f7a105b772b 100644
--- a/src/mongo/db/fts/fts_command.cpp
+++ b/src/mongo/db/fts/fts_command.cpp
@@ -55,7 +55,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
diff --git a/src/mongo/db/geo/geonear.cpp b/src/mongo/db/geo/geonear.cpp
index 358f860e3b4..91818276d89 100644
--- a/src/mongo/db/geo/geonear.cpp
+++ b/src/mongo/db/geo/geonear.cpp
@@ -106,7 +106,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
diff --git a/src/mongo/db/geo/haystack.cpp b/src/mongo/db/geo/haystack.cpp
index 4fb180fd8ac..e37bb9abbb5 100644
--- a/src/mongo/db/geo/haystack.cpp
+++ b/src/mongo/db/geo/haystack.cpp
@@ -70,7 +70,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbname, BSONObj& cmdObj, int,
string& errmsg, BSONObjBuilder& result, bool fromRepl) {
diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp
index 3d7d049d565..021a88a2633 100644
--- a/src/mongo/db/instance.cpp
+++ b/src/mongo/db/instance.cpp
@@ -147,8 +147,8 @@ namespace mongo {
QueryMessage q(d);
BSONObjBuilder b;
- const bool isAuthorized = cc().getAuthorizationSession()->checkAuthorization(
- AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::inprog);
+ const bool isAuthorized = cc().getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::inprog);
audit::logInProgAuthzCheck(
&cc(), q.query, isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized);
@@ -206,8 +206,8 @@ namespace mongo {
DbMessage d(m);
QueryMessage q(d);
BSONObj obj;
- const bool isAuthorized = cc().getAuthorizationSession()->checkAuthorization(
- AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::killop);
+ const bool isAuthorized = cc().getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::killop);
audit::logKillOpAuthzCheck(&cc(),
q.query,
isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized);
@@ -234,8 +234,8 @@ namespace mongo {
bool _unlockFsync();
void unlockFsync(const char *ns, Message& m, DbResponse &dbresponse) {
BSONObj obj;
- const bool isAuthorized = cc().getAuthorizationSession()->checkAuthorization(
- AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::unlock);
+ const bool isAuthorized = cc().getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::unlock);
audit::logFsyncUnlockAuthzCheck(
&cc(), isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized);
if (!isAuthorized) {
@@ -269,13 +269,12 @@ namespace mongo {
shared_ptr<AssertionException> ex;
try {
- if (!NamespaceString(d.getns()).isCommand()) {
+ NamespaceString ns(d.getns());
+ if (!ns.isCommand()) {
// Auth checking for Commands happens later.
Client* client = &cc();
- Status status = client->getAuthorizationSession()->checkAuthForQuery(d.getns(),
- q.query);
- audit::logQueryAuthzCheck(
- client, NamespaceString(d.getns()), q.query, status.code());
+ Status status = client->getAuthorizationSession()->checkAuthForQuery(ns, q.query);
+ audit::logQueryAuthzCheck(client, ns, q.query, status.code());
uassertStatusOK(status);
}
dbresponse.exhaustNS = runQuery(m, q, op, *resp);
@@ -588,8 +587,8 @@ namespace mongo {
void receivedUpdate(Message& m, CurOp& op) {
DbMessage d(m);
- const char *ns = d.getns();
- op.debug().ns = ns;
+ NamespaceString ns(d.getns());
+ op.debug().ns = ns.ns();
int flags = d.pullInt();
BSONObj query = d.nextJsObj();
@@ -607,8 +606,7 @@ namespace mongo {
query,
toupdate,
upsert);
- audit::logUpdateAuthzCheck(
- &cc(), NamespaceString(ns), query, toupdate, upsert, multi, status.code());
+ audit::logUpdateAuthzCheck(&cc(), ns, query, toupdate, upsert, multi, status.code());
uassertStatusOK(status);
op.debug().query = query;
@@ -646,11 +644,11 @@ namespace mongo {
PageFaultRetryableSection s;
while ( 1 ) {
try {
- Lock::DBWrite lk(ns);
+ Lock::DBWrite lk(ns.ns());
// void ReplSetImpl::relinquish() uses big write lock so this is thus
// synchronized given our lock above.
- uassert( 17010 , "not master", isMasterNs( ns ) );
+ uassert( 17010 , "not master", isMasterNs( ns.ns().c_str() ) );
// if this ever moves to outside of lock, need to adjust check
// Client::Context::_finishInit
@@ -682,9 +680,9 @@ namespace mongo {
void receivedDelete(Message& m, CurOp& op) {
DbMessage d(m);
- const char *ns = d.getns();
+ NamespaceString ns(d.getns());
- op.debug().ns = ns;
+ op.debug().ns = ns.ns();
int flags = d.pullInt();
bool justOne = flags & RemoveOption_JustOne;
bool broadcast = flags & RemoveOption_Broadcast;
@@ -692,7 +690,7 @@ namespace mongo {
BSONObj pattern = d.nextJsObj();
Status status = cc().getAuthorizationSession()->checkAuthForDelete(ns, pattern);
- audit::logDeleteAuthzCheck(&cc(), NamespaceString(ns), pattern, status.code());
+ audit::logDeleteAuthzCheck(&cc(), ns, pattern, status.code());
uassertStatusOK(status);
op.debug().query = pattern;
@@ -701,10 +699,10 @@ namespace mongo {
PageFaultRetryableSection s;
while ( 1 ) {
try {
- Lock::DBWrite lk(ns);
+ Lock::DBWrite lk(ns.ns());
// writelock is used to synchronize stepdowns w/ writes
- uassert( 10056 , "not master", isMasterNs( ns ) );
+ uassert( 10056 , "not master", isMasterNs( ns.ns().c_str() ) );
// if this ever moves to outside of lock, need to adjust check Client::Context::_finishInit
if ( ! broadcast && handlePossibleShardedMessage( m , 0 ) )
@@ -712,7 +710,7 @@ namespace mongo {
Client::Context ctx(ns);
- long long n = deleteObjects(ns, pattern, justOne, true);
+ long long n = deleteObjects(ns.ns().c_str(), pattern, justOne, true);
lastError.getSafe()->recordDelete( n );
op.debug().ndeleted = n;
break;
@@ -751,8 +749,9 @@ namespace mongo {
const NamespaceString nsString( ns );
uassert( 16258, str::stream() << "Invalid ns [" << ns << "]", nsString.isValid() );
- Status status = cc().getAuthorizationSession()->checkAuthForGetMore(ns, cursorid);
- audit::logGetMoreAuthzCheck(&cc(), NamespaceString(ns), cursorid, status.code());
+ Status status = cc().getAuthorizationSession()->checkAuthForGetMore(
+ nsString, cursorid);
+ audit::logGetMoreAuthzCheck(&cc(), nsString, cursorid, status.code());
uassertStatusOK(status);
if (str::startsWith(ns, "local.oplog.")){
@@ -910,8 +909,9 @@ namespace mongo {
// Check auth for insert (also handles checking if this is an index build and checks
// for the proper privileges in that case).
- Status status = cc().getAuthorizationSession()->checkAuthForInsert(ns, obj);
- audit::logInsertAuthzCheck(&cc(), NamespaceString(ns), obj, status.code());
+ const NamespaceString nsString(ns);
+ Status status = cc().getAuthorizationSession()->checkAuthForInsert(nsString, obj);
+ audit::logInsertAuthzCheck(&cc(), nsString, obj, status.code());
uassertStatusOK(status);
}
diff --git a/src/mongo/db/pipeline/pipeline.cpp b/src/mongo/db/pipeline/pipeline.cpp
index a7e83a66f3a..124ff523c0f 100644
--- a/src/mongo/db/pipeline/pipeline.cpp
+++ b/src/mongo/db/pipeline/pipeline.cpp
@@ -32,12 +32,13 @@
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/privilege.h"
+#include "mongo/db/commands.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/pipeline/accumulator.h"
#include "mongo/db/pipeline/document.h"
#include "mongo/db/pipeline/document_source.h"
-#include "mongo/db/pipeline/expression_context.h"
#include "mongo/db/pipeline/expression.h"
+#include "mongo/db/pipeline/expression_context.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
@@ -311,30 +312,37 @@ namespace mongo {
return pPipeline;
}
- void Pipeline::addRequiredPrivileges(const string& db,
+ void Pipeline::addRequiredPrivileges(Command* commandTemplate,
+ const string& db,
BSONObj cmdObj,
vector<Privilege>* out) {
- ActionSet actions;
- actions.addAction(ActionType::find);
- out->push_back(Privilege(db + '.' + cmdObj.firstElement().str(), actions));
+ ResourcePattern inputResource(commandTemplate->parseResourcePattern(db, cmdObj));
+ uassert(17138,
+ mongoutils::str::stream() << "Invalid input resource, " << inputResource.toString(),
+ inputResource.isExactNamespacePattern());
if (false && cmdObj["allowDiskUsage"].trueValue()) {
// TODO no privilege for this yet.
}
+ out->push_back(Privilege(inputResource, ActionType::find));
+
BSONObj pipeline = cmdObj.getObjectField("pipeline");
BSONForEach(stageElem, pipeline) {
BSONObj stage = stageElem.embeddedObjectUserCheck();
if (str::equals(stage.firstElementFieldName(), "$out")) {
// TODO Figure out how to handle temp collection privileges. For now, using the
// output ns is ok since we only do db-level privilege checks.
- const string outputNs = db + '.' + stage.firstElement().str();
+ NamespaceString outputNs(db, stage.firstElement().str());
+ uassert(17139,
+ mongoutils::str::stream() << "Invalid $out target namespace, " <<
+ outputNs.ns(),
+ outputNs.isValid());
ActionSet actions;
// logically on output ns
actions.addAction(ActionType::remove);
actions.addAction(ActionType::insert);
- actions.addAction(ActionType::indexRead);
// on temp ns due to implementation, but not logically on output ns
actions.addAction(ActionType::createCollection);
@@ -342,7 +350,10 @@ namespace mongo {
actions.addAction(ActionType::dropCollection);
actions.addAction(ActionType::renameCollectionSameDB);
- out->push_back(Privilege(outputNs, actions));
+ out->push_back(Privilege(ResourcePattern::forExactNamespace(outputNs), actions));
+ out->push_back(Privilege(ResourcePattern::forExactNamespace(
+ NamespaceString(db, "system.indexes")),
+ ActionType::find));
}
}
}
diff --git a/src/mongo/db/pipeline/pipeline.h b/src/mongo/db/pipeline/pipeline.h
index ac28c3084ad..c4c638e54d4 100644
--- a/src/mongo/db/pipeline/pipeline.h
+++ b/src/mongo/db/pipeline/pipeline.h
@@ -40,6 +40,7 @@ namespace mongo {
class BSONObj;
class BSONObjBuilder;
class BSONArrayBuilder;
+ class Command;
class DocumentSource;
class DocumentSourceProject;
class Expression;
@@ -66,7 +67,8 @@ namespace mongo {
const intrusive_ptr<ExpressionContext> &pCtx);
/// Helper to implement Command::addRequiredPrivileges
- static void addRequiredPrivileges(const string& inputNs,
+ static void addRequiredPrivileges(Command* commandTemplate,
+ const string& dbname,
BSONObj cmdObj,
vector<Privilege>* out);
diff --git a/src/mongo/db/repl/consensus.cpp b/src/mongo/db/repl/consensus.cpp
index 3974eeb0a7d..e91684da572 100644
--- a/src/mongo/db/repl/consensus.cpp
+++ b/src/mongo/db/repl/consensus.cpp
@@ -46,7 +46,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetFresh);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
private:
@@ -143,7 +143,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetElect);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
private:
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
diff --git a/src/mongo/db/repl/heartbeat.cpp b/src/mongo/db/repl/heartbeat.cpp
index 2a89e15075e..a64b520eb5c 100644
--- a/src/mongo/db/repl/heartbeat.cpp
+++ b/src/mongo/db/repl/heartbeat.cpp
@@ -89,7 +89,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetHeartbeat);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
if( replSetBlind ) {
diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp
index d46645bc44a..e1983cbd096 100644
--- a/src/mongo/db/repl/master_slave.cpp
+++ b/src/mongo/db/repl/master_slave.cpp
@@ -98,7 +98,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::resync);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
void help(stringstream&h) const { h << "resync (from scratch) an out of date replica slave.\nhttp://dochub.mongodb.org/core/masterslave"; }
CmdResync() : Command("resync") { }
diff --git a/src/mongo/db/repl/replset_commands.cpp b/src/mongo/db/repl/replset_commands.cpp
index 6c101ab9f8e..1539436b9a1 100644
--- a/src/mongo/db/repl/replset_commands.cpp
+++ b/src/mongo/db/repl/replset_commands.cpp
@@ -120,7 +120,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetGetRBID);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
if( !check(errmsg, result) )
@@ -154,7 +154,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetGetStatus);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
CmdReplSetGetStatus() : ReplSetCommand("replSetGetStatus", true) { }
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
@@ -181,7 +181,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetReconfig);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
CmdReplSetReconfig() : ReplSetCommand("replSetReconfig"), mutex("rsreconfig") { }
virtual bool run(const string& a, BSONObj& b, int e, string& errmsg, BSONObjBuilder& c, bool d) {
@@ -276,7 +276,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetFreeze);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
CmdReplSetFreeze() : ReplSetCommand("replSetFreeze") { }
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
@@ -306,7 +306,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetStepDown);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
CmdReplSetStepDown() : ReplSetCommand("replSetStepDown") { }
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
@@ -361,7 +361,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetMaintenance);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
CmdReplSetMaintenance() : ReplSetCommand("replSetMaintenance") { }
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
@@ -393,7 +393,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetSyncFrom);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
CmdReplSetSyncFrom() : ReplSetCommand("replSetSyncFrom") { }
virtual bool run(const string&,
@@ -421,7 +421,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetUpdatePosition);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
CmdReplSetUpdatePosition() : ReplSetCommand("replSetUpdatePosition") { }
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg,
diff --git a/src/mongo/db/repl/rs_initiate.cpp b/src/mongo/db/repl/rs_initiate.cpp
index e1fee73b175..43b8bf858cc 100644
--- a/src/mongo/db/repl/rs_initiate.cpp
+++ b/src/mongo/db/repl/rs_initiate.cpp
@@ -174,7 +174,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::replSetInitiate);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
log() << "replSet replSetInitiate admin command received from client" << rsLog;
diff --git a/src/mongo/db/stats/top.cpp b/src/mongo/db/stats/top.cpp
index 61555c69ac4..644a8871839 100644
--- a/src/mongo/db/stats/top.cpp
+++ b/src/mongo/db/stats/top.cpp
@@ -186,7 +186,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::top);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
{
diff --git a/src/mongo/s/commands_admin.cpp b/src/mongo/s/commands_admin.cpp
index b3607dcb9c4..611ea0d12c8 100644
--- a/src/mongo/s/commands_admin.cpp
+++ b/src/mongo/s/commands_admin.cpp
@@ -101,7 +101,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::netstat);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
result.append("configserver", configServer.getPrimary().getConnString() );
@@ -121,7 +121,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::flushRouterConfig);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
grid.flushConfig();
@@ -138,7 +138,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::fsync);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
if ( cmdObj["lock"].trueValue() ) {
@@ -186,7 +186,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::movePrimary);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string dbname = cmdObj.firstElement().valuestrsafe();
@@ -375,7 +375,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::enableSharding);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string dbname = cmdObj.firstElement().valuestrsafe();
@@ -426,7 +426,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::shardCollection);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
const string ns = cmdObj.firstElement().valuestrsafe();
@@ -794,7 +794,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::getShardVersion);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string ns = cmdObj.firstElement().valuestrsafe();
@@ -838,7 +838,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::split);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
if ( ! okForConfigChanges( errmsg ) )
@@ -988,7 +988,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::moveChunk);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
if ( ! okForConfigChanges( errmsg ) )
@@ -1087,7 +1087,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::listShards);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
ScopedDbConnection conn(configServer.getPrimary().getConnString(), 30);
@@ -1118,7 +1118,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::addShard);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
errmsg.clear();
@@ -1186,7 +1186,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::removeShard);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string target = cmdObj.firstElement().valuestrsafe();
@@ -1504,7 +1504,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::listDatabases);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
@@ -1632,7 +1632,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::closeAllDatabases);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& /*result*/, bool /*fromRepl*/) {
@@ -1656,7 +1656,7 @@ namespace mongo {
// TODO: Should this require no auth since it's not supported in mongos anyway?
ActionSet actions;
actions.addAction(ActionType::replSetGetStatus);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
if ( jsobj["forShell"].trueValue() ) {
diff --git a/src/mongo/s/commands_public.cpp b/src/mongo/s/commands_public.cpp
index 9f8054304c7..0ffa5398f04 100644
--- a/src/mongo/s/commands_public.cpp
+++ b/src/mongo/s/commands_public.cpp
@@ -231,7 +231,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::dropIndexes);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
} dropIndexesCmd;
@@ -243,7 +243,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::reIndex);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
} reIndexCmd;
@@ -255,7 +255,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::collMod);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
} collectionModCmd;
@@ -271,7 +271,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::profileEnable);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
} profileCmd;
@@ -284,8 +284,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::validate);
- // TODO: should the resource needed be the collection name instead of the db name?
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual void aggregateResults(const vector<BSONObj>& results, BSONObjBuilder& output) {
for (vector<BSONObj>::const_iterator it(results.begin()), end(results.end()); it!=end; it++){
@@ -319,7 +318,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::repairDatabase);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
} repairDatabaseCmd;
@@ -331,7 +330,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::dbStats);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
virtual void aggregateResults(const vector<BSONObj>& results, BSONObjBuilder& output) {
@@ -379,7 +378,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::createCollection);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbName,
BSONObj& cmdObj,
@@ -400,7 +399,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::dropCollection);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbName , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string collection = cmdObj.firstElement().valuestrsafe();
@@ -448,7 +447,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::dropDatabase);
- out->push_back(Privilege(dbname, actions));
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions));
}
bool run(const string& dbName , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
// disallow dropping the config database from mongos
@@ -552,7 +551,8 @@ namespace mongo {
// read from the source DB.
ActionSet actions;
actions.addAction(ActionType::copyDBTarget);
- out->push_back(Privilege(dbname, actions)); // NOTE: dbname is always admin
+ out->push_back(Privilege(ResourcePattern::forDatabaseName(cmdObj["todb"].str()),
+ actions));
}
bool run(const string& dbName, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string todb = cmdObj.getStringField("todb");
@@ -602,7 +602,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run( const string& dbName,
BSONObj& cmdObj,
@@ -699,7 +699,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::collStats);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbName , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string collection = cmdObj.firstElement().valuestrsafe();
@@ -831,7 +831,7 @@ namespace mongo {
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- find_and_modify::addPrivilegesRequiredForFindAndModify(dbname, cmdObj, out);
+ find_and_modify::addPrivilegesRequiredForFindAndModify(this, dbname, cmdObj, out);
}
bool run(const string& dbName, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string collection = cmdObj.firstElement().valuestrsafe();
@@ -882,7 +882,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbName, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string fullns = cmdObj.firstElement().String();
@@ -947,7 +947,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::convertToCapped);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual string getFullNS( const string& dbName , const BSONObj& cmdObj ) {
@@ -965,7 +965,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual bool passOptions() const { return true; }
virtual string getFullNS( const string& dbName , const BSONObj& cmdObj ) {
@@ -983,7 +983,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::splitVector);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string& dbName , BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool) {
string x = cmdObj.firstElement().valuestrsafe();
@@ -1012,7 +1012,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbName , BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool) {
string collection = cmdObj.firstElement().valuestrsafe();
@@ -1072,24 +1072,23 @@ namespace mongo {
virtual void help( stringstream &help ) const {
help << " example: { filemd5 : ObjectId(aaaaaaa) , root : \"fs\" }";
}
+
+ virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
+ std::string collectionName = cmdObj.getStringField("root");
+ if (collectionName.empty())
+ collectionName = "fs";
+ collectionName += ".chunks";
+ return NamespaceString(dbname, collectionName).ns();
+ }
+
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- ActionSet actions;
- actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), ActionType::find));
}
- bool run(const string& dbName , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
- string fullns = dbName;
- fullns += ".";
- {
- string root = cmdObj.getStringField( "root" );
- if ( root.size() == 0 )
- root = "fs";
- fullns += root;
- }
- fullns += ".chunks";
+ bool run(const string& dbName , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
+ const std::string fullns = parseNs(dbName, cmdObj);
DBConfigPtr conf = grid.getDBConfig( dbName , false );
if ( ! conf || ! conf->isShardingEnabled() || ! conf->isSharded( fullns ) ) {
@@ -1199,7 +1198,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbName , BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool) {
string collection = cmdObj.firstElement().valuestrsafe();
@@ -1305,7 +1304,7 @@ namespace mongo {
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- mr::addPrivilegesRequiredForMapReduce(dbname, cmdObj, out);
+ mr::addPrivilegesRequiredForMapReduce(this, dbname, cmdObj, out);
}
string getTmpName( const string& coll ) {
@@ -1725,7 +1724,7 @@ namespace mongo {
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
// applyOps can do pretty much anything, so require all privileges.
- out->push_back(Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME,
+ out->push_back(Privilege(ResourcePattern::forAnyResource(),
getGlobalAuthorizationManager()->getAllUserActions()));
}
virtual bool run(const string& dbName , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
@@ -1743,7 +1742,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::compact);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
virtual bool run(const string& dbName , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
errmsg = "compact not allowed through mongos";
@@ -1758,7 +1757,7 @@ namespace mongo {
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
// $eval can do pretty much anything, so require all privileges.
- out->push_back(Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME,
+ out->push_back(Privilege(ResourcePattern::forAnyResource(),
getGlobalAuthorizationManager()->getAllUserActions()));
}
virtual bool run(const string& dbName,
@@ -1837,7 +1836,7 @@ namespace mongo {
void PipelineCommand::addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- Pipeline::addRequiredPrivileges(dbname, cmdObj, out);
+ Pipeline::addRequiredPrivileges(this, dbname, cmdObj, out);
}
bool PipelineCommand::run(const string &dbName , BSONObj &cmdObj,
diff --git a/src/mongo/s/cursors.cpp b/src/mongo/s/cursors.cpp
index 178e1e5ac41..f38feba9048 100644
--- a/src/mongo/s/cursors.cpp
+++ b/src/mongo/s/cursors.cpp
@@ -314,8 +314,8 @@ namespace mongo {
MapSharded::iterator i = _cursors.find( id );
if ( i != _cursors.end() ) {
- const bool isAuthorized = authSession->checkAuthorization(
- i->second->getNS(), ActionType::killCursors);
+ const bool isAuthorized = authSession->isAuthorizedForActionsOnNamespace(
+ NamespaceString(i->second->getNS()), ActionType::killCursors);
audit::logKillCursorsAuthzCheck(
client,
NamespaceString(i->second->getNS()),
@@ -334,8 +334,8 @@ namespace mongo {
continue;
}
verify(refsNSIt != _refsNS.end());
- const bool isAuthorized = authSession->checkAuthorization(
- refsNSIt->second, ActionType::killCursors);
+ const bool isAuthorized = authSession->isAuthorizedForActionsOnNamespace(
+ NamespaceString(refsNSIt->second), ActionType::killCursors);
audit::logKillCursorsAuthzCheck(
client,
NamespaceString(refsNSIt->second),
@@ -411,7 +411,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::cursorInfo);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual LockType locktype() const { return NONE; }
bool run(const string&, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp
index e18a805be0d..77274df9d77 100644
--- a/src/mongo/s/d_migrate.cpp
+++ b/src/mongo/s/d_migrate.cpp
@@ -672,7 +672,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::_transferMods);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
return migrateFromStatus.transferMods( errmsg, result );
@@ -688,7 +688,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::_migrateClone);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
return migrateFromStatus.clone( errmsg, result );
@@ -717,7 +717,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::moveChunk);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
@@ -2036,7 +2036,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::_recvChunkStart);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
@@ -2129,7 +2129,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::_recvChunkStatus);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
migrateStatus.status( result );
@@ -2146,7 +2146,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::_recvChunkCommit);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
bool ok = migrateStatus.startCommit();
@@ -2164,7 +2164,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::_recvChunkAbort);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
migrateStatus.abort();
diff --git a/src/mongo/s/d_split.cpp b/src/mongo/s/d_split.cpp
index ae72c795b9b..da7a99eddfc 100644
--- a/src/mongo/s/d_split.cpp
+++ b/src/mongo/s/d_split.cpp
@@ -88,7 +88,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::find);
- out->push_back(Privilege(parseNs(dbname, cmdObj), actions));
+ out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
}
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
@@ -222,7 +222,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::splitVector);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
@@ -507,7 +507,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::splitChunk);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
diff --git a/src/mongo/s/d_state.cpp b/src/mongo/s/d_state.cpp
index d84c00f3b1a..e41af37165e 100644
--- a/src/mongo/s/d_state.cpp
+++ b/src/mongo/s/d_state.cpp
@@ -786,7 +786,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::unsetSharding);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
@@ -812,7 +812,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::setShardVersion);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool checkConfigOrInit( const string& configdb , bool authoritative , string& errmsg , BSONObjBuilder& result , bool locked=false ) const {
@@ -1120,7 +1120,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::getShardVersion);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
@@ -1163,7 +1163,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::shardingState);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
diff --git a/src/mongo/s/d_writeback.cpp b/src/mongo/s/d_writeback.cpp
index f8b7db8c60b..33da7dc3d55 100644
--- a/src/mongo/s/d_writeback.cpp
+++ b/src/mongo/s/d_writeback.cpp
@@ -168,7 +168,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::writebacklisten);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
@@ -220,7 +220,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::writeBacksQueued);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
WriteBacksQueuedCommand() : Command( "writeBacksQueued" ) {}
diff --git a/src/mongo/s/merge_chunks_cmd.cpp b/src/mongo/s/merge_chunks_cmd.cpp
index 742bad635dc..bb76b561843 100644
--- a/src/mongo/s/merge_chunks_cmd.cpp
+++ b/src/mongo/s/merge_chunks_cmd.cpp
@@ -55,9 +55,11 @@ namespace mongo {
virtual Status checkAuthForCommand( ClientBasic* client,
const std::string& dbname,
const BSONObj& cmdObj ) {
- return client->getAuthorizationSession()->checkAuthForPrivilege(
- Privilege( AuthorizationManager::CLUSTER_RESOURCE_NAME,
- ActionType::mergeChunks ) );
+ if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::mergeChunks)) {
+ return Status(ErrorCodes::Unauthorized, "Not authorized for mergeChunks.");
+ }
+ return Status::OK();
}
virtual bool slaveOk() const { return false; }
diff --git a/src/mongo/s/shard.cpp b/src/mongo/s/shard.cpp
index 00c8c3405e4..371acfe8af4 100644
--- a/src/mongo/s/shard.cpp
+++ b/src/mongo/s/shard.cpp
@@ -288,7 +288,7 @@ namespace mongo {
std::vector<Privilege>* out) {
ActionSet actions;
actions.addAction(ActionType::getShardMap);
- out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions));
+ out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
virtual bool run(const string&, mongo::BSONObj&, int, std::string& errmsg , mongo::BSONObjBuilder& result, bool) {
return staticShardInfo.getShardMap( result , errmsg );
diff --git a/src/mongo/s/shardconnection.cpp b/src/mongo/s/shardconnection.cpp
index 07e1c465f32..f6f057f6ab8 100644
--- a/src/mongo/s/shardconnection.cpp
+++ b/src/mongo/s/shardconnection.cpp
@@ -99,7 +99,7 @@ namespace mongo {
{
ActionSet actions;
actions.addAction( ActionType::connPoolStats );
- out->push_back( Privilege( AuthorizationManager::SERVER_RESOURCE_NAME, actions ) );
+ out->push_back( Privilege( ResourcePattern::forClusterResource(), actions ) );
}
virtual bool run ( const string&, mongo::BSONObj&, int, std::string&, mongo::BSONObjBuilder& result, bool ) {
diff --git a/src/mongo/s/strategy_shard.cpp b/src/mongo/s/strategy_shard.cpp
index 4cbfe290373..de5899cbb2b 100644
--- a/src/mongo/s/strategy_shard.cpp
+++ b/src/mongo/s/strategy_shard.cpp
@@ -67,10 +67,11 @@ namespace mongo {
QueryMessage q( r.d() );
+ NamespaceString ns(q.ns);
ClientBasic* client = ClientBasic::getCurrent();
AuthorizationSession* authSession = client->getAuthorizationSession();
- Status status = authSession->checkAuthForQuery(q.ns, q.query);
- audit::logQueryAuthzCheck(client, NamespaceString(q.ns), q.query, status.code());
+ Status status = authSession->checkAuthForQuery(ns, q.query);
+ audit::logQueryAuthzCheck(client, ns, q.query, status.code());
uassertStatusOK(status);
LOG(3) << "shard query: " << q.ns << " " << q.query << endl;
@@ -215,9 +216,10 @@ namespace mongo {
NULL == cursorCache.get( id ).get() || host.empty() );
ClientBasic* client = ClientBasic::getCurrent();
+ NamespaceString nsString(ns);
AuthorizationSession* authSession = client->getAuthorizationSession();
- Status status = authSession->checkAuthForGetMore( ns, id );
- audit::logGetMoreAuthzCheck( client, NamespaceString(ns), id, status.code() );
+ Status status = authSession->checkAuthForGetMore( nsString, id );
+ audit::logGetMoreAuthzCheck( client, nsString, id, status.code() );
uassertStatusOK(status);
if( !host.empty() ){
@@ -577,12 +579,13 @@ namespace mongo {
// We should always have a shard if we have any inserts
verify(group.inserts.size() == 0 || group.shard.get());
+ NamespaceString nsString(ns);
for (vector<BSONObj>::iterator it = group.inserts.begin();
it != group.inserts.end(); ++it) {
ClientBasic* client = ClientBasic::getCurrent();
AuthorizationSession* authSession = client->getAuthorizationSession();
- Status status = authSession->checkAuthForInsert(ns, *it);
- audit::logInsertAuthzCheck(client, NamespaceString(ns), *it, status.code());
+ Status status = authSession->checkAuthForInsert(nsString, *it);
+ audit::logInsertAuthzCheck(client, nsString, *it, status.code());
uassertStatusOK(status);
}
@@ -1033,12 +1036,13 @@ namespace mongo {
const BSONObj toUpdate = d.nextJsObj();
+ NamespaceString nsString(ns);
ClientBasic* client = ClientBasic::getCurrent();
AuthorizationSession* authzSession = client->getAuthorizationSession();
- Status status = authzSession->checkAuthForUpdate(ns, query, toUpdate, upsert);
+ Status status = authzSession->checkAuthForUpdate(nsString, query, toUpdate, upsert);
audit::logUpdateAuthzCheck(
client,
- NamespaceString(ns),
+ nsString,
query,
toUpdate,
upsert,
@@ -1202,10 +1206,11 @@ namespace mongo {
const BSONObj query = d.nextJsObj();
+ NamespaceString nsString(ns);
ClientBasic* client = ClientBasic::getCurrent();
AuthorizationSession* authSession = client->getAuthorizationSession();
- Status status = authSession->checkAuthForDelete(ns, query);
- audit::logDeleteAuthzCheck(client, NamespaceString(ns), query, status.code());
+ Status status = authSession->checkAuthForDelete(nsString, query);
+ audit::logDeleteAuthzCheck(client, nsString, query, status.code());
uassertStatusOK(status);
if( d.reservedField() & Reserved_FromWriteback ){
@@ -1275,7 +1280,7 @@ namespace mongo {
while (d.moreJSObjs()) {
BSONObj toInsert = d.nextJsObj();
Status status = authSession->checkAuthForInsert(
- ns,
+ nsAsNs,
toInsert);
audit::logInsertAuthzCheck(
client,
diff --git a/src/mongo/s/strategy_single.cpp b/src/mongo/s/strategy_single.cpp
index 89e4a97f3f9..08f95856a01 100644
--- a/src/mongo/s/strategy_single.cpp
+++ b/src/mongo/s/strategy_single.cpp
@@ -145,8 +145,8 @@ namespace mongo {
ClientBasic* client = ClientBasic::getCurrent();
AuthorizationSession* authSession = client->getAuthorizationSession();
if ( strcmp( ns , "inprog" ) == 0 ) {
- const bool isAuthorized = authSession->checkAuthorization(
- AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::inprog);
+ const bool isAuthorized = authSession->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::inprog);
audit::logInProgAuthzCheck(
client, q.query, isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized);
uassert(ErrorCodes::Unauthorized, "not authorized to run inprog", isAuthorized);
@@ -188,8 +188,8 @@ namespace mongo {
arr.done();
}
else if ( strcmp( ns , "killop" ) == 0 ) {
- const bool isAuthorized = authSession->checkAuthorization(
- AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::killop);
+ const bool isAuthorized = authSession->isAuthorizedForActionsOnResource(
+ ResourcePattern::forClusterResource(), ActionType::killop);
audit::logKillOpAuthzCheck(
client,
q.query,