summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuildscripts/smoke.py5
-rw-r--r--jstests/auth/auth1.js3
-rw-r--r--jstests/auth/basic_role_auth.js9
-rw-r--r--jstests/auth/renameSystemCollections.js69
-rw-r--r--src/mongo/db/auth/SConscript1
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp9
-rw-r--r--src/mongo/db/auth/authorization_manager.h5
-rw-r--r--src/mongo/db/auth/authorization_manager_test.cpp4
-rw-r--r--src/mongo/db/auth/authorization_session.cpp96
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp6
-rw-r--r--src/mongo/db/auth/privilege.cpp12
-rw-r--r--src/mongo/db/auth/privilege.h14
-rw-r--r--src/mongo/db/auth/resource_pattern.cpp37
-rw-r--r--src/mongo/db/auth/resource_pattern.h61
-rw-r--r--src/mongo/db/auth/resource_pattern_test.cpp342
-rw-r--r--src/mongo/db/auth/role_graph.cpp22
-rw-r--r--src/mongo/db/auth/role_graph.h5
-rw-r--r--src/mongo/db/auth/role_graph_builtin_roles.cpp557
-rw-r--r--src/mongo/db/auth/role_graph_test.cpp173
-rw-r--r--src/mongo/db/auth/user_document_parser_test.cpp8
-rw-r--r--src/mongo/db/commands/apply_ops.cpp3
-rw-r--r--src/mongo/db/dbeval.cpp3
-rw-r--r--src/mongo/s/commands_public.cpp6
-rw-r--r--src/mongo/shell/utils.js9
24 files changed, 622 insertions, 837 deletions
diff --git a/buildscripts/smoke.py b/buildscripts/smoke.py
index 65ceee5212e..bdfec533473 100755
--- a/buildscripts/smoke.py
+++ b/buildscripts/smoke.py
@@ -169,10 +169,7 @@ class mongod(object):
try:
Connection( "localhost" , int(port) ).admin.command("createUser", "admin",
pwd="password",
- roles=["readWriteAnyDatabase",
- "dbAdminAnyDatabase",
- "userAdminAnyDatabase",
- "clusterAdmin"])
+ roles=["__system"])
except OperationFailure, e:
if e.message == 'need to login':
pass # SERVER-4225
diff --git a/jstests/auth/auth1.js b/jstests/auth/auth1.js
index 0d1610a83d5..d77f1544734 100644
--- a/jstests/auth/auth1.js
+++ b/jstests/auth/auth1.js
@@ -18,7 +18,7 @@ tRO = dbRO[ baseName ];
db.removeAllUsers();
-db.getSisterDB( "admin" ).addUser( "super", "super", jsTest.adminUserRoles );
+db.getSisterDB( "admin" ).addUser( "super", "super", ["__system"] );
db.getSisterDB("admin").auth("super", "super");
db.addUser( "eliot" , "eliot", jsTest.basicUserRoles );
db.addUser( "guest" , "guest", jsTest.readOnlyUserRoles );
@@ -87,5 +87,4 @@ assert.eq( 1000, db.eval( function() { return db[ "jstests_auth_auth1" ].count()
db.eval( function() { db[ "jstests_auth_auth1" ].save( {i:1000} ) } );
assert.eq( 1001, db.eval( function() { return db[ "jstests_auth_auth1" ].count(); } ) , "D2" );
-
print("SUCCESS auth1.js");
diff --git a/jstests/auth/basic_role_auth.js b/jstests/auth/basic_role_auth.js
index ddb1229ec16..60ad58bb9fc 100644
--- a/jstests/auth/basic_role_auth.js
+++ b/jstests/auth/basic_role_auth.js
@@ -15,8 +15,7 @@ var AUTH_INFO = {
admin: {
root: {
pwd: 'root',
- roles: [ 'readWriteAnyDatabase', 'userAdminAnyDatabase',
- 'dbAdminAnyDatabase', 'clusterAdmin' ]
+ roles: [ 'root' ]
},
cluster: {
pwd: 'cluster',
@@ -187,7 +186,10 @@ var testOps = function(db, allowedActions) {
}, db);
checkErr(allowedActions.hasOwnProperty('user_r'), function() {
- db.system.users.findOne();
+ var result = db.runCommand({usersInfo: /.*/});
+ if (!result.ok) {
+ throw new Error(tojson(result));
+ }
});
checkErr(allowedActions.hasOwnProperty('user_w'), function() {
@@ -524,6 +526,7 @@ var runTests = function(conn) {
testFunc.test(newConn);
} catch (x) {
failures.push(testFunc.name);
+ jsTestLog(x);
}
});
diff --git a/jstests/auth/renameSystemCollections.js b/jstests/auth/renameSystemCollections.js
index 4d3e67035b1..e682635c1e3 100644
--- a/jstests/auth/renameSystemCollections.js
+++ b/jstests/auth/renameSystemCollections.js
@@ -7,17 +7,21 @@ var testDB2 = conn.getDB("testdb2");
var CodeUnauthorized = 13;
-adminDB.addUser({user:'userAdmin',
+var backdoorUserDoc = { name: 'backdoor', source: 'admin', pwd: 'hashed', roles: ['root'] }
+
+adminDB.addUser({name:'userAdmin',
pwd:'password',
roles:['userAdminAnyDatabase']});
adminDB.auth('userAdmin', 'password');
-adminDB.addUser({user:'readWriteAdmin',
+adminDB.addUser({name:'readWriteAdmin',
pwd:'password',
roles:['readWriteAnyDatabase']});
-adminDB.addUser({user:'readWriteAndUserAdmin',
+adminDB.addUser({name:'readWriteAndUserAdmin',
pwd:'password',
roles:['readWriteAnyDatabase', 'userAdminAnyDatabase']});
+adminDB.addUser({name: 'root', pwd: 'password', roles: ['root']});
+adminDB.addUser({name: 'rootier', pwd: 'password', roles: ['__system']});
adminDB.logout();
@@ -36,9 +40,7 @@ assert.eq(0, adminDB.users.count());
jsTestLog("Test that a readWrite user can't use renameCollection to override system.users");
-adminDB.users.insert({user:'backdoor',
- pwd:'hashedpassword',
- roles:'userAdmin'});
+adminDB.users.insert(backdoorUserDoc);
res = adminDB.users.renameCollection("system.users", true);
assert.eq(0, res.ok);
assert.eq(CodeUnauthorized, res.code);
@@ -50,21 +52,58 @@ adminDB.auth('userAdmin', 'password');
var res = adminDB.system.users.renameCollection("users");
assert.eq(0, res.ok);
assert.eq(CodeUnauthorized, res.code);
-assert.eq(3, adminDB.system.users.count());
+assert.eq(5, adminDB.system.users.count());
adminDB.auth('readWriteAndUserAdmin', 'password');
assert.eq(0, adminDB.users.count());
-jsTestLog("Test that with userAdmin AND dbAdmin you CAN rename to/from system.users");
+jsTestLog("Test that even with userAdmin AND dbAdmin you CANNOT rename to/from system.users");
var res = adminDB.system.users.renameCollection("users");
-assert.eq(1, res.ok);
-assert.eq(3, adminDB.users.count());
+assert.eq(0, res.ok);
+assert.eq(CodeUnauthorized, res.code);
+assert.eq(5, adminDB.system.users.count());
adminDB.users.drop();
-adminDB.users.insert({user:'newUser',
- pwd:'hashedPassword',
- roles:['readWrite']});
+adminDB.users.insert(backdoorUserDoc);
var res = adminDB.users.renameCollection("system.users");
+assert.eq(0, res.ok);
+assert.eq(CodeUnauthorized, res.code);
+
+assert.eq(null, adminDB.system.users.findOne({name: backdoorUserDoc.name}));
+assert.neq(null, adminDB.system.users.findOne({name:'userAdmin'}));
+
+adminDB.auth('root', 'password');
+adminDB.users.drop();
+adminDB.users.insert(backdoorUserDoc);
+
+jsTestLog("Test that with root you CANNOT rename to/from system.users");
+var res = adminDB.system.users.renameCollection("users");
+assert.eq(0, res.ok);
+assert.eq(CodeUnauthorized, res.code);
+assert.eq(5, adminDB.system.users.count());
+
+adminDB.users.drop();
+adminDB.users.insert(backdoorUserDoc);
+var res = adminDB.users.renameCollection("system.users");
+assert.eq(0, res.ok);
+assert.eq(CodeUnauthorized, res.code);
+
+assert.eq(null, adminDB.system.users.findOne({name: backdoorUserDoc.name}));
+assert.neq(null, adminDB.system.users.findOne({name:'userAdmin'}));
+
+adminDB.auth('rootier', 'password');
+
+jsTestLog("Test that with __system you CAN rename to/from system.users");
+var res = adminDB.system.users.renameCollection("users", true);
+assert.eq(1, res.ok, tojson(res));
+assert.eq(0, adminDB.system.users.count());
+assert.eq(5, adminDB.users.count());
+
+adminDB.users.drop();
+adminDB.users.insert(backdoorUserDoc);
+var res = adminDB.users.renameCollection("system.users", true);
assert.eq(1, res.ok);
-assert.neq(null, adminDB.system.users.findOne({user:'newUser'}));
-assert.eq(null, adminDB.system.users.findOne({user:'userAdmin'}));
+assert.neq(null, adminDB.system.users.findOne({name: backdoorUserDoc.name}));
+assert.eq(null, adminDB.system.users.findOne({name:'userAdmin'}));
+
+
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index 20486ff8b64..0da1f578d4f 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -69,7 +69,6 @@ env.CppUnitTest('authorization_manager_test', 'authorization_manager_test.cpp',
LIBDEPS=['authcore', 'authmocks'])
env.CppUnitTest('authorization_session_test', 'authorization_session_test.cpp',
LIBDEPS=['authcore', 'authmocks'])
-env.CppUnitTest('resource_pattern_test', 'resource_pattern_test.cpp', LIBDEPS=['authcore'])
env.CppUnitTest('user_management_commands_parser_test', 'user_management_commands_parser_test.cpp',
LIBDEPS=['usercommandsparser', 'authmocks'],
NO_CRUTCH=True)
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp
index 4b4cd1cffc7..835403cd20e 100644
--- a/src/mongo/db/auth/authorization_manager.cpp
+++ b/src/mongo/db/auth/authorization_manager.cpp
@@ -61,8 +61,9 @@ namespace mongo {
user->incrementRefCount(); // Pin this user so the ref count never drops below 1.
ActionSet allActions;
allActions.addAllActions();
- user->addPrivilege(Privilege(ResourcePattern::forAnyResource(), allActions));
-
+ PrivilegeVector privileges;
+ RoleGraph::generateUniversalPrivileges(&privileges);
+ user->addPrivileges(privileges);
internalSecurity.user = user;
return Status::OK();
@@ -191,10 +192,6 @@ namespace mongo {
return _externalState->query(collectionName, query, resultProcessor);
}
- ActionSet AuthorizationManager::getAllUserActions() {
- return RoleGraph::getAllUserActions();
- }
-
bool AuthorizationManager::roleExists(const RoleName& role) {
boost::lock_guard<boost::mutex> lk(_lock);
return _roleGraph.roleExists(role);
diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h
index 7e3723a1875..9515b97fcb5 100644
--- a/src/mongo/db/auth/authorization_manager.h
+++ b/src/mongo/db/auth/authorization_manager.h
@@ -37,6 +37,7 @@
#include "mongo/base/status.h"
#include "mongo/db/auth/action_set.h"
#include "mongo/db/auth/authz_manager_external_state.h"
+#include "mongo/db/auth/resource_pattern.h"
#include "mongo/db/auth/role_graph.h"
#include "mongo/db/auth/user.h"
#include "mongo/db/auth/user_name.h"
@@ -176,10 +177,6 @@ namespace mongo {
// that an old-style user with those attributes should be given.
ActionSet getActionsForOldStyleUser(const std::string& dbname, bool readOnly) const;
- // Returns an ActionSet of all actions that can be be granted to users. This does not
- // include internal-only actions.
- ActionSet getAllUserActions();
-
/**
* Returns the User object for the given userName in the out parameter "acquiredUser".
* If the user cache already has a user object for this user, it increments the refcount
diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp
index 71f1272241d..dc8497ac1e3 100644
--- a/src/mongo/db/auth/authorization_manager_test.cpp
+++ b/src/mongo/db/auth/authorization_manager_test.cpp
@@ -73,7 +73,7 @@ namespace {
const User::RoleDataMap& roles = v0RW->getRoles();
ASSERT_EQUALS(1U, roles.size());
User::RoleData role = roles.begin()->second;
- ASSERT_EQUALS(RoleName("oldReadWrite", "test"), role.name);
+ ASSERT_EQUALS(RoleName("dbOwner", "test"), role.name);
ASSERT(role.hasRole);
ASSERT(!role.canDelegate);
// Make sure user's refCount is 0 at the end of the test to avoid an assertion failure
@@ -87,7 +87,7 @@ namespace {
const User::RoleDataMap& adminRoles = v0AdminRO->getRoles();
ASSERT_EQUALS(1U, adminRoles.size());
role = adminRoles.begin()->second;
- ASSERT_EQUALS(RoleName("oldAdminRead", "admin"), role.name);
+ ASSERT_EQUALS(RoleName("readAnyDatabase", "admin"), role.name);
ASSERT(role.hasRole);
ASSERT(!role.canDelegate);
// Make sure user's refCount is 0 at the end of the test to avoid an assertion failure
diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp
index 0c446fdd6f1..ce547214e1d 100644
--- a/src/mongo/db/auth/authorization_session.cpp
+++ b/src/mongo/db/auth/authorization_session.cpp
@@ -238,60 +238,62 @@ namespace {
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)) {
- // End users can't modify system.users directly, only the system can.
- newActions.addAction(ActionType::userAdminV1);
- } else {
- newActions.addAction(ActionType::userAdmin);
+ static const int resourceSearchListCapacity = 5;
+ /**
+ * Builds from "target" an exhaustive list of all ResourcePatterns that match "target".
+ *
+ * Stores the resulting list into resourceSearchList, and returns the length.
+ *
+ * The seach lists are as follows, depending on the type of "target":
+ *
+ * target is ResourcePattern::forAnyResource():
+ * searchList = { ResourcePattern::forAnyResource(), ResourcePattern::forAnyResource() }
+ * target is the ResourcePattern::forClusterResource():
+ * searchList = { ResourcePattern::forAnyResource(), ResourcePattern::forClusterResource() }
+ * target is a database, db:
+ * searchList = { ResourcePattern::forAnyResource(),
+ * ResourcePattern::forAnyNormalResource(),
+ * db }
+ * target is a non-system collection, db.coll:
+ * searchList = { ResourcePattern::forAnyResource(),
+ * ResourcePattern::forAnyNormalResource(),
+ * db,
+ * coll,
+ * db.coll }
+ * target is a system collection, db.system.coll:
+ * searchList = { ResourcePattern::forAnyResource(),
+ * system.coll,
+ * db.system.coll }
+ */
+ static int buildResourceSearchList(
+ const ResourcePattern& target,
+ ResourcePattern resourceSearchList[resourceSearchListCapacity]) {
+
+ int size = 0;
+ resourceSearchList[size++] = ResourcePattern::forAnyResource();
+ if (target.isExactNamespacePattern()) {
+ if (!target.ns().isSystem()) {
+ resourceSearchList[size++] = ResourcePattern::forAnyNormalResource();
+ resourceSearchList[size++] = ResourcePattern::forDatabaseName(target.ns().db());
}
- newActions.removeAction(ActionType::find);
- newActions.removeAction(ActionType::insert);
- newActions.removeAction(ActionType::update);
- newActions.removeAction(ActionType::remove);
- } else if (anyProfileCollectionPattern.matchesResourcePattern(target)) {
- newActions.removeAction(ActionType::find);
- newActions.addAction(ActionType::profileRead);
- } else if (anyIndexesCollectionPattern.matchesResourcePattern(target)
- && newActions.contains(ActionType::find)) {
- newActions.removeAction(ActionType::find);
- newActions.addAction(ActionType::indexRead);
+ resourceSearchList[size++] = ResourcePattern::forCollectionName(target.ns().coll());
}
-
- return Privilege(privilege.getResourcePattern(), newActions);
+ else if (target.isDatabasePattern()) {
+ resourceSearchList[size++] = ResourcePattern::forAnyNormalResource();
+ }
+ resourceSearchList[size++] = target;
+ dassert(size <= resourceSearchListCapacity);
+ return size;
}
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.
- ResourcePattern resourceSearchList[3];
- resourceSearchList[0] = ResourcePattern::forAnyResource();
- resourceSearchList[1] = modifiedPrivilege.getResourcePattern();
- if (modifiedPrivilege.getResourcePattern().isExactNamespacePattern()) {
- resourceSearchList[2] =
- ResourcePattern::forDatabaseName(modifiedPrivilege.getResourcePattern().ns().db());
- }
+ const ResourcePattern& target(privilege.getResourcePattern());
+ ResourcePattern resourceSearchList[resourceSearchListCapacity];
+ const int resourceSearchListLength = buildResourceSearchList(target, resourceSearchList);
- ActionSet unmetRequirements = modifiedPrivilege.getActions();
+ ActionSet unmetRequirements = privilege.getActions();
UserSet::iterator it = _authenticatedUsers.begin();
while (it != _authenticatedUsers.end()) {
User* user = *it;
@@ -329,7 +331,7 @@ namespace {
}
}
- for (int i = 0; i < static_cast<int>(boost::size(resourceSearchList)); ++i) {
+ for (int i = 0; i < resourceSearchListLength; ++i) {
ActionSet userActions = user->getActionsForResource(resourceSearchList[i]);
unmetRequirements.removeAllActionsFromSet(userActions);
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp
index 9360d36e788..bf71c8b68ee 100644
--- a/src/mongo/db/auth/authorization_session_test.cpp
+++ b/src/mongo/db/auth/authorization_session_test.cpp
@@ -153,7 +153,9 @@ namespace {
ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("admin", "admin")));
ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
- ResourcePattern::forAnyResource(), ActionType::insert));
+ ResourcePattern::forExactNamespace(
+ NamespaceString("anydb.somecollection")),
+ ActionType::insert));
ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
otherDBResource, ActionType::insert));
ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
@@ -289,7 +291,7 @@ namespace {
ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("useradmin", "test")));
ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
testUsersCollResource, ActionType::insert));
- ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource(
+ ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
testUsersCollResource, ActionType::find));
ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource(
otherUsersCollResource, ActionType::insert));
diff --git a/src/mongo/db/auth/privilege.cpp b/src/mongo/db/auth/privilege.cpp
index 89261791f98..a1d0dab7bfe 100644
--- a/src/mongo/db/auth/privilege.cpp
+++ b/src/mongo/db/auth/privilege.cpp
@@ -20,6 +20,18 @@
namespace mongo {
+ void Privilege::addPrivilegeToPrivilegeVector(PrivilegeVector* privileges,
+ const Privilege& privilegeToAdd) {
+ for (PrivilegeVector::iterator it = privileges->begin(); it != privileges->end(); ++it) {
+ if (it->getResourcePattern() == privilegeToAdd.getResourcePattern()) {
+ it->addActions(privilegeToAdd.getActions());
+ return;
+ }
+ }
+ // No privilege exists yet for this resource
+ privileges->push_back(privilegeToAdd);
+ }
+
Privilege::Privilege(const ResourcePattern& resource, const ActionType& action) :
_resource(resource) {
diff --git a/src/mongo/db/auth/privilege.h b/src/mongo/db/auth/privilege.h
index dda2aca6c09..710e18e6be8 100644
--- a/src/mongo/db/auth/privilege.h
+++ b/src/mongo/db/auth/privilege.h
@@ -24,11 +24,23 @@
namespace mongo {
+ class Privilege;
+ typedef std::vector<Privilege> PrivilegeVector;
+
/**
* A representation of the permission to perform a set of actions on a resource.
*/
class Privilege {
public:
+ /**
+ * Adds "privilegeToAdd" to "privileges", de-duping "privilegeToAdd" if the vector already
+ * contains a privilege on the same resource.
+ *
+ * This method is the preferred way to add privileges to privilege vectors.
+ */
+ static void addPrivilegeToPrivilegeVector(PrivilegeVector* privileges,
+ const Privilege& privilegeToAdd);
+
Privilege() {};
Privilege(const ResourcePattern& resource, const ActionType& action);
@@ -53,6 +65,4 @@ namespace mongo {
ActionSet _actions; // bitmask of actions this privilege grants
};
- typedef std::vector<Privilege> PrivilegeVector;
-
} // namespace mongo
diff --git a/src/mongo/db/auth/resource_pattern.cpp b/src/mongo/db/auth/resource_pattern.cpp
index 954bbc24d0a..9a527f4598e 100644
--- a/src/mongo/db/auth/resource_pattern.cpp
+++ b/src/mongo/db/auth/resource_pattern.cpp
@@ -24,43 +24,6 @@
namespace mongo {
- bool ResourcePattern::matchesDatabaseName(const StringData& dbName) const {
- switch (_matchType) {
- case matchAnyResource: return true;
- case matchAnyNormalResource: return true;
- case matchDatabaseName: return dbName == _ns.db();
- default: return false;
- }
- }
-
- bool ResourcePattern::matchesNamespaceString(const NamespaceString& ns) const {
- switch (_matchType) {
- case matchAnyResource: return true;
- case matchAnyNormalResource: return !ns.isSystem();
- case matchDatabaseName: return ns.db() == _ns.db() && !ns.isSystem();
- case matchCollectionName: return ns.coll() == _ns.coll();
- case matchExactNamespace: return ns == _ns;
- default: return false;
- }
- }
-
- bool ResourcePattern::matchesResourcePattern(const ResourcePattern& target) const {
- switch (target._matchType) {
- case matchAnyResource:
- return matchesEverything();
- case matchClusterResource:
- return matchesClusterResource();
- case matchDatabaseName:
- return matchesDatabaseName(target._ns.db());
- case matchExactNamespace:
- return matchesNamespaceString(target._ns);
- default:
- error() << "Programming error: target of matchesResourcePattern() must be a specific "
- "resource or ResourcePattern::forAnyResource(); not a wildcard";
- fassertFailed(17136);
- }
- }
-
std::string ResourcePattern::toString() const {
switch (_matchType) {
case matchNever:
diff --git a/src/mongo/db/auth/resource_pattern.h b/src/mongo/db/auth/resource_pattern.h
index 24bc1020301..9cbd9255840 100644
--- a/src/mongo/db/auth/resource_pattern.h
+++ b/src/mongo/db/auth/resource_pattern.h
@@ -26,10 +26,14 @@
namespace mongo {
/**
- * Representation of patterns that match various kinds of resources used in access control
- * checks.
+ * Representation of names of various kinds of resources targetable by the access control
+ * system.
*
- * The resources are databases, collections and the the cluster itself.
+ * Three of the types of name, "forDatabaseName", "forExactNamespace" and "forClusterResource",
+ * can represent concrete resources targeted for manipulation by database operations. All of
+ * the types also act as patterns, useful for matching against groups of concrete resources as
+ * part of the access control system. See buildResourceSearchList() in
+ * authorization_session.cpp for details.
*/
class ResourcePattern {
public:
@@ -119,57 +123,6 @@ namespace mongo {
}
/**
- * Returns true if this pattern matches nothing at all.
- */
- bool matchesNothing() const { return matchNever == _matchType; }
-
- /**
- * Returns true if this pattern matches every possible resource.
- */
- bool matchesEverything() const { return matchAnyResource == _matchType; }
-
- /**
- * Returns true if this pattern matches every resource except the cluster resource and
- * system collections.
- */
- bool matchesAnyNormalResource() const {
- return matchesEverything() || matchAnyNormalResource == _matchType;
- }
-
- /**
- * Returns true if this pattern matches the system resource.
- */
- bool matchesClusterResource() const {
- return matchesEverything() || _matchType == matchClusterResource;
- }
-
- /**
- * Returns true if this pattern matches the named database.
- */
- bool matchesDatabaseName(const StringData& dbName) const;
-
- /**
- * Returns true if this pattern matches the given NamespaceString.
- */
- bool matchesNamespaceString(const NamespaceString& ns) const;
-
- /**
- * Returns true if this pattern matches the target.
- *
- * The target must be a pattern matching some specific instance of a resource, rather than a
- * wildcard of some sort. That is, it must be a database name pattern, an exact match
- * pattern, or a cluster resource pattern.
- *
- * As a special exception, the target may also be ResourcePattern::forAnyResource(), since
- * this is the target used for providing access control on applyOps and db.eval. If the
- * target type is ResourcePattern::forAnyResource(), this method only returns true if this
- * instance is ResourcePattern::forAnyResource().
- *
- * Behavior for other patterns is undefined.
- */
- bool matchesResourcePattern(const ResourcePattern& target) const;
-
- /**
* Returns the namespace that this pattern matches.
*
* Behavior is undefined unless isExactNamespacePattern() is true.
diff --git a/src/mongo/db/auth/resource_pattern_test.cpp b/src/mongo/db/auth/resource_pattern_test.cpp
deleted file mode 100644
index 4ac2c467846..00000000000
--- a/src/mongo/db/auth/resource_pattern_test.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/**
- * Copyright (C) 2013 10gen Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string>
-
-#include "mongo/db/auth/resource_pattern.h"
-#include "mongo/db/namespace_string.h"
-#include "mongo/unittest/unittest.h"
-
-namespace mongo {
-namespace {
-
- TEST(ResourcePattern, AnyResourcePattern) {
- ResourcePattern pattern = ResourcePattern::forAnyResource();
- ASSERT(pattern.matchesEverything());
- ASSERT(pattern.matchesAnyNormalResource());
- ASSERT(pattern.matchesClusterResource());
- ASSERT(pattern.matchesDatabaseName("admin"));
- ASSERT(pattern.matchesDatabaseName("config"));
- ASSERT(pattern.matchesDatabaseName("test"));
- ASSERT(pattern.matchesDatabaseName("work"));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
- }
-
- TEST(ResourcePattern, AnyNormalResourcePattern) {
- ResourcePattern pattern = ResourcePattern::forAnyNormalResource();
- ASSERT(!pattern.matchesEverything());
- ASSERT(pattern.matchesAnyNormalResource());
- ASSERT(!pattern.matchesClusterResource());
- ASSERT(pattern.matchesDatabaseName("admin"));
- ASSERT(pattern.matchesDatabaseName("config"));
- ASSERT(pattern.matchesDatabaseName("test"));
- ASSERT(pattern.matchesDatabaseName("work"));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
- }
-
- TEST(ResourcePattern, ClusterResourcePattern) {
- ResourcePattern pattern = ResourcePattern::forClusterResource();
- ASSERT(!pattern.matchesEverything());
- ASSERT(!pattern.matchesAnyNormalResource());
- ASSERT(pattern.matchesClusterResource());
- ASSERT(!pattern.matchesDatabaseName("admin"));
- ASSERT(!pattern.matchesDatabaseName("config"));
- ASSERT(!pattern.matchesDatabaseName("test"));
- ASSERT(!pattern.matchesDatabaseName("work"));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
- }
-
- TEST(ResourcePattern, DatabaseNameTestPattern) {
- ResourcePattern pattern = ResourcePattern::forDatabaseName("test");
- ASSERT(!pattern.matchesEverything());
- ASSERT(!pattern.matchesAnyNormalResource());
- ASSERT(!pattern.matchesClusterResource());
- ASSERT(!pattern.matchesDatabaseName("admin"));
- ASSERT(!pattern.matchesDatabaseName("config"));
- ASSERT(pattern.matchesDatabaseName("test"));
- ASSERT(!pattern.matchesDatabaseName("work"));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
-
- pattern = ResourcePattern::forDatabaseName("admin");
- ASSERT(!pattern.matchesEverything());
- ASSERT(!pattern.matchesClusterResource());
- ASSERT(pattern.matchesDatabaseName("admin"));
- ASSERT(!pattern.matchesDatabaseName("config"));
- ASSERT(!pattern.matchesDatabaseName("test"));
- ASSERT(!pattern.matchesDatabaseName("work"));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
- }
-
- TEST(ResourcePattern, NormalCollectionPattern) {
- ResourcePattern pattern = ResourcePattern::forCollectionName("collection");
- ASSERT(!pattern.matchesEverything());
- ASSERT(!pattern.matchesAnyNormalResource());
- ASSERT(!pattern.matchesClusterResource());
- ASSERT(!pattern.matchesDatabaseName("admin"));
- ASSERT(!pattern.matchesDatabaseName("config"));
- ASSERT(!pattern.matchesDatabaseName("test"));
- ASSERT(!pattern.matchesDatabaseName("work"));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
- }
-
- TEST(ResourcePattern, DottedCollectionPattern) {
- ResourcePattern pattern = ResourcePattern::forCollectionName("dotted.collection");
- ASSERT(!pattern.matchesEverything());
- ASSERT(!pattern.matchesAnyNormalResource());
- ASSERT(!pattern.matchesClusterResource());
- ASSERT(!pattern.matchesDatabaseName("admin"));
- ASSERT(!pattern.matchesDatabaseName("config"));
- ASSERT(!pattern.matchesDatabaseName("test"));
- ASSERT(!pattern.matchesDatabaseName("work"));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("config")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
- }
-
- TEST(ResourcePattern, SystemCollectionPattern) {
- ResourcePattern pattern = ResourcePattern::forCollectionName("system.profile");
- ASSERT(!pattern.matchesEverything());
- ASSERT(!pattern.matchesAnyNormalResource());
- ASSERT(!pattern.matchesClusterResource());
- ASSERT(!pattern.matchesDatabaseName("admin"));
- ASSERT(!pattern.matchesDatabaseName("config"));
- ASSERT(!pattern.matchesDatabaseName("test"));
- ASSERT(!pattern.matchesDatabaseName("work"));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
- }
-
- TEST(ResourcePattern, ExactNamespacePattern) {
- ResourcePattern pattern = ResourcePattern::forExactNamespace(
- NamespaceString("admin.system.profile"));
- ASSERT(!pattern.matchesEverything());
- ASSERT(!pattern.matchesAnyNormalResource());
- ASSERT(!pattern.matchesClusterResource());
- ASSERT(!pattern.matchesDatabaseName("admin"));
- ASSERT(!pattern.matchesDatabaseName("config"));
- ASSERT(!pattern.matchesDatabaseName("test"));
- ASSERT(!pattern.matchesDatabaseName("work"));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
-
- pattern = ResourcePattern::forExactNamespace(NamespaceString("test.system.profile"));
- ASSERT(!pattern.matchesEverything());
- ASSERT(!pattern.matchesClusterResource());
- ASSERT(!pattern.matchesDatabaseName("admin"));
- ASSERT(!pattern.matchesDatabaseName("config"));
- ASSERT(!pattern.matchesDatabaseName("test"));
- ASSERT(!pattern.matchesDatabaseName("work"));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
-
- pattern = ResourcePattern::forExactNamespace(NamespaceString("test.collection"));
- ASSERT(!pattern.matchesEverything());
- ASSERT(!pattern.matchesClusterResource());
- ASSERT(!pattern.matchesDatabaseName("admin"));
- ASSERT(!pattern.matchesDatabaseName("config"));
- ASSERT(!pattern.matchesDatabaseName("test"));
- ASSERT(!pattern.matchesDatabaseName("work"));
- ASSERT(pattern.matchesNamespaceString(NamespaceString("test.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("test.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("work.system.frimfram")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.dotted.collection")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.not.system.profile")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.profile.not")));
- ASSERT(!pattern.matchesNamespaceString(NamespaceString("admin.system.frimfram")));
- }
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/db/auth/role_graph.cpp b/src/mongo/db/auth/role_graph.cpp
index 9a76da37223..4f96d073ed0 100644
--- a/src/mongo/db/auth/role_graph.cpp
+++ b/src/mongo/db/auth/role_graph.cpp
@@ -223,24 +223,6 @@ namespace {
return Status::OK();
}
-namespace {
- // Helper function for adding a privilege to a privilege vector, de-duping the privilege if
- // the vector already contains a privilege on the same resource.
- void addPrivilegeToPrivilegeVector(PrivilegeVector& currentPrivileges,
- const Privilege& privilegeToAdd) {
- for (PrivilegeVector::iterator it = currentPrivileges.begin();
- it != currentPrivileges.end(); ++it) {
- Privilege& curPrivilege = *it;
- if (curPrivilege.getResourcePattern() == privilegeToAdd.getResourcePattern()) {
- curPrivilege.addActions(privilegeToAdd.getActions());
- return;
- }
- }
- // No privilege exists yet for this resource
- currentPrivileges.push_back(privilegeToAdd);
- }
-} // namespace
-
Status RoleGraph::addPrivilegeToRole(const RoleName& role, const Privilege& privilegeToAdd) {
if (!roleExists(role)) {
return Status(ErrorCodes::RoleNotFound,
@@ -261,7 +243,7 @@ namespace {
void RoleGraph::_addPrivilegeToRoleNoChecks(const RoleName& role,
const Privilege& privilegeToAdd) {
- addPrivilegeToPrivilegeVector(_directPrivilegesForRole[role], privilegeToAdd);
+ Privilege::addPrivilegeToPrivilegeVector(&_directPrivilegesForRole[role], privilegeToAdd);
}
// NOTE: Current runtime of this is O(n*m) where n is the size of the current PrivilegeVector
@@ -444,7 +426,7 @@ namespace {
const PrivilegeVector& childsPrivileges = _allPrivilegesForRole[childRole];
for (PrivilegeVector::const_iterator privIt = childsPrivileges.begin();
privIt != childsPrivileges.end(); ++privIt) {
- addPrivilegeToPrivilegeVector(currentRoleAllPrivileges, *privIt);
+ Privilege::addPrivilegeToPrivilegeVector(&currentRoleAllPrivileges, *privIt);
}
}
diff --git a/src/mongo/db/auth/role_graph.h b/src/mongo/db/auth/role_graph.h
index c1be6c10b60..7d6b83a3acc 100644
--- a/src/mongo/db/auth/role_graph.h
+++ b/src/mongo/db/auth/role_graph.h
@@ -66,10 +66,9 @@ namespace mongo {
void swap(RoleGraph& other);
/**
- * Returns an ActionSet of all actions that can be be granted to users. This does not
- * include internal-only actions.
+ * Adds to "privileges" the necessary privileges to do absolutely anything on the system.
*/
- static ActionSet getAllUserActions();
+ static void generateUniversalPrivileges(PrivilegeVector* privileges);
/**
* Returns an iterator that can be used to get a list of the members of the given role.
diff --git a/src/mongo/db/auth/role_graph_builtin_roles.cpp b/src/mongo/db/auth/role_graph_builtin_roles.cpp
index 2ca5544c79c..9543bc1b54a 100644
--- a/src/mongo/db/auth/role_graph_builtin_roles.cpp
+++ b/src/mongo/db/auth/role_graph_builtin_roles.cpp
@@ -24,10 +24,10 @@
namespace mongo {
- const std::string RoleGraph::BUILTIN_ROLE_V0_READ = "oldRead";
- const std::string RoleGraph::BUILTIN_ROLE_V0_READ_WRITE= "oldReadWrite";
- const std::string RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ = "oldAdminRead";
- const std::string RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ_WRITE= "oldAdminReadWrite";
+ const std::string RoleGraph::BUILTIN_ROLE_V0_READ = "read";
+ const std::string RoleGraph::BUILTIN_ROLE_V0_READ_WRITE= "dbOwner";
+ const std::string RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ = "readAnyDatabase";
+ const std::string RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ_WRITE= "root";
namespace {
const std::string ADMIN_DBNAME = "admin";
@@ -41,248 +41,392 @@ namespace {
const std::string BUILTIN_ROLE_READ_WRITE_ANY_DB = "readWriteAnyDatabase";
const std::string BUILTIN_ROLE_USER_ADMIN_ANY_DB = "userAdminAnyDatabase";
const std::string BUILTIN_ROLE_DB_ADMIN_ANY_DB = "dbAdminAnyDatabase";
+ const std::string BUILTIN_ROLE_ROOT = "root";
+ const std::string BUILTIN_ROLE_INTERNAL = "__system";
+ const std::string BUILTIN_ROLE_DB_OWNER = "dbOwner";
- // ActionSets for the various built-in roles. These ActionSets contain all the actions that
- // a user of each built-in role is granted.
+ /// Actions that the "read" role may perform on a normal resources of a specific database, and
+ /// that the "readAnyDatabase" role may perform on normal resources of any database.
ActionSet readRoleActions;
+
+ /// Actions that the "readWrite" role may perform on a normal resources of a specific database,
+ /// and that the "readWriteAnyDatabase" role may perform on normal resources of any database.
ActionSet readWriteRoleActions;
+
+ /// Actions that the "userAdmin" role may perform on normal resources of a specific database,
+ /// and that the "userAdminAnyDatabase" role may perform on normal resources of any database.
ActionSet userAdminRoleActions;
+
+ /// Actions that the "dbAdmin" role may perform on normal resources of a specific database,
+ // and that the "dbAdminAnyDatabase" role may perform on normal resources of any database.
ActionSet dbAdminRoleActions;
- ActionSet clusterAdminRoleActions;
- // Can only be performed by internal connections. Nothing ever explicitly grants these actions,
- // but they're included when calling addAllActions on an ActionSet, which is how internal
- // connections are granted their privileges.
- ActionSet internalActions;
- // Old-style user roles
- ActionSet compatibilityReadOnlyActions;
- ActionSet compatibilityReadWriteActions;
- ActionSet compatibilityReadOnlyAdminActions;
- ActionSet compatibilityReadWriteAdminActions;
+ /// Actions that the clusterAdmin role may perform on the cluster resource.
+ ActionSet clusterAdminRoleClusterActions;
+
+ /// Actions that the clusterAdmin role may perform on any database.
+ ActionSet clusterAdminRoleDatabaseActions;
+
+ /// Actions that the "dbOwner" role may perform on normal resources of a specific database.
+ ActionSet dbOwnerRoleActions;
+
+ ActionSet& operator<<(ActionSet& target, ActionType source) {
+ target.addAction(source);
+ return target;
+ }
+
+ void operator+=(ActionSet& target, const ActionSet& source) {
+ target.addAllActionsFromSet(source);
+ }
// This sets up the built-in role ActionSets. This is what determines what actions each role
// is authorized to perform
MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) {
// Read role
- readRoleActions.addAction(ActionType::cloneCollectionLocalSource);
- readRoleActions.addAction(ActionType::collStats);
- readRoleActions.addAction(ActionType::dbHash);
- readRoleActions.addAction(ActionType::dbStats);
- readRoleActions.addAction(ActionType::find);
- readRoleActions.addAction(ActionType::indexRead);
- readRoleActions.addAction(ActionType::killCursors);
+ readRoleActions
+ << ActionType::cloneCollectionLocalSource
+ << ActionType::collStats
+ << ActionType::dbHash
+ << ActionType::dbStats
+ << ActionType::find
+ << ActionType::killCursors;
// Read-write role
- readWriteRoleActions.addAllActionsFromSet(readRoleActions);
- readWriteRoleActions.addAction(ActionType::cloneCollectionTarget);
- readWriteRoleActions.addAction(ActionType::convertToCapped);
- readWriteRoleActions.addAction(ActionType::createCollection); // db admin gets this also
- readWriteRoleActions.addAction(ActionType::dropCollection);
- readWriteRoleActions.addAction(ActionType::dropIndexes);
- readWriteRoleActions.addAction(ActionType::emptycapped);
- readWriteRoleActions.addAction(ActionType::ensureIndex);
- readWriteRoleActions.addAction(ActionType::insert);
- readWriteRoleActions.addAction(ActionType::remove);
- readWriteRoleActions.addAction(ActionType::renameCollectionSameDB); // db admin gets this also
- readWriteRoleActions.addAction(ActionType::update);
+ readWriteRoleActions += readRoleActions;
+ readWriteRoleActions
+ << ActionType::cloneCollectionTarget
+ << ActionType::convertToCapped
+ << ActionType::createCollection // db admin gets this also
+ << ActionType::dropCollection
+ << ActionType::dropIndexes
+ << ActionType::emptycapped
+ << ActionType::ensureIndex
+ << ActionType::insert
+ << ActionType::remove
+ << ActionType::renameCollectionSameDB // db admin gets this also
+ << ActionType::update;
// User admin role
- userAdminRoleActions.addAction(ActionType::userAdmin);
+ userAdminRoleActions
+ << ActionType::userAdmin;
// DB admin role
- dbAdminRoleActions.addAction(ActionType::clean);
- dbAdminRoleActions.addAction(ActionType::cloneCollectionLocalSource);
- dbAdminRoleActions.addAction(ActionType::collMod);
- dbAdminRoleActions.addAction(ActionType::collStats);
- dbAdminRoleActions.addAction(ActionType::compact);
- dbAdminRoleActions.addAction(ActionType::convertToCapped);
- dbAdminRoleActions.addAction(ActionType::createCollection); // read_write gets this also
- dbAdminRoleActions.addAction(ActionType::dbStats);
- dbAdminRoleActions.addAction(ActionType::dropCollection);
- dbAdminRoleActions.addAction(ActionType::dropIndexes);
- dbAdminRoleActions.addAction(ActionType::ensureIndex);
- dbAdminRoleActions.addAction(ActionType::indexRead);
- dbAdminRoleActions.addAction(ActionType::indexStats);
- dbAdminRoleActions.addAction(ActionType::profileEnable);
- dbAdminRoleActions.addAction(ActionType::profileRead);
- dbAdminRoleActions.addAction(ActionType::reIndex);
- dbAdminRoleActions.addAction(ActionType::renameCollectionSameDB); // read_write gets this also
- dbAdminRoleActions.addAction(ActionType::storageDetails);
- dbAdminRoleActions.addAction(ActionType::validate);
-
- // We separate clusterAdmin read-only and read-write actions for backwards
- // compatibility with old-style read-only admin users. This separation is not exposed to
- // the user, and could go away once we stop supporting old-style privilege documents.
- ActionSet clusterAdminRoleReadActions;
- ActionSet clusterAdminRoleWriteActions;
-
- // Cluster admin role
- clusterAdminRoleReadActions.addAction(ActionType::connPoolStats);
- clusterAdminRoleReadActions.addAction(ActionType::connPoolSync);
- clusterAdminRoleReadActions.addAction(ActionType::getCmdLineOpts);
- clusterAdminRoleReadActions.addAction(ActionType::getLog);
- clusterAdminRoleReadActions.addAction(ActionType::getParameter);
- clusterAdminRoleReadActions.addAction(ActionType::getShardMap);
- clusterAdminRoleReadActions.addAction(ActionType::getShardVersion);
- clusterAdminRoleReadActions.addAction(ActionType::hostInfo);
- clusterAdminRoleReadActions.addAction(ActionType::listDatabases);
- clusterAdminRoleReadActions.addAction(ActionType::listShards);
- clusterAdminRoleReadActions.addAction(ActionType::logRotate);
- clusterAdminRoleReadActions.addAction(ActionType::netstat);
- clusterAdminRoleReadActions.addAction(ActionType::replSetFreeze);
- clusterAdminRoleReadActions.addAction(ActionType::replSetGetStatus);
- clusterAdminRoleReadActions.addAction(ActionType::replSetMaintenance);
- clusterAdminRoleReadActions.addAction(ActionType::replSetStepDown);
- clusterAdminRoleReadActions.addAction(ActionType::replSetSyncFrom);
- clusterAdminRoleReadActions.addAction(ActionType::setParameter);
- clusterAdminRoleReadActions.addAction(ActionType::setShardVersion); // TODO: should this be internal?
- clusterAdminRoleReadActions.addAction(ActionType::serverStatus);
- clusterAdminRoleReadActions.addAction(ActionType::splitVector);
- // Shutdown is in read actions b/c that's how it was in 2.2
- clusterAdminRoleReadActions.addAction(ActionType::shutdown);
- clusterAdminRoleReadActions.addAction(ActionType::top);
- clusterAdminRoleReadActions.addAction(ActionType::touch);
- clusterAdminRoleReadActions.addAction(ActionType::unlock);
- clusterAdminRoleReadActions.addAction(ActionType::unsetSharding);
- clusterAdminRoleReadActions.addAction(ActionType::writeBacksQueued);
-
- clusterAdminRoleWriteActions.addAction(ActionType::addShard);
- clusterAdminRoleWriteActions.addAction(ActionType::cleanupOrphaned);
- clusterAdminRoleWriteActions.addAction(ActionType::closeAllDatabases);
- clusterAdminRoleWriteActions.addAction(ActionType::cpuProfiler);
- clusterAdminRoleWriteActions.addAction(ActionType::cursorInfo);
- clusterAdminRoleWriteActions.addAction(ActionType::diagLogging);
- clusterAdminRoleWriteActions.addAction(ActionType::dropDatabase); // TODO: Should there be a CREATE_DATABASE also?
- clusterAdminRoleWriteActions.addAction(ActionType::enableSharding);
- clusterAdminRoleWriteActions.addAction(ActionType::flushRouterConfig);
- clusterAdminRoleWriteActions.addAction(ActionType::fsync);
- clusterAdminRoleWriteActions.addAction(ActionType::inprog);
- clusterAdminRoleWriteActions.addAction(ActionType::killop);
- clusterAdminRoleWriteActions.addAction(ActionType::mergeChunks);
- clusterAdminRoleWriteActions.addAction(ActionType::moveChunk);
- clusterAdminRoleWriteActions.addAction(ActionType::movePrimary);
- clusterAdminRoleWriteActions.addAction(ActionType::removeShard);
- clusterAdminRoleWriteActions.addAction(ActionType::repairDatabase);
- clusterAdminRoleWriteActions.addAction(ActionType::replSetInitiate);
- clusterAdminRoleWriteActions.addAction(ActionType::replSetReconfig);
- clusterAdminRoleWriteActions.addAction(ActionType::resync);
- clusterAdminRoleWriteActions.addAction(ActionType::shardCollection);
- clusterAdminRoleWriteActions.addAction(ActionType::shardingState);
- clusterAdminRoleWriteActions.addAction(ActionType::split);
- clusterAdminRoleWriteActions.addAction(ActionType::splitChunk);
-
- clusterAdminRoleActions.addAllActionsFromSet(clusterAdminRoleReadActions);
- clusterAdminRoleActions.addAllActionsFromSet(clusterAdminRoleWriteActions);
- clusterAdminRoleActions.addAction(ActionType::killCursors);
-
- // Old-style user actions, for backwards compatibility
- compatibilityReadOnlyActions.addAllActionsFromSet(readRoleActions);
-
- compatibilityReadWriteActions.addAllActionsFromSet(readWriteRoleActions);
- compatibilityReadWriteActions.addAllActionsFromSet(dbAdminRoleActions);
- compatibilityReadWriteActions.addAllActionsFromSet(userAdminRoleActions);
- compatibilityReadWriteActions.addAction(ActionType::clone);
- compatibilityReadWriteActions.addAction(ActionType::copyDBTarget);
- compatibilityReadWriteActions.addAction(ActionType::dropDatabase);
- compatibilityReadWriteActions.addAction(ActionType::repairDatabase);
-
- compatibilityReadOnlyAdminActions.addAllActionsFromSet(compatibilityReadOnlyActions);
- compatibilityReadOnlyAdminActions.addAllActionsFromSet(clusterAdminRoleReadActions);
-
- compatibilityReadWriteAdminActions.addAllActionsFromSet(compatibilityReadWriteActions);
- compatibilityReadWriteAdminActions.addAllActionsFromSet(compatibilityReadOnlyAdminActions);
- compatibilityReadWriteAdminActions.addAllActionsFromSet(clusterAdminRoleWriteActions);
-
- // Internal commands
- internalActions.addAction(ActionType::clone);
- internalActions.addAction(ActionType::handshake);
- internalActions.addAction(ActionType::mapReduceShardedFinish);
- internalActions.addAction(ActionType::replSetElect);
- internalActions.addAction(ActionType::replSetFresh);
- internalActions.addAction(ActionType::replSetGetRBID);
- internalActions.addAction(ActionType::replSetHeartbeat);
- internalActions.addAction(ActionType::writebacklisten);
- internalActions.addAction(ActionType::userAdminV1);
- internalActions.addAction(ActionType::_migrateClone);
- internalActions.addAction(ActionType::_recvChunkAbort);
- internalActions.addAction(ActionType::_recvChunkCommit);
- internalActions.addAction(ActionType::_recvChunkStart);
- internalActions.addAction(ActionType::_recvChunkStatus);
- internalActions.addAction(ActionType::_transferMods);
+ dbAdminRoleActions
+ << ActionType::clean
+ << ActionType::cloneCollectionLocalSource
+ << ActionType::collMod
+ << ActionType::collStats
+ << ActionType::compact
+ << ActionType::convertToCapped
+ << ActionType::createCollection // read_write gets this also
+ << ActionType::dbStats
+ << ActionType::dropCollection
+ << ActionType::dropIndexes
+ << ActionType::ensureIndex
+ << ActionType::indexStats
+ << ActionType::profileEnable
+ << ActionType::reIndex
+ << ActionType::renameCollectionSameDB // read_write gets this also
+ << ActionType::storageDetails
+ << ActionType::validate;
+
+ // Cluster admin role actions that target the cluster resource.
+ clusterAdminRoleClusterActions
+ << ActionType::connPoolStats
+ << ActionType::connPoolSync
+ << ActionType::getCmdLineOpts
+ << ActionType::getLog
+ << ActionType::getParameter
+ << ActionType::getShardMap
+ << ActionType::getShardVersion
+ << ActionType::hostInfo
+ << ActionType::listDatabases
+ << ActionType::listShards
+ << ActionType::logRotate
+ << ActionType::netstat
+ << ActionType::replSetFreeze
+ << ActionType::replSetGetStatus
+ << ActionType::replSetMaintenance
+ << ActionType::replSetStepDown
+ << ActionType::replSetSyncFrom
+ << ActionType::setParameter
+ << ActionType::setShardVersion // TODO: should this be internal?
+ << ActionType::serverStatus
+ << ActionType::splitVector
+ << ActionType::shutdown
+ << ActionType::top
+ << ActionType::touch
+ << ActionType::unlock
+ << ActionType::unsetSharding
+ << ActionType::writeBacksQueued
+ << ActionType::addShard
+ << ActionType::cleanupOrphaned
+ << ActionType::closeAllDatabases
+ << ActionType::cpuProfiler
+ << ActionType::cursorInfo
+ << ActionType::diagLogging
+ << ActionType::enableSharding
+ << ActionType::flushRouterConfig
+ << ActionType::fsync
+ << ActionType::inprog
+ << ActionType::killop
+ << ActionType::mergeChunks
+ << ActionType::moveChunk
+ << ActionType::movePrimary
+ << ActionType::removeShard
+ << ActionType::repairDatabase
+ << ActionType::replSetInitiate
+ << ActionType::replSetReconfig
+ << ActionType::resync
+ << ActionType::shardCollection
+ << ActionType::shardingState
+ << ActionType::split
+ << ActionType::splitChunk;
+
+ clusterAdminRoleDatabaseActions
+ << ActionType::dropDatabase
+ << ActionType::killCursors;
+
+ // Database-owner role database actions.
+ dbOwnerRoleActions += readWriteRoleActions;
+ dbOwnerRoleActions += dbAdminRoleActions;
+ dbOwnerRoleActions += userAdminRoleActions;
+ dbOwnerRoleActions
+ << ActionType::clone
+ << ActionType::copyDBTarget
+ << ActionType::dropDatabase
+ << ActionType::repairDatabase;
return Status::OK();
}
+ void addReadOnlyDbPrivileges(PrivilegeVector* privileges, const StringData& dbName) {
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges, Privilege(ResourcePattern::forDatabaseName(dbName), readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forExactNamespace(
+ NamespaceString(dbName, "system.indexes")),
+ readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forExactNamespace(NamespaceString(dbName, "system.js")),
+ readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forExactNamespace(
+ NamespaceString(dbName, "system.namespaces")),
+ readRoleActions));
+ }
+
+ void addReadWriteDbPrivileges(PrivilegeVector* privileges, const StringData& dbName) {
+ addReadOnlyDbPrivileges(privileges, dbName);
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forDatabaseName(dbName), readWriteRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forExactNamespace(NamespaceString(dbName, "system.js")),
+ readWriteRoleActions));
+ }
+
+ void addUserAdminDbPrivileges(PrivilegeVector* privileges, const StringData& dbName) {
+ privileges->push_back(
+ Privilege(ResourcePattern::forDatabaseName(dbName), userAdminRoleActions));
+ }
+
+ void addDbAdminDbPrivileges(PrivilegeVector* privileges, const StringData& dbName) {
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forDatabaseName(dbName), dbAdminRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forExactNamespace(
+ NamespaceString(dbName, "system.indexes")),
+ readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forExactNamespace(
+ NamespaceString(dbName, "system.namespaces")),
+ readRoleActions));
+ ActionSet profileActions = readRoleActions;
+ profileActions.addAction(ActionType::dropCollection);
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forExactNamespace(
+ NamespaceString(dbName, "system.profile")),
+ profileActions));
+ }
+
+ void addDbOwnerPrivileges(PrivilegeVector* privileges, const StringData& dbName) {
+
+ addReadWriteDbPrivileges(privileges, dbName);
+ addDbAdminDbPrivileges(privileges, dbName);
+ addUserAdminDbPrivileges(privileges, dbName);
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forDatabaseName(dbName), dbOwnerRoleActions));
+ }
+
+
+ void addReadOnlyAnyDbPrivileges(PrivilegeVector* privileges) {
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forAnyNormalResource(), readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forClusterResource(), ActionType::listDatabases));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forCollectionName("system.indexes"),
+ readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forCollectionName("system.js"),
+ readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forCollectionName("system.namespaces"),
+ readRoleActions));
+ }
+
+ void addReadWriteAnyDbPrivileges(PrivilegeVector* privileges) {
+ addReadOnlyAnyDbPrivileges(privileges);
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forAnyNormalResource(), readWriteRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forCollectionName("system.js"), readWriteRoleActions));
+ }
+
+ void addUserAdminAnyDbPrivileges(PrivilegeVector* privileges) {
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forAnyNormalResource(), userAdminRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forCollectionName("system.roles"),
+ readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forCollectionName("system.users"),
+ readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forExactNamespace(
+ NamespaceString("admin.system.version")),
+ readRoleActions));
+ }
+
+ void addDbAdminAnyDbPrivileges(PrivilegeVector* privileges) {
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forAnyNormalResource(), dbAdminRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forCollectionName("system.indexes"),
+ readRoleActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forCollectionName("system.namespaces"),
+ readRoleActions));
+ ActionSet profileActions = readRoleActions;
+ profileActions.addAction(ActionType::dropCollection);
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forCollectionName("system.profile"),
+ profileActions));
+ }
+
+ void addClusterAdminPrivileges(PrivilegeVector* privileges) {
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forClusterResource(), clusterAdminRoleClusterActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forAnyNormalResource(),
+ clusterAdminRoleDatabaseActions));
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forExactNamespace(NamespaceString("local",
+ "system.replset")),
+ readRoleActions));
+ }
+
+ void addRootRolePrivileges(PrivilegeVector* privileges) {
+ addClusterAdminPrivileges(privileges);
+ addUserAdminAnyDbPrivileges(privileges);
+ addDbAdminAnyDbPrivileges(privileges);
+ addReadWriteAnyDbPrivileges(privileges);
+ Privilege::addPrivilegeToPrivilegeVector(
+ privileges,
+ Privilege(ResourcePattern::forAnyNormalResource(), dbOwnerRoleActions));
+ }
+
+ void addInternalRolePrivileges(PrivilegeVector* privileges) {
+ RoleGraph::generateUniversalPrivileges(privileges);
+ }
+
/**
* Returns the privilege that corresponds with the given built-in role.
*/
- Privilege getPrivilegeForBuiltinRole(const RoleName& roleName) {
+ PrivilegeVector getPrivilegesForBuiltinRole(const RoleName& roleName) {
+ PrivilegeVector result;
const bool isAdminDB = (roleName.getDB() == ADMIN_DBNAME);
if (roleName.getRole() == BUILTIN_ROLE_READ) {
- return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()), readRoleActions);
+ addReadOnlyDbPrivileges(&result, roleName.getDB());
}
- if (roleName.getRole() == BUILTIN_ROLE_READ_WRITE) {
- return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
- readWriteRoleActions);
+ else if (roleName.getRole() == BUILTIN_ROLE_READ_WRITE) {
+ addReadWriteDbPrivileges(&result, roleName.getDB());
}
- if (roleName.getRole() == BUILTIN_ROLE_USER_ADMIN) {
- return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
- userAdminRoleActions);
+ else if (roleName.getRole() == BUILTIN_ROLE_USER_ADMIN) {
+ addUserAdminDbPrivileges(&result, roleName.getDB());
}
- if (roleName.getRole() == BUILTIN_ROLE_DB_ADMIN) {
- return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
- dbAdminRoleActions);
+ else if (roleName.getRole() == BUILTIN_ROLE_DB_ADMIN) {
+ addDbAdminDbPrivileges(&result, roleName.getDB());
}
- if (roleName.getRole() == RoleGraph::BUILTIN_ROLE_V0_READ) {
- return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
- compatibilityReadOnlyActions);
+ else if (roleName.getRole() == BUILTIN_ROLE_DB_OWNER) {
+ addDbOwnerPrivileges(&result, roleName.getDB());
}
- if (roleName.getRole() == RoleGraph::BUILTIN_ROLE_V0_READ_WRITE) {
- return Privilege(ResourcePattern::forDatabaseName(roleName.getDB()),
- compatibilityReadWriteActions);
+ else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_READ_ANY_DB) {
+ addReadOnlyAnyDbPrivileges(&result);
}
- if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_READ_ANY_DB) {
- return Privilege(ResourcePattern::forAnyResource(), readRoleActions);
+ else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_READ_WRITE_ANY_DB) {
+ addReadWriteAnyDbPrivileges(&result);
}
- if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_READ_WRITE_ANY_DB) {
- return Privilege(ResourcePattern::forAnyResource(), readWriteRoleActions);
+ else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_USER_ADMIN_ANY_DB) {
+ addUserAdminAnyDbPrivileges(&result);
}
- if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_USER_ADMIN_ANY_DB) {
- return Privilege(ResourcePattern::forAnyResource(), userAdminRoleActions);
+ else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_DB_ADMIN_ANY_DB) {
+ addDbAdminAnyDbPrivileges(&result);
}
- if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_DB_ADMIN_ANY_DB) {
- return Privilege(ResourcePattern::forAnyResource(), dbAdminRoleActions);
+ else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_CLUSTER_ADMIN) {
+ addClusterAdminPrivileges(&result);
}
- if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_CLUSTER_ADMIN) {
- return Privilege(ResourcePattern::forAnyResource(), clusterAdminRoleActions);
+ else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_ROOT) {
+ addRootRolePrivileges(&result);
}
- if (isAdminDB && roleName.getRole() == RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ) {
- return Privilege(ResourcePattern::forAnyResource(),
- compatibilityReadOnlyAdminActions);
+ else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_INTERNAL) {
+ addInternalRolePrivileges(&result);
}
- if (isAdminDB && roleName.getRole() == RoleGraph::BUILTIN_ROLE_V0_ADMIN_READ_WRITE) {
- return Privilege(ResourcePattern::forAnyResource(),
- compatibilityReadWriteAdminActions);
+ else {
+ fassertFailed(0);
}
-
- fassertFailed(17116);
+ return result;
}
} // namespace
- ActionSet RoleGraph::getAllUserActions() {
+ void RoleGraph::generateUniversalPrivileges(PrivilegeVector* privileges) {
ActionSet allActions;
- allActions.addAllActionsFromSet(readRoleActions);
- allActions.addAllActionsFromSet(readWriteRoleActions);
- allActions.addAllActionsFromSet(userAdminRoleActions);
- allActions.addAllActionsFromSet(dbAdminRoleActions);
- allActions.addAllActionsFromSet(clusterAdminRoleActions);
- return allActions;
+ allActions.addAllActions();
+ privileges->push_back(Privilege(ResourcePattern::forAnyResource(), allActions));
}
bool RoleGraph::_isBuiltinRole(const RoleName& role) {
- bool isAdminDB = role.getDB() == "admin";
+ bool isAdminDB = role.getDB() == ADMIN_DBNAME;
if (role.getRole() == BUILTIN_ROLE_READ) {
return true;
@@ -296,10 +440,7 @@ namespace {
else if (role.getRole() == BUILTIN_ROLE_DB_ADMIN) {
return true;
}
- else if (role.getRole() == BUILTIN_ROLE_V0_READ) {
- return true;
- }
- else if (role.getRole() == BUILTIN_ROLE_V0_READ_WRITE) {
+ else if (role.getRole() == BUILTIN_ROLE_DB_OWNER) {
return true;
}
else if (isAdminDB && role.getRole() == BUILTIN_ROLE_READ_ANY_DB) {
@@ -317,10 +458,10 @@ namespace {
else if (isAdminDB && role.getRole() == BUILTIN_ROLE_CLUSTER_ADMIN) {
return true;
}
- else if (isAdminDB && role.getRole() == BUILTIN_ROLE_V0_ADMIN_READ) {
+ else if (isAdminDB && role.getRole() == BUILTIN_ROLE_ROOT) {
return true;
}
- else if (isAdminDB && role.getRole() == BUILTIN_ROLE_V0_ADMIN_READ_WRITE) {
+ else if (isAdminDB && role.getRole() == BUILTIN_ROLE_INTERNAL) {
return true;
}
@@ -333,9 +474,11 @@ namespace {
}
_createRoleDontCheckIfRoleExists(role);
- Privilege privilege = getPrivilegeForBuiltinRole(role);
- _addPrivilegeToRoleNoChecks(role, privilege);
- _allPrivilegesForRole[role].push_back(privilege);
+ PrivilegeVector privileges = getPrivilegesForBuiltinRole(role);
+ for (size_t i = 0; i < privileges.size(); ++i) {
+ _addPrivilegeToRoleNoChecks(role, privileges[i]);
+ _allPrivilegesForRole[role].push_back(privileges[i]);
+ }
}
} // namespace mongo
diff --git a/src/mongo/db/auth/role_graph_test.cpp b/src/mongo/db/auth/role_graph_test.cpp
index 27afc61b7ac..5d719779a90 100644
--- a/src/mongo/db/auth/role_graph_test.cpp
+++ b/src/mongo/db/auth/role_graph_test.cpp
@@ -167,6 +167,16 @@ namespace {
ASSERT_FALSE(it.more());
}
+ const ResourcePattern collectionAFooResource(ResourcePattern::forExactNamespace(
+ NamespaceString("dbA.foo")));
+ const ResourcePattern db1Resource(ResourcePattern::forDatabaseName("db1"));
+ const ResourcePattern db2Resource(ResourcePattern::forDatabaseName("db2"));
+ const ResourcePattern dbAResource(ResourcePattern::forDatabaseName("dbA"));
+ const ResourcePattern dbBResource(ResourcePattern::forDatabaseName("dbB"));
+ const ResourcePattern dbCResource(ResourcePattern::forDatabaseName("dbC"));
+ const ResourcePattern dbDResource(ResourcePattern::forDatabaseName("dbD"));
+ const ResourcePattern dbResource(ResourcePattern::forDatabaseName("db"));
+
// Tests that adding multiple privileges on the same resource correctly collapses those to one
// privilege
TEST(RoleGraphTest, AddPrivileges) {
@@ -178,20 +188,20 @@ namespace {
// Test adding a single privilege
ActionSet actions;
actions.addAction(ActionType::find);
- ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(ResourcePattern::forDatabaseName("dbA"), actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(dbAResource, actions)));
PrivilegeVector privileges = graph.getDirectPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
ASSERT_EQUALS(actions.toString(), privileges[0].getActions().toString());
// Add a privilege on a different resource
- ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(ResourcePattern::forExactNamespace(NamespaceString("dbA.foo")), actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(collectionAFooResource, actions)));
privileges = graph.getDirectPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
ASSERT_EQUALS(actions.toString(), privileges[0].getActions().toString());
- ASSERT_EQUALS(ResourcePattern::forExactNamespace(NamespaceString("dbA.foo")), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(collectionAFooResource, privileges[1].getResourcePattern());
ASSERT_EQUALS(actions.toString(), privileges[1].getActions().toString());
@@ -200,24 +210,24 @@ namespace {
actions.addAction(ActionType::insert);
PrivilegeVector privilegesToAdd;
- privilegesToAdd.push_back(Privilege(ResourcePattern::forDatabaseName("dbA"), actions));
+ privilegesToAdd.push_back(Privilege(dbAResource, actions));
actions.removeAllActions();
actions.addAction(ActionType::update);
- privilegesToAdd.push_back(Privilege(ResourcePattern::forDatabaseName("dbA"), actions));
+ privilegesToAdd.push_back(Privilege(dbAResource, actions));
ASSERT_OK(graph.addPrivilegesToRole(roleA, privilegesToAdd));
privileges = graph.getDirectPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbAResource, 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(ResourcePattern::forExactNamespace(NamespaceString("dbA.foo")), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(collectionAFooResource, privileges[1].getResourcePattern());
ASSERT_EQUALS(actions.toString(), privileges[1].getActions().toString());
}
@@ -283,15 +293,15 @@ namespace {
ASSERT_OK(graph.createRole(roleB));
ASSERT_OK(graph.createRole(roleC));
- 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.addPrivilegeToRole(roleA, Privilege(dbAResource, actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(dbBResource, actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege(dbCResource, actions)));
ASSERT_OK(graph.recomputePrivilegeData());
PrivilegeVector privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbAResource, 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 +311,8 @@ namespace {
ASSERT_OK(graph.recomputePrivilegeData());
privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbBResource, 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,36 +320,31 @@ namespace {
ASSERT_OK(graph.recomputePrivilegeData());
privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(3), privileges.size());
- 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(dbAResource, privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbBResource, privileges[1].getResourcePattern());
+ ASSERT_EQUALS(dbCResource, privileges[2].getResourcePattern());
privileges = graph.getAllPrivileges(roleB);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[0].getResourcePattern());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(dbBResource, privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbCResource, 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));
// Role graph: A->B->C->D
ASSERT_OK(graph.recomputePrivilegeData());
privileges = graph.getAllPrivileges(roleA);
- ASSERT_EQUALS(static_cast<size_t>(4), privileges.size());
- 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());
+ const size_t readWriteRolePrivilegeCount = graph.getAllPrivileges(roleD).size();
+ ASSERT_EQUALS(readWriteRolePrivilegeCount + 3, privileges.size());
+ ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbBResource, privileges[1].getResourcePattern());
+ ASSERT_EQUALS(dbCResource, privileges[2].getResourcePattern());
privileges = graph.getAllPrivileges(roleB);
- ASSERT_EQUALS(static_cast<size_t>(3), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[0].getResourcePattern());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[1].getResourcePattern());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[2].getResourcePattern());
+ ASSERT_EQUALS(readWriteRolePrivilegeCount + 2, privileges.size());
+ ASSERT_EQUALS(dbBResource, privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbCResource, privileges[1].getResourcePattern());
privileges = graph.getAllPrivileges(roleC);
- ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- 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(ResourcePattern::forDatabaseName("dbD"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(readWriteRolePrivilegeCount + 1, privileges.size());
+ ASSERT_EQUALS(dbCResource, privileges[0].getResourcePattern());
// Remove roleC from roleB, make sure that roleA then loses both roleC's and roleD's
// privileges
@@ -348,32 +353,29 @@ namespace {
ASSERT_OK(graph.recomputePrivilegeData());
privileges = graph.getAllPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbBResource, privileges[1].getResourcePattern());
privileges = graph.getAllPrivileges(roleB);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbBResource, privileges[0].getResourcePattern());
privileges = graph.getAllPrivileges(roleC);
- ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[0].getResourcePattern());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[1].getResourcePattern());
+ ASSERT_EQUALS(readWriteRolePrivilegeCount + 1, privileges.size());
+ ASSERT_EQUALS(dbCResource, privileges[0].getResourcePattern());
privileges = graph.getAllPrivileges(roleD);
- ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(readWriteRolePrivilegeCount, privileges.size());
// Make sure direct privileges were untouched
privileges = graph.getDirectPrivileges(roleA);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
privileges = graph.getDirectPrivileges(roleB);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbBResource, privileges[0].getResourcePattern());
privileges = graph.getDirectPrivileges(roleC);
ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbCResource, privileges[0].getResourcePattern());
privileges = graph.getDirectPrivileges(roleD);
- ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbD"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(readWriteRolePrivilegeCount, privileges.size());
}
// Test that if you grant 1 role to another, then remove it and change it's privileges, then
@@ -393,9 +395,9 @@ namespace {
ASSERT_OK(graph.createRole(roleB));
ASSERT_OK(graph.createRole(roleC));
- 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.addPrivilegeToRole(roleA, Privilege(dbResource, actionsA)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(dbResource, actionsB)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege(dbResource, actionsC)));
ASSERT_OK(graph.addRoleToRole(roleA, roleB));
ASSERT_OK(graph.addRoleToRole(roleB, roleC)); // graph: A <- B <- C
@@ -425,7 +427,7 @@ namespace {
ASSERT_OK(graph.removeAllPrivilegesFromRole(roleB));
ActionSet newActionsB;
newActionsB.addAction(ActionType::remove);
- ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(ResourcePattern::forDatabaseName("db"), newActionsB)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(dbResource, 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 +458,7 @@ namespace {
ASSERT_OK(graph.createRole(roleB));
actionsB.removeAllActions();
actionsB.addAction(ActionType::shutdown);
- ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(ResourcePattern::forDatabaseName("db"), actionsB)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(dbResource, actionsB)));
ASSERT_OK(graph.addRoleToRole(roleA, roleB));
ASSERT_OK(graph.recomputePrivilegeData());
@@ -482,9 +484,9 @@ namespace {
ActionSet actions;
actions.addAction(ActionType::find);
- 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.addPrivilegeToRole(roleA, Privilege(dbAResource, actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(dbBResource, actions)));
+ ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege(dbCResource, actions)));
ASSERT_OK(graph.addRoleToRole(roleA, roleB));
@@ -505,9 +507,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(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbB"), privileges[1].getResourcePattern());
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbC"), privileges[2].getResourcePattern());
+ ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbBResource, privileges[1].getResourcePattern());
+ ASSERT_EQUALS(dbCResource, privileges[2].getResourcePattern());
}
// Tests error handling
@@ -518,8 +520,8 @@ namespace {
ActionSet actions;
actions.addAction(ActionType::find);
- Privilege privilege1(ResourcePattern::forDatabaseName("db1"), actions);
- Privilege privilege2(ResourcePattern::forDatabaseName("db2"), actions);
+ Privilege privilege1(db1Resource, actions);
+ Privilege privilege2(db2Resource, actions);
PrivilegeVector privileges;
privileges.push_back(privilege1);
privileges.push_back(privilege2);
@@ -570,7 +572,7 @@ namespace {
ActionSet actions;
actions.addAction(ActionType::insert);
- Privilege privilege(ResourcePattern::forDatabaseName("dbA"), actions);
+ Privilege privilege(dbAResource, actions);
RoleGraph graph;
@@ -595,18 +597,53 @@ namespace {
ASSERT_EQUALS(1U, privileges.size());
ASSERT(privileges[0].getActions().equals(actions));
ASSERT(!privileges[0].getActions().contains(ActionType::find));
- ASSERT_EQUALS(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ ASSERT_EQUALS(dbAResource, 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(ResourcePattern::forDatabaseName("dbA"), privileges[0].getResourcePattern());
+ size_t i;
+ for (i = 0; i < privileges.size(); ++i) {
+ if (dbAResource == privileges[i].getResourcePattern())
+ break;
+ }
+ ASSERT_NOT_EQUALS(privileges.size(), i);
+ ASSERT(privileges[i].getActions().isSupersetOf(actions));
+ ASSERT(privileges[i].getActions().contains(ActionType::insert));
+ ASSERT(privileges[i].getActions().contains(ActionType::find));
ASSERT_OK(graph.deleteRole(userRole));
ASSERT(!graph.roleExists(userRole));
}
+ TEST(RoleGraphTest, BuiltinRolesOnlyOnAppropriateDatabases) {
+ RoleGraph graph;
+ ASSERT(graph.roleExists(RoleName("read", "test")));
+ ASSERT(graph.roleExists(RoleName("readWrite", "test")));
+ ASSERT(graph.roleExists(RoleName("userAdmin", "test")));
+ ASSERT(graph.roleExists(RoleName("dbAdmin", "test")));
+ ASSERT(graph.roleExists(RoleName("dbOwner", "test")));
+ ASSERT(!graph.roleExists(RoleName("readAnyDatabase", "test")));
+ ASSERT(!graph.roleExists(RoleName("readWriteAnyDatabase", "test")));
+ ASSERT(!graph.roleExists(RoleName("userAdminAnyDatabase", "test")));
+ ASSERT(!graph.roleExists(RoleName("dbAdminAnyDatabase", "test")));
+ ASSERT(!graph.roleExists(RoleName("clusterAdmin", "test")));
+ ASSERT(!graph.roleExists(RoleName("root", "test")));
+ ASSERT(!graph.roleExists(RoleName("__system", "test")));
+ ASSERT(!graph.roleExists(RoleName("MyRole", "test")));
+
+ ASSERT(graph.roleExists(RoleName("read", "admin")));
+ ASSERT(graph.roleExists(RoleName("readWrite", "admin")));
+ ASSERT(graph.roleExists(RoleName("userAdmin", "admin")));
+ ASSERT(graph.roleExists(RoleName("dbAdmin", "admin")));
+ ASSERT(graph.roleExists(RoleName("dbOwner", "admin")));
+ ASSERT(graph.roleExists(RoleName("readAnyDatabase", "admin")));
+ ASSERT(graph.roleExists(RoleName("readWriteAnyDatabase", "admin")));
+ ASSERT(graph.roleExists(RoleName("userAdminAnyDatabase", "admin")));
+ ASSERT(graph.roleExists(RoleName("dbAdminAnyDatabase", "admin")));
+ ASSERT(graph.roleExists(RoleName("clusterAdmin", "admin")));
+ ASSERT(graph.roleExists(RoleName("root", "admin")));
+ ASSERT(graph.roleExists(RoleName("__system", "admin")));
+ ASSERT(!graph.roleExists(RoleName("MyRole", "admin")));
+ }
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/db/auth/user_document_parser_test.cpp b/src/mongo/db/auth/user_document_parser_test.cpp
index 023bdc5b566..e61f7d91b3f 100644
--- a/src/mongo/db/auth/user_document_parser_test.cpp
+++ b/src/mongo/db/auth/user_document_parser_test.cpp
@@ -60,25 +60,25 @@ namespace {
ASSERT_OK(v1parser.initializeUserRolesFromUserDocument(
user.get(), readOnly, "test"));
ASSERT_EQUALS(1U, user->getRoles().size());
- ASSERT_EQUALS(1U, user->getRoles().count(RoleName("oldRead", "test")));
+ ASSERT_EQUALS(1U, user->getRoles().count(RoleName("read", "test")));
resetUsers();
ASSERT_OK(v1parser.initializeUserRolesFromUserDocument(
user.get(), readWrite, "test"));
ASSERT_EQUALS(1U, user->getRoles().size());
- ASSERT_EQUALS(1U, user->getRoles().count(RoleName("oldReadWrite", "test")));
+ ASSERT_EQUALS(1U, user->getRoles().count(RoleName("dbOwner", "test")));
resetUsers();
ASSERT_OK(v1parser.initializeUserRolesFromUserDocument(
adminUser.get(), readOnlyAdmin, "admin"));
ASSERT_EQUALS(1U, adminUser->getRoles().size());
- ASSERT_EQUALS(1U, adminUser->getRoles().count(RoleName("oldAdminRead", "admin")));
+ ASSERT_EQUALS(1U, adminUser->getRoles().count(RoleName("readAnyDatabase", "admin")));
resetUsers();
ASSERT_OK(v1parser.initializeUserRolesFromUserDocument(
adminUser.get(), readWriteAdmin, "admin"));
ASSERT_EQUALS(1U, adminUser->getRoles().size());
- ASSERT_EQUALS(1U, adminUser->getRoles().count(RoleName("oldAdminReadWrite", "admin")));
+ ASSERT_EQUALS(1U, adminUser->getRoles().count(RoleName("root", "admin")));
}
TEST_F(V1UserDocumentParsing, VerifyRolesFieldMustBeAnArray) {
diff --git a/src/mongo/db/commands/apply_ops.cpp b/src/mongo/db/commands/apply_ops.cpp
index 0b207c529f3..1f1503fe002 100644
--- a/src/mongo/db/commands/apply_ops.cpp
+++ b/src/mongo/db/commands/apply_ops.cpp
@@ -55,8 +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(ResourcePattern::forAnyResource(),
- getGlobalAuthorizationManager()->getAllUserActions()));
+ RoleGraph::generateUniversalPrivileges(out);
}
virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
diff --git a/src/mongo/db/dbeval.cpp b/src/mongo/db/dbeval.cpp
index b02ded46776..af190d082c3 100644
--- a/src/mongo/db/dbeval.cpp
+++ b/src/mongo/db/dbeval.cpp
@@ -137,8 +137,7 @@ namespace mongo {
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
- out->push_back(Privilege(ResourcePattern::forAnyResource(),
- getGlobalAuthorizationManager()->getAllUserActions()));
+ RoleGraph::generateUniversalPrivileges(out);
}
CmdEval() : Command("eval", false, "$eval") { }
bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
diff --git a/src/mongo/s/commands_public.cpp b/src/mongo/s/commands_public.cpp
index 1dadc1bf0e7..f10ba91cab7 100644
--- a/src/mongo/s/commands_public.cpp
+++ b/src/mongo/s/commands_public.cpp
@@ -1724,8 +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(ResourcePattern::forAnyResource(),
- getGlobalAuthorizationManager()->getAllUserActions()));
+ RoleGraph::generateUniversalPrivileges(out);
}
virtual bool run(const string& dbName , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
errmsg = "applyOps not allowed through mongos";
@@ -1757,8 +1756,7 @@ namespace mongo {
const BSONObj& cmdObj,
std::vector<Privilege>* out) {
// $eval can do pretty much anything, so require all privileges.
- out->push_back(Privilege(ResourcePattern::forAnyResource(),
- getGlobalAuthorizationManager()->getAllUserActions()));
+ RoleGraph::generateUniversalPrivileges(out);
}
virtual bool run(const string& dbName,
BSONObj& cmdObj,
diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js
index d45591e4fd3..f62febac867 100644
--- a/src/mongo/shell/utils.js
+++ b/src/mongo/shell/utils.js
@@ -403,11 +403,8 @@ jsTest.options = jsTestOptions
jsTest.setOption = setJsTestOption
jsTest.log = jsTestLog
jsTest.readOnlyUserRoles = ["read"]
-jsTest.basicUserRoles = ["readWrite", "dbAdmin", "userAdmin"]
-jsTest.adminUserRoles = ["clusterAdmin",
- "userAdminAnyDatabase",
- "dbAdminAnyDatabase",
- "readWriteAnyDatabase"]
+jsTest.basicUserRoles = ["dbOwner"]
+jsTest.adminUserRoles = ["root"]
jsTest.dir = function(){
return jsTest.path().replace( /\/[^\/]+$/, "/" )
@@ -436,7 +433,7 @@ jsTest.addAuth = function(conn) {
}
print ("Adding admin user on connection: " + localconn);
return localconn.getDB('admin').addUser(jsTestOptions().adminUser, jsTestOptions().adminPassword,
- jsTest.adminUserRoles, 'majority', 60000);
+ ["__system"], 'majority', 60000);
}
jsTest.authenticate = function(conn) {