diff options
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(¤tRoleAllPrivileges, *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) { |