diff options
26 files changed, 234 insertions, 1454 deletions
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index 39ede94e793..26748a9e8b3 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -14,10 +14,7 @@ env.StaticLibrary('authcore', ['action_set.cpp', 'authorization_session.cpp', 'authz_manager_external_state.cpp', 'authz_session_external_state.cpp', - 'principal.cpp', - 'principal_set.cpp', 'privilege.cpp', - 'privilege_set.cpp', 'role_graph.cpp', 'role_name.cpp', 'user.cpp', @@ -50,8 +47,6 @@ env.StaticLibrary('authmocks', LIBDEPS=['$BUILD_DIR/mongo/expressions']) env.CppUnitTest('action_set_test', 'action_set_test.cpp', LIBDEPS=['authcore']) -env.CppUnitTest('principal_set_test', 'principal_set_test.cpp', LIBDEPS=['authcore']) -env.CppUnitTest('privilege_set_test', 'privilege_set_test.cpp', LIBDEPS=['authcore']) env.CppUnitTest('role_graph_test', 'role_graph_test.cpp', LIBDEPS=['authcore']) env.CppUnitTest('user_set_test', 'user_set_test.cpp', LIBDEPS=['authcore']) env.CppUnitTest('authorization_manager_test', 'authorization_manager_test.cpp', diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp index 21722d2fcf9..3ef9d841c2b 100644 --- a/src/mongo/db/auth/authorization_manager.cpp +++ b/src/mongo/db/auth/authorization_manager.cpp @@ -27,7 +27,6 @@ #include "mongo/base/status.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/privilege.h" -#include "mongo/db/auth/privilege_set.h" #include "mongo/db/auth/user.h" #include "mongo/db/auth/user_name.h" #include "mongo/db/auth/user_name_hash.h" @@ -471,63 +470,6 @@ namespace { return Status::OK(); } - Status AuthorizationManager::buildPrivilegeSet(const std::string& dbname, - const UserName& user, - const BSONObj& privilegeDocument, - PrivilegeSet* result) const { - if (!privilegeDocument.hasField(ROLES_FIELD_NAME)) { - // Old-style (v2.2 and prior) privilege document - if (AuthorizationManager::getSupportOldStylePrivilegeDocuments()) { - return _buildPrivilegeSetFromOldStylePrivilegeDocument(dbname, - user, - privilegeDocument, - result); - } - else { - return _oldPrivilegeFormatNotSupported(); - } - } - else { - return _buildPrivilegeSetFromExtendedPrivilegeDocument( - dbname, user, privilegeDocument, result); - } - } - - Status AuthorizationManager::_buildPrivilegeSetFromOldStylePrivilegeDocument( - const std::string& dbname, - const UserName& user, - const BSONObj& privilegeDocument, - PrivilegeSet* result) const { - if (!(privilegeDocument.hasField(AuthorizationManager::USER_NAME_FIELD_NAME) && - privilegeDocument.hasField(AuthorizationManager::PASSWORD_FIELD_NAME))) { - - return Status(ErrorCodes::UnsupportedFormat, - mongoutils::str::stream() << "Invalid old-style privilege document " - "received when trying to extract privileges: " - << privilegeDocument, - 0); - } - std::string userName = privilegeDocument[AuthorizationManager::USER_NAME_FIELD_NAME].str(); - if (userName != user.getUser()) { - return Status(ErrorCodes::BadValue, - mongoutils::str::stream() << "Principal name from privilege document \"" - << userName - << "\" doesn't match name of provided Principal \"" - << user.getUser() - << "\"", - 0); - } - - bool readOnly = privilegeDocument[READONLY_FIELD_NAME].trueValue(); - ActionSet actions = getActionsForOldStyleUser(dbname, readOnly); - std::string resourceName = (dbname == ADMIN_DBNAME || dbname == LOCAL_DBNAME) ? - AuthorizationManager::WILDCARD_RESOURCE_NAME : dbname; - result->grantPrivilege(Privilege(resourceName, actions), user); - - return Status::OK(); - } - - /** * Adds to "outPrivileges" the privileges associated with having the named "role" on "dbname". * @@ -593,90 +535,6 @@ namespace { } } - /** - * Given a database name and a BSONElement representing an array of roles, populates - * "outPrivileges" with the privileges associated with the given roles on the named database. - * - * Returns Status::OK() on success. - */ - Status _getPrivilegesFromRoles(const std::string& dbname, - const BSONElement& rolesElement, - std::vector<Privilege>* outPrivileges) { - - static const char privilegesTypeMismatchMessage[] = - "Roles must be enumerated in an array of strings."; - - if (dbname == AuthorizationManager::WILDCARD_RESOURCE_NAME) { - return Status(ErrorCodes::BadValue, - AuthorizationManager::WILDCARD_RESOURCE_NAME + - " is an invalid database name."); - } - - if (rolesElement.type() != Array) - return Status(ErrorCodes::TypeMismatch, privilegesTypeMismatchMessage); - - for (BSONObjIterator iter(rolesElement.embeddedObject()); iter.more(); iter.next()) { - BSONElement roleElement = *iter; - if (roleElement.type() != String) - return Status(ErrorCodes::TypeMismatch, privilegesTypeMismatchMessage); - _addPrivilegesForSystemRole(dbname, roleElement.str(), outPrivileges); - } - return Status::OK(); - } - - Status AuthorizationManager::_buildPrivilegeSetFromExtendedPrivilegeDocument( - const std::string& dbname, - const UserName& user, - const BSONObj& privilegeDocument, - PrivilegeSet* result) const { - - if (!privilegeDocument[READONLY_FIELD_NAME].eoo()) { - return Status(ErrorCodes::UnsupportedFormat, - "Privilege documents may not contain both \"readonly\" and " - "\"roles\" fields"); - } - - std::vector<Privilege> acquiredPrivileges; - - // Acquire privileges on "dbname". - Status status = _getPrivilegesFromRoles( - dbname, privilegeDocument[ROLES_FIELD_NAME], &acquiredPrivileges); - if (!status.isOK()) - return status; - - // If "dbname" is the admin database, handle the otherDBPrivileges field, which - // grants privileges on databases other than "dbname". - BSONElement otherDbPrivileges = privilegeDocument[OTHER_DB_ROLES_FIELD_NAME]; - if (dbname == ADMIN_DBNAME) { - switch (otherDbPrivileges.type()) { - case EOO: - break; - case Object: { - for (BSONObjIterator iter(otherDbPrivileges.embeddedObject()); - iter.more(); iter.next()) { - - BSONElement rolesElement = *iter; - status = _getPrivilegesFromRoles( - rolesElement.fieldName(), rolesElement, &acquiredPrivileges); - if (!status.isOK()) - return status; - } - break; - } - default: - return Status(ErrorCodes::TypeMismatch, - "Field \"otherDBRoles\" must be an object, if present."); - } - } - else if (!otherDbPrivileges.eoo()) { - return Status(ErrorCodes::BadValue, "Only the admin database may contain a field " - "called \"otherDBRoles\""); - } - - result->grantPrivileges(acquiredPrivileges, user); - return Status::OK(); - } - Status AuthorizationManager::acquireUser(const UserName& userName, User** acquiredUser) { boost::lock_guard<boost::mutex> lk(_lock); unordered_map<UserName, User*>::iterator it = _userCache.find(userName); @@ -764,21 +622,21 @@ namespace { */ Status _initializeUserCredentialsFromPrivilegeDocument(User* user, const BSONObj& privDoc) { User::CredentialData credentials; - if (privDoc.hasField("pwd")) { - credentials.password = privDoc["pwd"].String(); + if (privDoc.hasField(AuthorizationManager::PASSWORD_FIELD_NAME)) { + credentials.password = privDoc[AuthorizationManager::PASSWORD_FIELD_NAME].String(); credentials.isExternal = false; } - else if (privDoc.hasField("userSource")) { - std::string userSource = privDoc["userSource"].String(); + else if (privDoc.hasField(AuthorizationManager::USER_SOURCE_FIELD_NAME)) { + std::string userSource = privDoc[AuthorizationManager::USER_SOURCE_FIELD_NAME].String(); if (userSource != "$external") { - return Status(ErrorCodes::FailedToParse, + return Status(ErrorCodes::UnsupportedFormat, "Cannot extract credentials from user documents without a password " "and with userSource != \"$external\""); } else { credentials.isExternal = true; } } else { - return Status(ErrorCodes::FailedToParse, + return Status(ErrorCodes::UnsupportedFormat, "Invalid user document: must have one of \"pwd\" and \"userSource\""); } @@ -831,6 +689,13 @@ namespace { Status _initializeUserRolesFromV1PrivilegeDocument( User* user, const BSONObj& privDoc, const StringData& dbname) { + + if (!privDoc[READONLY_FIELD_NAME].eoo()) { + return Status(ErrorCodes::UnsupportedFormat, + "Privilege documents may not contain both \"readonly\" and " + "\"roles\" fields"); + } + Status status = _initializeUserRolesFromV1RolesArray(user, privDoc[ROLES_FIELD_NAME], dbname); @@ -864,8 +729,8 @@ namespace { } } else if (!otherDbPrivileges.eoo()) { - return Status(ErrorCodes::BadValue, "Only the admin database may contain a field " - "called \"otherDBRoles\""); + return Status(ErrorCodes::UnsupportedFormat, + "Only the admin database may contain a field called \"otherDBRoles\""); } return Status::OK(); @@ -906,6 +771,17 @@ namespace { Status AuthorizationManager::_initializeUserFromPrivilegeDocument( User* user, const BSONObj& privDoc) const { + std::string userName = privDoc[AuthorizationManager::USER_NAME_FIELD_NAME].str(); + if (userName != user->getName().getUser()) { + return Status(ErrorCodes::BadValue, + mongoutils::str::stream() << "User name from privilege document \"" + << userName + << "\" doesn't match name of provided User \"" + << user->getName().getUser() + << "\"", + 0); + } + Status status = _initializeUserCredentialsFromPrivilegeDocument(user, privDoc); if (!status.isOK()) { return status; diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h index 8f1de7a9474..fa169ca473d 100644 --- a/src/mongo/db/auth/authorization_manager.h +++ b/src/mongo/db/auth/authorization_manager.h @@ -24,7 +24,6 @@ #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/privilege_set.h" #include "mongo/db/auth/user.h" #include "mongo/db/auth/user_name.h" #include "mongo/db/auth/user_name_hash.h" @@ -113,13 +112,6 @@ namespace mongo { // Returns Status::OK() if the document is good, or Status(ErrorCodes::BadValue), otherwise. Status checkValidPrivilegeDocument(const StringData& dbname, const BSONObj& doc); - // Parses the privilege document and returns a PrivilegeSet of all the Privileges that - // the privilege document grants. - Status buildPrivilegeSet(const std::string& dbname, - const UserName& user, - const BSONObj& privilegeDocument, - PrivilegeSet* result) const; - // Given a database name and a readOnly flag return an ActionSet describing all the actions // that an old-style user with those attributes should be given. ActionSet getActionsForOldStyleUser(const std::string& dbname, bool readOnly) const; @@ -170,34 +162,17 @@ namespace mongo { */ Status initializeAllV1UserData(); - private: - - // Parses the old-style (pre 2.4) privilege document and returns a PrivilegeSet of all the - // Privileges that the privilege document grants. - Status _buildPrivilegeSetFromOldStylePrivilegeDocument( - const std::string& dbname, - const UserName& user, - const BSONObj& privilegeDocument, - PrivilegeSet* result) const ; - - // Parses extended-form (2.4+) privilege documents and returns a PrivilegeSet of all the - // privileges that the document grants. - // - // The document, "privilegeDocument", is assumed to describe privileges for "principal", and - // to come from database "dbname". - Status _buildPrivilegeSetFromExtendedPrivilegeDocument( - const std::string& dbname, - const UserName& user, - const BSONObj& privilegeDocument, - PrivilegeSet* result) const; - /** * Parses privDoc and initializes the user object with the information extracted from the * privilege document. + * This should never be called from outside the AuthorizationManager - the only reason it's + * public instead of private is so it can be unit tested. */ Status _initializeUserFromPrivilegeDocument(User* user, const BSONObj& privDoc) const; + private: + /** * Invalidates all User objects in the cache and removes them from the cache. * Should only be called when already holding _lock. diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp index 86078c3439c..4c68e11a389 100644 --- a/src/mongo/db/auth/authorization_manager_test.cpp +++ b/src/mongo/db/auth/authorization_manager_test.cpp @@ -49,314 +49,276 @@ namespace { }; TEST_F(AuthorizationManagerTest, GetPrivilegesFromPrivilegeDocumentCompatible) { - UserName user("Spencer", "test"); + User user(UserName("Spencer", "test")); + User adminUser(UserName("Spencer", "admin")); BSONObj invalid; BSONObj readWrite = BSON("user" << "Spencer" << "pwd" << "passwordHash"); BSONObj readOnly = BSON("user" << "Spencer" << "pwd" << "passwordHash" << "readOnly" << true); - PrivilegeSet privilegeSet; - ASSERT_EQUALS(ErrorCodes::UnsupportedFormat, - authzManager->buildPrivilegeSet("test", - user, - invalid, - &privilegeSet).code()); - - ASSERT_OK(authzManager->buildPrivilegeSet("test", - user, - readOnly, - &privilegeSet)); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::insert))); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - - ASSERT_OK(authzManager->buildPrivilegeSet("test", - user, - readWrite, - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::insert))); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin))); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::compact))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::shutdown))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::addShard))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("*", ActionType::find))); - - ASSERT_OK(authzManager->buildPrivilegeSet("admin", - user, - readOnly, - &privilegeSet)); - // Should grant privileges on *. - ASSERT(privilegeSet.hasPrivilege(Privilege("*", ActionType::find))); - - ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::insert))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("*", ActionType::insert))); - - ASSERT_OK(authzManager->buildPrivilegeSet("admin", - user, - readWrite, - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("*", ActionType::insert))); + ASSERT_NOT_OK(authzManager->_initializeUserFromPrivilegeDocument( + &user, + invalid)); + + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument(&user, readOnly)); + ASSERT(user.getActionsForResource("test").contains(ActionType::find)); + ASSERT(!user.getActionsForResource("test").contains(ActionType::insert)); + + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument(&user, readWrite)); + ASSERT(user.getActionsForResource("test").contains(ActionType::find)); + ASSERT(user.getActionsForResource("test").contains(ActionType::insert)); + ASSERT(user.getActionsForResource("test").contains(ActionType::userAdmin)); + ASSERT(user.getActionsForResource("test").contains(ActionType::compact)); + ASSERT(!user.getActionsForResource("test").contains(ActionType::shutdown)); + ASSERT(!user.getActionsForResource("test").contains(ActionType::addShard)); + ASSERT(!user.getActionsForResource("admin").contains(ActionType::find)); + ASSERT(!user.getActionsForResource("*").contains(ActionType::find)); + + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument(&adminUser, readOnly)); + ASSERT(adminUser.getActionsForResource("*").contains(ActionType::find)); + ASSERT(!adminUser.getActionsForResource("admin").contains(ActionType::insert)); + ASSERT(!adminUser.getActionsForResource("*").contains(ActionType::insert)); + + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument(&adminUser, readWrite)); + ASSERT(adminUser.getActionsForResource("*").contains(ActionType::find)); + ASSERT(adminUser.getActionsForResource("*").contains(ActionType::insert)); } class PrivilegeDocumentParsing : public AuthorizationManagerTest { public: - PrivilegeDocumentParsing() : user("spencer", "test") {} + PrivilegeDocumentParsing() {} - UserName user; - PrivilegeSet privilegeSet; + scoped_ptr<User> user; + scoped_ptr<User> adminUser; + + void setUp() { + AuthorizationManagerTest::setUp(); + + user.reset(new User(UserName("spencer", "test"))); + adminUser.reset(new User(UserName("admin", "admin"))); + } }; TEST_F(PrivilegeDocumentParsing, VerifyRolesFieldMustBeAnArray) { - ASSERT_NOT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << "read"), - &privilegeSet)); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); + ASSERT_NOT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << "pwd" << "" << "roles" << "read"))); + ASSERT(user->getActionsForResource("test").empty()); } TEST_F(PrivilegeDocumentParsing, VerifyInvalidRoleGrantsNoPrivileges) { - ASSERT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("frim")), - &privilegeSet)); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << "pwd" << "" << "roles" << BSON_ARRAY("frim")))); + ASSERT(user->getActionsForResource("test").empty()); } TEST_F(PrivilegeDocumentParsing, VerifyInvalidRoleStillAllowsOtherRoles) { - ASSERT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("read" << "frim")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "" << + "roles" << BSON_ARRAY("read" << "frim")))); + ASSERT(user->getActionsForResource("test").contains(ActionType::find)); } TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterAdminRoleFromNonAdminDatabase) { - ASSERT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("read" << "clusterAdmin")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::shutdown))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::dropDatabase))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "" << + "roles" << BSON_ARRAY("read" << "clusterAdmin")))); + ASSERT(user->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!user->getActionsForResource("test").contains(ActionType::shutdown)); + ASSERT(!user->getActionsForResource("test").contains(ActionType::dropDatabase)); } TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterReadFromNonAdminDatabase) { - ASSERT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("read" << "readAnyDatabase")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "" << + "roles" << BSON_ARRAY("read" << "readAnyDatabase")))); + ASSERT(user->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!user->getActionsForResource("test2").contains(ActionType::find)); } TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterReadWriteFromNonAdminDatabase) { - ASSERT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("read" << "readWriteAnyDatabase")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::insert))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::insert))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "" << + "roles" << BSON_ARRAY("read" << "readWriteAnyDatabase")))); + ASSERT(user->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!user->getActionsForResource("test").contains(ActionType::insert)); + ASSERT(!user->getActionsForResource("test2").contains(ActionType::insert)); } TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterUserAdminFromNonAdminDatabase) { - ASSERT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("read" << "userAdminAnyDatabase")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "" << + "roles" << BSON_ARRAY("read" << "userAdminAnyDatabase")))); + ASSERT(user->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!user->getActionsForResource("test").contains(ActionType::userAdmin)); + ASSERT(!user->getActionsForResource("test2").contains(ActionType::userAdmin)); } TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantClusterDBAdminFromNonAdminDatabase) { - ASSERT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("read" << "dbAdminAnyDatabase")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::clean))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::clean))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "" << + "roles" << BSON_ARRAY("read" << "dbAdminAnyDatabase")))); + ASSERT(user->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!user->getActionsForResource("test").contains(ActionType::clean)); + ASSERT(!user->getActionsForResource("test2").contains(ActionType::clean)); } TEST_F(PrivilegeDocumentParsing, VerifyOtherDBRolesMustBeAnObjectOfArraysOfStrings) { - ASSERT_NOT_OK(authzManager->buildPrivilegeSet( - "admin", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("read") << - "otherDBRoles" << BSON_ARRAY("read")), - &privilegeSet)); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::find))); - - ASSERT_NOT_OK(authzManager->buildPrivilegeSet( - "admin", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("read") << - "otherDBRoles" << BSON("test2" << "read")), - &privilegeSet)); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::find))); + ASSERT_NOT_OK(authzManager->_initializeUserFromPrivilegeDocument( + adminUser.get(), + BSON("user" << "admin" << + "pwd" << "" << + "roles" << BSON_ARRAY("read") << + "otherDBRoles" << BSON_ARRAY("read")))); + ASSERT(!adminUser->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!adminUser->getActionsForResource("test2").contains(ActionType::find)); + ASSERT(!adminUser->getActionsForResource("admin").contains(ActionType::find)); + + ASSERT_NOT_OK(authzManager->_initializeUserFromPrivilegeDocument( + adminUser.get(), + BSON("user" << "admin" << + "pwd" << "" << + "roles" << BSON_ARRAY("read") << + "otherDBRoles" << BSON("test2" << "read")))); + ASSERT(!adminUser->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!adminUser->getActionsForResource("test2").contains(ActionType::find)); + ASSERT(!adminUser->getActionsForResource("admin").contains(ActionType::find)); } TEST_F(PrivilegeDocumentParsing, VerifyCannotGrantPrivilegesOnOtherDatabasesNormally) { // Cannot grant privileges on other databases, except from admin database. - ASSERT_NOT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("read") << - "otherDBRoles" << BSON("test2" << BSON_ARRAY("read"))), - &privilegeSet)); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find))); + ASSERT_NOT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "" << + "roles" << BSON_ARRAY("read") << + "otherDBRoles" << BSON("test2" << BSON_ARRAY("read"))))); + ASSERT(!user->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!user->getActionsForResource("test2").contains(ActionType::find)); + ASSERT(!user->getActionsForResource("admin").contains(ActionType::find)); } TEST_F(PrivilegeDocumentParsing, SuccessfulSimpleReadGrant) { // Grant read on test. - ASSERT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << "roles" << BSON_ARRAY("read")), - &privilegeSet)); - - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::find))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "" << + "roles" << BSON_ARRAY("read")))); + ASSERT(user->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!user->getActionsForResource("test2").contains(ActionType::find)); + ASSERT(!user->getActionsForResource("admin").contains(ActionType::find)); } TEST_F(PrivilegeDocumentParsing, SuccessfulSimpleUserAdminTest) { // Grant userAdmin on "test" database. - ASSERT_OK(authzManager->buildPrivilegeSet( - "test", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("userAdmin")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::userAdmin))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "" << + "roles" << BSON_ARRAY("userAdmin")))); + ASSERT(user->getActionsForResource("test").contains(ActionType::userAdmin)); + ASSERT(!user->getActionsForResource("test2").contains(ActionType::userAdmin)); + ASSERT(!user->getActionsForResource("admin").contains(ActionType::userAdmin)); } TEST_F(PrivilegeDocumentParsing, GrantUserAdminOnAdmin) { // Grant userAdmin on admin. - ASSERT_OK(authzManager->buildPrivilegeSet( - "admin", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("userAdmin")), - &privilegeSet)); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin))); - ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::userAdmin))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + adminUser.get(), + BSON("user" << "admin" << + "pwd" << "" << + "roles" << BSON_ARRAY("userAdmin")))); + ASSERT(!adminUser->getActionsForResource("test").contains(ActionType::userAdmin)); + ASSERT(!adminUser->getActionsForResource("test2").contains(ActionType::userAdmin)); + ASSERT(adminUser->getActionsForResource("admin").contains(ActionType::userAdmin)); } TEST_F(PrivilegeDocumentParsing, GrantUserAdminOnTestViaAdmin) { // Grant userAdmin on test via admin. - ASSERT_OK(authzManager->buildPrivilegeSet( - "admin", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSONArrayBuilder().arr() << - "otherDBRoles" << BSON("test" << BSON_ARRAY("userAdmin"))), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::userAdmin))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + adminUser.get(), + BSON("user" << "admin" << + "pwd" << "" << + "roles" << BSONArrayBuilder().arr() << + "otherDBRoles" << BSON("test" << BSON_ARRAY("userAdmin"))))); + ASSERT(adminUser->getActionsForResource("test").contains(ActionType::userAdmin)); + ASSERT(!adminUser->getActionsForResource("test2").contains(ActionType::userAdmin)); + ASSERT(!adminUser->getActionsForResource("admin").contains(ActionType::userAdmin)); } TEST_F(PrivilegeDocumentParsing, SuccessfulClusterAdminTest) { // Grant userAdminAnyDatabase. - ASSERT_OK(authzManager->buildPrivilegeSet( - "admin", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("userAdminAnyDatabase")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::userAdmin))); - ASSERT(privilegeSet.hasPrivilege(Privilege("test2", ActionType::userAdmin))); - ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::userAdmin))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + adminUser.get(), + BSON("user" << "admin" << + "pwd" << "" << + "roles" << BSON_ARRAY("userAdminAnyDatabase")))); + ASSERT(adminUser->getActionsForResource("*").contains(ActionType::userAdmin)); } TEST_F(PrivilegeDocumentParsing, GrantClusterReadWrite) { // Grant readWrite on everything via the admin database. - ASSERT_OK(authzManager->buildPrivilegeSet( - "admin", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("readWriteAnyDatabase")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(privilegeSet.hasPrivilege(Privilege("test2", ActionType::find))); - ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::find))); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::insert))); - ASSERT(privilegeSet.hasPrivilege(Privilege("test2", ActionType::insert))); - ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::insert))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + adminUser.get(), + BSON("user" << "admin" << + "pwd" << "" << + "roles" << BSON_ARRAY("readWriteAnyDatabase")))); + ASSERT(adminUser->getActionsForResource("*").contains(ActionType::find)); + ASSERT(adminUser->getActionsForResource("*").contains(ActionType::insert)); } TEST_F(PrivilegeDocumentParsing, ProhibitGrantOnWildcard) { - // Cannot grant readWrite to everythign using "otherDBRoles". - ASSERT_NOT_OK(authzManager->buildPrivilegeSet( - "admin", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSONArrayBuilder().arr() << - "otherDBRoles" << BSON("*" << BSON_ARRAY("readWrite"))), - &privilegeSet)); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::find))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test", ActionType::insert))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("test2", ActionType::insert))); - ASSERT(!privilegeSet.hasPrivilege(Privilege("admin", ActionType::insert))); + // Cannot grant readWrite to everything using "otherDBRoles". + ASSERT_NOT_OK(authzManager->_initializeUserFromPrivilegeDocument( + adminUser.get(), + BSON("user" << "admin" << + "pwd" << "" << + "roles" << BSONArrayBuilder().arr() << + "otherDBRoles" << BSON("*" << BSON_ARRAY("readWrite"))))); + ASSERT(!adminUser->getActionsForResource("test").contains(ActionType::find)); + ASSERT(!adminUser->getActionsForResource("test2").contains(ActionType::find)); + ASSERT(!adminUser->getActionsForResource("admin").contains(ActionType::find)); + ASSERT(!adminUser->getActionsForResource("test").contains(ActionType::insert)); + ASSERT(!adminUser->getActionsForResource("test2").contains(ActionType::insert)); + ASSERT(!adminUser->getActionsForResource("admin").contains(ActionType::insert)); } TEST_F(PrivilegeDocumentParsing, GrantClusterAdmin) { // Grant cluster admin - ASSERT_OK(authzManager->buildPrivilegeSet( - "admin", - user, - BSON("user" << "spencer" << "pwd" << "" << - "roles" << BSON_ARRAY("clusterAdmin")), - &privilegeSet)); - ASSERT(privilegeSet.hasPrivilege(Privilege("test", ActionType::dropDatabase))); - ASSERT(privilegeSet.hasPrivilege(Privilege("test2", ActionType::dropDatabase))); - ASSERT(privilegeSet.hasPrivilege(Privilege("admin", ActionType::dropDatabase))); - ASSERT(privilegeSet.hasPrivilege(Privilege("$SERVER", ActionType::shutdown))); - ASSERT(privilegeSet.hasPrivilege(Privilege("$CLUSTER", ActionType::moveChunk))); + ASSERT_OK(authzManager->_initializeUserFromPrivilegeDocument( + adminUser.get(), + BSON("user" << "admin" << + "pwd" << "" << + "roles" << BSON_ARRAY("clusterAdmin")))); + ASSERT(adminUser->getActionsForResource("*").contains(ActionType::dropDatabase)); + ASSERT(adminUser->getActionsForResource("*").contains(ActionType::shutdown)); + ASSERT(adminUser->getActionsForResource("*").contains(ActionType::moveChunk)); } - TEST_F(AuthorizationManagerTest, GetPrivilegesFromPrivilegeDocumentInvalid) { - BSONObj oldAndNewMixed = BSON("user" << "spencer" << - "pwd" << "passwordHash" << - "readOnly" << false << - "roles" << BSON_ARRAY("write" << "userAdmin")); - - UserName user("spencer", "anydb"); - PrivilegeSet result; - ASSERT_NOT_OK(authzManager->buildPrivilegeSet("anydb", user, oldAndNewMixed, &result)); + TEST_F(PrivilegeDocumentParsing, GetPrivilegesFromPrivilegeDocumentInvalid) { + // Try to mix fields from V0 and V1 privilege documents and make sure it fails. + ASSERT_NOT_OK(authzManager->_initializeUserFromPrivilegeDocument( + user.get(), + BSON("user" << "spencer" << + "pwd" << "passwordHash" << + "readOnly" << false << + "roles" << BSON_ARRAY("read")))); + ASSERT(!adminUser->getActionsForResource("test").contains(ActionType::find)); } TEST_F(AuthorizationManagerTest, DocumentValidationCompatibility) { diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp index 89c9664a11f..02d659a1b6a 100644 --- a/src/mongo/db/auth/authorization_session.cpp +++ b/src/mongo/db/auth/authorization_session.cpp @@ -24,10 +24,7 @@ #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authz_session_external_state.h" #include "mongo/db/auth/authorization_manager.h" -#include "mongo/db/auth/principal.h" -#include "mongo/db/auth/principal_set.h" #include "mongo/db/auth/privilege.h" -#include "mongo/db/auth/privilege_set.h" #include "mongo/db/auth/security_key.h" #include "mongo/db/client.h" #include "mongo/db/jsobj.h" @@ -61,39 +58,6 @@ namespace { _externalState->startRequest(); } - void AuthorizationSession::addAndAuthorizePrincipal(Principal* principal) { - - // Log out any already-logged-in user on the same database as "principal". - logoutDatabase(principal->getName().getDB().toString()); // See SERVER-8144. - - _authenticatedPrincipals.add(principal); - - if (principal->getName() == internalSecurity.user->getName()) { - - // Grant full access to internal user - ActionSet allActions; - allActions.addAllActions(); - acquirePrivilege(Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, allActions), - principal->getName()); - return; - } - - const std::string dbname = principal->getName().getDB().toString(); - _acquirePrivilegesForPrincipalFromDatabase(ADMIN_DBNAME, principal->getName()); - principal->markDatabaseAsProbed(ADMIN_DBNAME); - _acquirePrivilegesForPrincipalFromDatabase(dbname, principal->getName()); - principal->markDatabaseAsProbed(dbname); - _externalState->onAddAuthorizedPrincipal(principal); - } - - void AuthorizationSession::addPrincipal(Principal* principal) { - - // Log out any already-logged-in user on the same database as "principal". - logoutDatabase(principal->getName().getDB().toString()); // See SERVER-8144. - _authenticatedPrincipals.add(principal); - _externalState->onAddAuthorizedPrincipal(principal); - } - Status AuthorizationSession::addAndAuthorizeUser(const UserName& userName) { User* user; Status status = getAuthorizationManager().acquireUser(userName, &user); @@ -108,39 +72,15 @@ namespace { getAuthorizationManager().releaseUser(replacedUser); } + _externalState->onAddAuthorizedUser(); return Status::OK(); } - void AuthorizationSession::_acquirePrivilegesForPrincipalFromDatabase( - const std::string& dbname, const UserName& user) { - - BSONObj privilegeDocument; - Status status = _externalState->getAuthorizationManager().getPrivilegeDocument( - dbname, user, &privilegeDocument); - if (status.isOK()) { - status = acquirePrivilegesFromPrivilegeDocument(dbname, user, privilegeDocument); - } - if (!status.isOK() && status != ErrorCodes::UserNotFound) { - log() << "Privilege acquisition failed for " << user << " in database " << - dbname << ": " << status.reason() << " (" << status.codeString() << ")" << endl; - } - } - - Principal* AuthorizationSession::lookupPrincipal(const UserName& name) { - return _authenticatedPrincipals.lookup(name); - } - User* AuthorizationSession::lookupUser(const UserName& name) { return _authenticatedUsers.lookup(name); } void AuthorizationSession::logoutDatabase(const std::string& dbname) { - Principal* principal = _authenticatedPrincipals.lookupByDBName(dbname); - if (principal) { - _acquiredPrivileges.revokePrivilegesFromUser(principal->getName()); - _authenticatedPrincipals.removeByDBName(dbname); - } - User* removedUser = _authenticatedUsers.removeByDBName(dbname); if (removedUser) { getAuthorizationManager().releaseUser(removedUser); @@ -153,56 +93,15 @@ namespace { return _authenticatedUsers.getNames(); } - Status AuthorizationSession::acquirePrivilege(const Privilege& privilege, - const UserName& authorizingUser) { - if (!_authenticatedPrincipals.lookup(authorizingUser)) { - return Status(ErrorCodes::UserNotFound, - mongoutils::str::stream() - << "No authenticated user found with name: " - << authorizingUser.getUser() - << " from database " - << authorizingUser.getDB(), - 0); - } - _acquiredPrivileges.grantPrivilege(privilege, authorizingUser); - return Status::OK(); - } - void AuthorizationSession::grantInternalAuthorization() { - Principal* principal = new Principal(internalSecurity.user->getName()); - ActionSet actions; - actions.addAllActions(); - - addPrincipal(principal); - fassert(16581, - acquirePrivilege(Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, actions), - principal->getName()).isOK()); - _authenticatedUsers.add(internalSecurity.user); } bool AuthorizationSession::hasInternalAuthorization() { ActionSet allActions; allActions.addAllActions(); - return _acquiredPrivileges.hasPrivilege( - Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, allActions)); - } - - Status AuthorizationSession::acquirePrivilegesFromPrivilegeDocument( - const std::string& dbname, const UserName& user, const BSONObj& privilegeDocument) { - if (!_authenticatedPrincipals.lookup(user)) { - return Status(ErrorCodes::UserNotFound, - mongoutils::str::stream() - << "No authenticated principle found with name: " - << user.getUser() - << " from database " - << user.getDB(), - 0); - } - return _externalState->getAuthorizationManager().buildPrivilegeSet(dbname, - user, - privilegeDocument, - &_acquiredPrivileges); + return _checkAuthForPrivilegeHelper( + Privilege(AuthorizationManager::WILDCARD_RESOURCE_NAME, allActions)).isOK(); } bool AuthorizationSession::checkAuthorization(const std::string& resource, diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h index 01bcff370df..b8f587b8091 100644 --- a/src/mongo/db/auth/authorization_session.h +++ b/src/mongo/db/auth/authorization_session.h @@ -25,10 +25,7 @@ #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/authz_session_external_state.h" -#include "mongo/db/auth/principal.h" -#include "mongo/db/auth/principal_set.h" #include "mongo/db/auth/privilege.h" -#include "mongo/db/auth/privilege_set.h" #include "mongo/db/auth/user_name.h" #include "mongo/db/auth/user_set.h" @@ -56,25 +53,12 @@ namespace mongo { // TODO: try to eliminate the need for this call. void startRequest(); - // Adds "principal" to the authorization session, acquiring privileges for that principal, - // and takes ownership of it. - void addAndAuthorizePrincipal(Principal* principal); - - // Adds "principal" to the authorization session and takes ownership of it, without - // acquiring privileges for it. - void addPrincipal(Principal* principal); - /** * Adds the User identified by "UserName" to the authorization session, acquiring privileges * for it in the process. */ Status addAndAuthorizeUser(const UserName& userName); - // Returns the authenticated principal with the given name. Returns NULL - // if no such user is found. - // Ownership of the returned Principal remains with _authenticatedPrincipals - Principal* lookupPrincipal(const UserName& name); - // Returns the authenticated user with the given name. Returns NULL // if no such user is found. // The user remains in the _authenticatedUsers set for this AuthorizationSession, @@ -88,10 +72,6 @@ namespace mongo { // database, and revokes any privileges that were granted via that principal. void logoutDatabase(const std::string& dbname); - // Grant this connection the given privilege. - Status acquirePrivilege(const Privilege& privilege, - const UserName& authorizingUser); - // Adds the internalSecurity user to the set of authenticated users. // Used to grant internal threads full access. void grantInternalAuthorization(); @@ -109,12 +89,6 @@ namespace mongo { // all of the actions may proceed on the resource. bool checkAuthorization(const std::string& resource, ActionSet actions); - // Parses the privilege documents and acquires all privileges that the privilege document - // grants - Status acquirePrivilegesFromPrivilegeDocument(const std::string& dbname, - const UserName& user, - const BSONObj& privilegeDocument); - // Checks if this connection has the privileges necessary to perform the given query on the // given namespace. Status checkAuthForQuery(const std::string& ns, const BSONObj& query); @@ -151,11 +125,6 @@ namespace mongo { // we should even be doing authorization checks in general. Status _checkAuthForPrivilegeHelper(const Privilege& privilege); - // Finds the set of privileges attributed to "principal" in database "dbname", - // and adds them to the set of acquired privileges. - void _acquirePrivilegesForPrincipalFromDatabase(const std::string& dbname, - const UserName& user); - // 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. @@ -164,10 +133,6 @@ namespace mongo { scoped_ptr<AuthzSessionExternalState> _externalState; - // All the privileges that have been acquired by the authenticated principals. - PrivilegeSet _acquiredPrivileges; - // All principals who have been authenticated on this connection - PrincipalSet _authenticatedPrincipals; // All Users who have been authenticated on this connection UserSet _authenticatedUsers; }; diff --git a/src/mongo/db/auth/authz_session_external_state.h b/src/mongo/db/auth/authz_session_external_state.h index 4e633b3b570..063181615f0 100644 --- a/src/mongo/db/auth/authz_session_external_state.h +++ b/src/mongo/db/auth/authz_session_external_state.h @@ -57,7 +57,7 @@ namespace mongo { // Authorization event hooks // Handle any global state which needs to be updated when a new user has been authorized - virtual void onAddAuthorizedPrincipal(Principal*) = 0; + virtual void onAddAuthorizedUser() = 0; // Handle any global state which needs to be updated when a user logs out virtual void onLogoutDatabase(const std::string& dbname) = 0; diff --git a/src/mongo/db/auth/authz_session_external_state_d.cpp b/src/mongo/db/auth/authz_session_external_state_d.cpp index 03c9306bbc5..1736e827bc2 100644 --- a/src/mongo/db/auth/authz_session_external_state_d.cpp +++ b/src/mongo/db/auth/authz_session_external_state_d.cpp @@ -43,7 +43,7 @@ namespace mongo { return cc().isGod() || AuthzSessionExternalStateServerCommon::shouldIgnoreAuthChecks(); } - void AuthzSessionExternalStateMongod::onAddAuthorizedPrincipal(Principal*) { + void AuthzSessionExternalStateMongod::onAddAuthorizedUser() { // invalidate all thread-local JS scopes due to new user authentication if (globalScriptEngine) globalScriptEngine->threadDone(); diff --git a/src/mongo/db/auth/authz_session_external_state_d.h b/src/mongo/db/auth/authz_session_external_state_d.h index 8e26e2bb518..9cdae29bc1f 100644 --- a/src/mongo/db/auth/authz_session_external_state_d.h +++ b/src/mongo/db/auth/authz_session_external_state_d.h @@ -37,7 +37,7 @@ namespace mongo { virtual void startRequest(); - virtual void onAddAuthorizedPrincipal(Principal*); + virtual void onAddAuthorizedUser(); virtual void onLogoutDatabase(const std::string&); diff --git a/src/mongo/db/auth/authz_session_external_state_mock.h b/src/mongo/db/auth/authz_session_external_state_mock.h index 967c50d78b2..32b76db5bd1 100644 --- a/src/mongo/db/auth/authz_session_external_state_mock.h +++ b/src/mongo/db/auth/authz_session_external_state_mock.h @@ -49,7 +49,7 @@ namespace mongo { virtual void startRequest() {} - virtual void onAddAuthorizedPrincipal(Principal*) {} + virtual void onAddAuthorizedUser() {} virtual void onLogoutDatabase(const std::string& dbname) {} diff --git a/src/mongo/db/auth/authz_session_external_state_s.cpp b/src/mongo/db/auth/authz_session_external_state_s.cpp index 73585453da8..a7c8bb7cbd4 100644 --- a/src/mongo/db/auth/authz_session_external_state_s.cpp +++ b/src/mongo/db/auth/authz_session_external_state_s.cpp @@ -31,7 +31,7 @@ namespace mongo { AuthzSessionExternalStateServerCommon(authzManager) {} AuthzSessionExternalStateMongos::~AuthzSessionExternalStateMongos() {} - void AuthzSessionExternalStateMongos::onAddAuthorizedPrincipal(Principal*) { } + void AuthzSessionExternalStateMongos::onAddAuthorizedUser() { } void AuthzSessionExternalStateMongos::onLogoutDatabase(const std::string&) { } diff --git a/src/mongo/db/auth/authz_session_external_state_s.h b/src/mongo/db/auth/authz_session_external_state_s.h index 8a07eb166c5..c91d2826438 100644 --- a/src/mongo/db/auth/authz_session_external_state_s.h +++ b/src/mongo/db/auth/authz_session_external_state_s.h @@ -35,7 +35,7 @@ namespace mongo { virtual void startRequest(); - virtual void onAddAuthorizedPrincipal(Principal*); + virtual void onAddAuthorizedUser(); virtual void onLogoutDatabase(const std::string&); diff --git a/src/mongo/db/auth/principal.cpp b/src/mongo/db/auth/principal.cpp deleted file mode 100644 index bba850d80c8..00000000000 --- a/src/mongo/db/auth/principal.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2012 10gen Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "mongo/db/auth/principal.h" - -#include <boost/date_time/posix_time/posix_time.hpp> -#include <string> - -#include "mongo/util/map_util.h" - -namespace mongo { - - Principal::Principal(const UserName& name) : - _name(name), - _expirationTime(boost::posix_time::pos_infin) { - } - - Principal::~Principal() {} - - void Principal::setExpirationTime(boost::posix_time::ptime& expiration) { - _expirationTime = expiration; - } - - bool Principal::isDatabaseProbed(const StringData& dbname) const { - return mapFindWithDefault(_probedDatabases, dbname, false); - } - - void Principal::markDatabaseAsProbed(const StringData& dbname) { - _probedDatabases[dbname] = true; - } - -} // namespace mongo diff --git a/src/mongo/db/auth/principal.h b/src/mongo/db/auth/principal.h deleted file mode 100644 index 0ebb502b16a..00000000000 --- a/src/mongo/db/auth/principal.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright 2012 10gen Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <boost/date_time/posix_time/posix_time.hpp> -#include <string> - -#include "mongo/base/disallow_copying.h" -#include "mongo/base/string_data.h" -#include "mongo/db/auth/user_name.h" -#include "mongo/util/string_map.h" - -namespace mongo { - - /** - * Represents an authenticated user. Every principal has a name, a time that the user's - * authentication expires, and a flag that describes whether or not privileges should be - * acquired implicitly. - * - * The implicit privilege acquisition flag defaults to disabled, and the expiration time - * defaults to never. - * - * This class does not do any locking/synchronization, the consumer will be responsible for - * synchronizing access. - */ - class Principal { - MONGO_DISALLOW_COPYING(Principal); - - public: - Principal(const UserName& name, - const boost::posix_time::ptime& expirationTime); - explicit Principal(const UserName& name); - ~Principal(); - - const UserName& getName() const { return _name; } - - // Returns the expiration time of this principal information. - // No expiration is represented as boost::posix_time::pos_infin - const boost::posix_time::ptime& getExpirationTime() const { return _expirationTime; } - - void setExpirationTime(boost::posix_time::ptime& expiration); - - bool isDatabaseProbed(const StringData& dbname) const; - void markDatabaseAsProbed(const StringData& dbname); - - private: - UserName _name; - boost::posix_time::ptime _expirationTime; - StringMap<bool> _probedDatabases; - }; - -} // namespace mongo diff --git a/src/mongo/db/auth/principal_set.cpp b/src/mongo/db/auth/principal_set.cpp deleted file mode 100644 index 48e9be09d79..00000000000 --- a/src/mongo/db/auth/principal_set.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright 2012 10gen Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "mongo/pch.h" - -#include "mongo/db/auth/principal_set.h" - -#include <boost/date_time/posix_time/posix_time.hpp> -#include <string> -#include <vector> - -#include "mongo/db/auth/principal.h" -#include "mongo/util/mongoutils/str.h" - -namespace mongo { - - PrincipalSet::PrincipalSet() {} - PrincipalSet::~PrincipalSet() { - for (std::vector<Principal*>::iterator it = _principals.begin(); - it != _principals.end(); ++it) { - delete *it; - } - } - - void PrincipalSet::add(Principal* principal) { - for (std::vector<Principal*>::iterator it = _principals.begin(); - it != _principals.end(); ++it) { - Principal* current = *it; - if (current->getName().getDB() == principal->getName().getDB()) { - // There can be only one principal per database. - delete current; - *it = principal; - return; - } - } - _principals.push_back(principal); - } - - void PrincipalSet::removeByDBName(const StringData& dbname) { - for (std::vector<Principal*>::iterator it = _principals.begin(); - it != _principals.end(); ++it) { - Principal* current = *it; - if (current->getName().getDB() == dbname) { - delete current; - _principals.erase(it); - break; - } - } - } - - Principal* PrincipalSet::lookup(const UserName& name) const { - Principal* principal = lookupByDBName(name.getDB()); - if (principal && principal->getName() == name) { - return principal; - } - return NULL; - } - - Principal* PrincipalSet::lookupByDBName(const StringData& dbname) const { - for (std::vector<Principal*>::const_iterator it = _principals.begin(); - it != _principals.end(); ++it) { - Principal* current = *it; - if (current->getName().getDB() == dbname) { - return current; - } - } - return NULL; - } - -} // namespace mongo diff --git a/src/mongo/db/auth/principal_set.h b/src/mongo/db/auth/principal_set.h deleted file mode 100644 index 90a1c6d8e56..00000000000 --- a/src/mongo/db/auth/principal_set.h +++ /dev/null @@ -1,106 +0,0 @@ -/* Copyright 2012 10gen Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <string> -#include <vector> - -#include "mongo/base/disallow_copying.h" -#include "mongo/base/string_data.h" -#include "mongo/db/auth/principal.h" -#include "mongo/db/auth/user_name.h" - -namespace mongo { - - /** - * A collection of authenticated principals. - * This class does not do any locking/synchronization, the consumer will be responsible for - * synchronizing access. - */ - class PrincipalSet { - MONGO_DISALLOW_COPYING(PrincipalSet); - public: - typedef std::vector<Principal*>::const_iterator iterator; - - /** - * Forward iterator over the names of the principals stored in a PrincipalSet. - * - * Instances are valid until the underlying vector<Principal*> is modified. - * - * more() must be the first method called after construction, and must be checked - * after each call to next() before calling any other methods. - */ - class NameIterator { - public: - explicit NameIterator(const std::vector<Principal*>& principals) : - _curr(principals.begin()), - _end(principals.end()) { - } - - NameIterator() {} - - bool more() { return _curr != _end; } - const UserName& next() { - const UserName& ret = get(); - ++_curr; - return ret; - } - - const UserName& get() const { return (*_curr)->getName(); } - - const UserName& operator*() const { return get(); } - const UserName* operator->() const { return &get(); } - - private: - std::vector<Principal*>::const_iterator _curr; - std::vector<Principal*>::const_iterator _end; - }; - - PrincipalSet(); - ~PrincipalSet(); - - // If the principal is already present, this will replace the existing entry. - // The PrincipalSet takes ownership of the passed-in principal and is responsible for - // deleting it eventually - void add(Principal* principal); - - // Removes all principals whose authentication credentials came from dbname. - void removeByDBName(const StringData& dbname); - - // Returns the Principal with the given name, or NULL if not found. - // Ownership of the returned Principal remains with the PrincipalSet. The pointer - // returned is only guaranteed to remain valid until the next non-const method is called - // on the PrincipalSet. - Principal* lookup(const UserName& name) const; - - // Gets the principal whose authentication credentials came from dbname, or NULL if none - // exist. There should be at most one such principal. - Principal* lookupByDBName(const StringData& dbname) const; - - // Gets an iterator over the names of the principals stored in the set. The iterator is - // valid until the next non-const method is called on the PrincipalSet. - NameIterator getNames() const { return NameIterator(_principals); } - - iterator begin() const { return _principals.begin(); } - iterator end() const { return _principals.end(); } - - private: - // The PrincipalSet maintains ownership of the Principals in it, and is responsible for - // deleting them when done with them. - std::vector<Principal*> _principals; - }; - -} // namespace mongo diff --git a/src/mongo/db/auth/principal_set_test.cpp b/src/mongo/db/auth/principal_set_test.cpp deleted file mode 100644 index 7ed30d2930a..00000000000 --- a/src/mongo/db/auth/principal_set_test.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright 2012 10gen Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Unit tests of the PrincipalSet type. - */ - -#include "mongo/db/auth/principal_set.h" -#include "mongo/db/auth/principal.h" -#include "mongo/db/auth/user_name.h" -#include "mongo/unittest/unittest.h" - -#define ASSERT_NULL(EXPR) ASSERT_FALSE((EXPR)) - -namespace mongo { - - static inline std::ostream& operator<<(std::ostream& os, const UserName& uname) { - return os << uname.toString(); - } - -namespace { - - TEST(PrincipalSetTest, BasicTest) { - PrincipalSet set; - - Principal* p1 = new Principal(UserName("Bob", "test")); - Principal* p2 = new Principal(UserName("George", "test")); - Principal* p3 = new Principal(UserName("Bob", "test2")); - - ASSERT_NULL(set.lookup(UserName("Bob", "test"))); - ASSERT_NULL(set.lookup(UserName("George", "test"))); - ASSERT_NULL(set.lookup(UserName("Bob", "test2"))); - ASSERT_NULL(set.lookupByDBName("test")); - ASSERT_NULL(set.lookupByDBName("test2")); - - set.add(p1); - - ASSERT_EQUALS(p1, set.lookup(UserName("Bob", "test"))); - ASSERT_EQUALS(p1, set.lookupByDBName("test")); - ASSERT_NULL(set.lookup(UserName("George", "test"))); - ASSERT_NULL(set.lookup(UserName("Bob", "test2"))); - ASSERT_NULL(set.lookupByDBName("test2")); - - // This should not replace the existing user "Bob" because they are different databases - set.add(p3); - - ASSERT_EQUALS(p1, set.lookup(UserName("Bob", "test"))); - ASSERT_EQUALS(p1, set.lookupByDBName("test")); - ASSERT_NULL(set.lookup(UserName("George", "test"))); - ASSERT_EQUALS(p3, set.lookup(UserName("Bob", "test2"))); - ASSERT_EQUALS(p3, set.lookupByDBName("test2")); - - set.add(p2); // This should replace Bob since they're on the same database - - ASSERT_NULL(set.lookup(UserName("Bob", "test"))); - ASSERT_EQUALS(p2, set.lookup(UserName("George", "test"))); - ASSERT_EQUALS(p2, set.lookupByDBName("test")); - ASSERT_EQUALS(p3, set.lookup(UserName("Bob", "test2"))); - ASSERT_EQUALS(p3, set.lookupByDBName("test2")); - - set.removeByDBName("test"); - - ASSERT_NULL(set.lookup(UserName("Bob", "test"))); - ASSERT_NULL(set.lookup(UserName("George", "test"))); - ASSERT_NULL(set.lookupByDBName("test")); - ASSERT_EQUALS(p3, set.lookup(UserName("Bob", "test2"))); - ASSERT_EQUALS(p3, set.lookupByDBName("test2")); - } - - TEST(PrincipalSetTest, IterateNames) { - PrincipalSet pset; - PrincipalSet::NameIterator iter = pset.getNames(); - ASSERT(!iter.more()); - - pset.add(new Principal(UserName("bob", "test"))); - - iter = pset.getNames(); - ASSERT(iter.more()); - ASSERT_EQUALS(*iter, UserName("bob", "test")); - ASSERT_EQUALS(iter.next(), UserName("bob", "test")); - ASSERT(!iter.more()); - } - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/auth/privilege.cpp b/src/mongo/db/auth/privilege.cpp index d1797473aad..b048af41777 100644 --- a/src/mongo/db/auth/privilege.cpp +++ b/src/mongo/db/auth/privilege.cpp @@ -19,7 +19,6 @@ #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" -#include "mongo/db/auth/principal.h" namespace mongo { diff --git a/src/mongo/db/auth/privilege.h b/src/mongo/db/auth/privilege.h index 0b113c7ff56..114e5315da2 100644 --- a/src/mongo/db/auth/privilege.h +++ b/src/mongo/db/auth/privilege.h @@ -20,7 +20,6 @@ #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" -#include "mongo/db/auth/principal.h" namespace mongo { diff --git a/src/mongo/db/auth/privilege_set.cpp b/src/mongo/db/auth/privilege_set.cpp deleted file mode 100644 index fa555226255..00000000000 --- a/src/mongo/db/auth/privilege_set.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright 2012 10gen Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "mongo/pch.h" - -#include "mongo/db/auth/privilege_set.h" - -#include <map> -#include <string> - -#include "mongo/db/auth/action_set.h" -#include "mongo/db/auth/action_type.h" -#include "mongo/db/auth/principal.h" -#include "mongo/db/namespace_string.h" -#include "mongo/util/map_util.h" - -namespace mongo { - - PrivilegeSet::PrivilegeSet() {} - PrivilegeSet::~PrivilegeSet() {} - - void PrivilegeSet::grantPrivilege(const Privilege& privilege, - const UserName& authorizingUser) { - grantPrivileges(std::vector<Privilege>(1, privilege), authorizingUser); - } - - void PrivilegeSet::grantPrivileges(const std::vector<Privilege>& privileges, - const UserName& authorizingUser) { - StringMap<ActionSet>& byResourceForUser = _byUser[authorizingUser]; - for (std::vector<Privilege>::const_iterator iter = privileges.begin(), - end = privileges.end(); - iter != end; ++iter) { - - byResourceForUser[iter->getResource()].addAllActionsFromSet(iter->getActions()); - - ResourcePrivilegeCacheEntry* entry = _lookupOrInsertEntry(iter->getResource()); - entry->actions.addAllActionsFromSet(iter->getActions()); - } - } - - void PrivilegeSet::revokePrivilegesFromUser(const UserName& user) { - UserPrivilegeMap::iterator userEntry = _byUser.find(user); - if (userEntry == _byUser.end()) - return; - - // For every resource that "user" authorizes, mark its entry in the _byResource table - // as dirty, so that it will be rebuilt on next consultation. - for (StringMap<ActionSet>::const_iterator resourceEntry = userEntry->second.begin(), - end = userEntry->second.end(); - resourceEntry != end; ++resourceEntry) { - - _lookupOrInsertEntry(resourceEntry->first)->dirty = true; - } - - // Remove the user from the _byUser table. - _byUser.erase(userEntry); - } - - bool PrivilegeSet::hasPrivilege(const Privilege& desiredPrivilege) { - if (desiredPrivilege.getActions().empty()) - return true; - - StringData resourceSearchList[2]; - resourceSearchList[0] = "*"; - resourceSearchList[1] = nsToDatabaseSubstring(desiredPrivilege.getResource()); - - ActionSet unmetRequirements = desiredPrivilege.getActions(); - for (int i = 0; i < static_cast<int>(boost::size(resourceSearchList)); ++i) { - ResourcePrivilegeCacheEntry* entry = _lookupEntry(resourceSearchList[i]); - if (NULL == entry) - continue; - if (entry->dirty) - _rebuildEntry(resourceSearchList[i], entry); - unmetRequirements.removeAllActionsFromSet(entry->actions); - if (unmetRequirements.empty()) - return true; - } - return false; - } - - bool PrivilegeSet::hasPrivileges(const std::vector<Privilege>& desiredPrivileges) { - for (std::vector<Privilege>::const_iterator iter = desiredPrivileges.begin(), - end = desiredPrivileges.end(); - iter != end; ++iter) { - - if (!hasPrivilege(*iter)) - return false; - } - return true; - } - - void PrivilegeSet::_rebuildEntry(const StringData& resource, - ResourcePrivilegeCacheEntry* entry) { - const ActionSet emptyActionSet; - entry->actions.removeAllActions(); - - for (UserPrivilegeMap::const_iterator iter = _byUser.begin(), - end = _byUser.end(); - iter != end; ++iter) { - - entry->actions.addAllActionsFromSet( - mapFindWithDefault(iter->second, resource, emptyActionSet)); - } - - entry->dirty = false; - } - - PrivilegeSet::ResourcePrivilegeCacheEntry* PrivilegeSet::_lookupEntry( - const StringData& resource) { - - if (resource == "*") - return &_globalPrivilegeEntry; - - ResourcePrivilegeCache::const_iterator iter = _byResource.find(resource); - if (iter != _byResource.end()) { - // StringMap doesn't have non-const iterators, so there is no way to lookup without - // inserting and get a mutable value, without const-cast. - return const_cast<ResourcePrivilegeCacheEntry*>(&iter->second); - } - return NULL; - } - - PrivilegeSet::ResourcePrivilegeCacheEntry* PrivilegeSet::_lookupOrInsertEntry( - const StringData& resource) { - - if (resource == "*") - return &_globalPrivilegeEntry; - return &_byResource[resource]; - } - -} // namespace mongo diff --git a/src/mongo/db/auth/privilege_set.h b/src/mongo/db/auth/privilege_set.h deleted file mode 100644 index 209bbb5086a..00000000000 --- a/src/mongo/db/auth/privilege_set.h +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright 2012 10gen Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include <map> -#include <string> - -#include "mongo/base/disallow_copying.h" -#include "mongo/db/auth/action_set.h" -#include "mongo/db/auth/action_type.h" -#include "mongo/db/auth/privilege.h" -#include "mongo/db/auth/user_name.h" -#include "mongo/util/string_map.h" - -namespace mongo { - - /** - * A collection of privileges describing which authenticated users bestow the client the - * ability to perform various actions on specific resources. Since every privilege comes from - * an authenticated user, removing that user removes all privileges granted by that - * user. - * - * Resources are arranged hierarchically, with a wildcard resource, - * PrivilegeSet::WILDCARD_RESOURCE, matching any resource. In the current implementation, the - * only two levels of the hierarchy are the wildcard and one level below, which is analagous to - * the name of a database. It is future work to support collection or other sub-database - * resources. - * - * This class does not do any locking/synchronization, the consumer will be responsible for - * synchronizing access. - */ - class PrivilegeSet { - MONGO_DISALLOW_COPYING(PrivilegeSet); - public: - PrivilegeSet(); - ~PrivilegeSet(); - - /** - * Adds the specified privilege to the set, associating it with the named user. - * - * The privilege should be on a specific resource, or on the WILDCARD_RESOURCE. - */ - void grantPrivilege(const Privilege& privilege, const UserName& authorizingUser); - - /** - * Adds the specified privileges to the set, associating them with the named user. - */ - void grantPrivileges(const std::vector<Privilege>& privileges, - const UserName& authorizingUser); - - /** - * Removes from the set all privileges associated with the given user. - * - * If multiple users enable the same privilege, the set will continue to - * contain those privileges until all authorizing users have had their - * privileges revoked from the set. - */ - void revokePrivilegesFromUser(const UserName& user); - - /** - * Returns true if the set authorizes "desiredPrivilege". - * - * The set is considered to authorize "desiredPrivilege" if each action in - * "desiredPrivilege" is satisfied either on the database component of - * "desiredPrivilege.getResource()" or on WILDCARD_RESOURCE. - * - * TODO: Support checking for the privilege on the full resource name as well as the - * database component, to support sub-database granularity privilege assignment. - */ - bool hasPrivilege(const Privilege& desiredPrivilege); - - /** - * Same as hasPrivilege, except checks all the privileges in a vector. - */ - bool hasPrivileges(const std::vector<Privilege>& desiredPrivileges); - - private: - - /** - * Information about privileges held on a resource. - * - * Instances are stored in the _byResource map, and accelerate the fast path of - * hasPrivilege(). Privilege revocations via revokePrivilegesFromUser() can make these - * entries invalid, at which point they are marked "dirty". Dirty entries are rebuilt via - * _rebuildEntry(), below, during execution of hasPrivilege(). - */ - class ResourcePrivilegeCacheEntry { - public: - ResourcePrivilegeCacheEntry() : actions(), dirty(false) {} - - // All actions enabled on the associated resource, provided that "dirty" is false. - ActionSet actions; - - // False if this data is consistent with the full privilege information, stored in the - // _byUser map. - bool dirty; - }; - - /** - * Type of map from resource names to authorized actions. - */ - typedef StringMap<ResourcePrivilegeCacheEntry> ResourcePrivilegeCache; - - /** - * Type of map from user identity to information about the user's privileges. The - * values in the map are themselves maps from resource names to associated actions. - */ - typedef std::map<UserName, StringMap<ActionSet> > UserPrivilegeMap; - - void _rebuildEntry(const StringData& resource, ResourcePrivilegeCacheEntry* summary); - - ResourcePrivilegeCacheEntry* _lookupEntry(const StringData& resource); - ResourcePrivilegeCacheEntry* _lookupOrInsertEntry(const StringData& resource); - - // Information about privileges available on all resources. - ResourcePrivilegeCacheEntry _globalPrivilegeEntry; - - // Cache of privilege information, by resource. - ResourcePrivilegeCache _byResource; - - // Directory of privilege information, by user. - UserPrivilegeMap _byUser; - }; - -} // namespace mongo diff --git a/src/mongo/db/auth/privilege_set_test.cpp b/src/mongo/db/auth/privilege_set_test.cpp deleted file mode 100644 index 235fb7f6b7d..00000000000 --- a/src/mongo/db/auth/privilege_set_test.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* Copyright 2012 10gen Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Unit tests of the PrivilegeSet type. - */ - -#include <iostream> - -#include "mongo/db/auth/action_set.h" -#include "mongo/db/auth/privilege_set.h" -#include "mongo/unittest/unittest.h" - -namespace mongo { -namespace { - - // Convenience methods for outputting UserName and construction ActionSets that make tests - // concise, but that we're reluctant to put into the types themselves. - - std::ostream& operator<<(std::ostream& os, const UserName& uname) { - return os << uname.toString(); - } - - std::ostream& operator<<(std::ostream&os, const std::vector<UserName>& ps) { - os << "[ "; - for (size_t i = 0; i < ps.size(); ++i) - os << ps[i] << ' '; - os << ']'; - return os; - } - - ActionSet operator|(const ActionSet& lhs, const ActionSet& rhs) { - ActionSet result = lhs; - result.addAllActionsFromSet(rhs); - return result; - } - - ActionSet operator|(const ActionSet& lhs, const ActionType& rhs) { - ActionSet result = lhs; - result.addAction(rhs); - return result; - } - - ActionSet operator|(const ActionType& lhs, const ActionType& rhs) { - ActionSet result; - result.addAction(lhs); - result.addAction(rhs); - return result; - } - - // Tests - - TEST(PrivilegeSetTest, PrivilegeSet) { - PrivilegeSet capSet; - UserName user1("user1", "test"); - UserName user2("user2", "test2"); - - // Initially, the capability set contains no privileges at all. - ASSERT_FALSE(capSet.hasPrivilege(Privilege("foo", ActionType::find))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("bar", ActionType::find))); - - // Grant find and update to "foo", only. - capSet.grantPrivilege(Privilege("foo", ActionType::find|ActionType::update), user1); - - ASSERT_TRUE(capSet.hasPrivilege(Privilege("foo", ActionType::find))); - ASSERT_TRUE(capSet.hasPrivilege(Privilege("foo", ActionType::find|ActionType::update))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("foo", ActionType::find|ActionType::remove))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("bar", ActionType::find))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("foo", ActionType::remove))); - - // Grant "userAdmin", "update" and "remove" on "foo" to user2, which changes the set of - // actions this privilege set will approve. - capSet.grantPrivilege( - Privilege("foo", ActionType::userAdmin|ActionType::update|ActionType::remove), - user2); - - ASSERT_TRUE(capSet.hasPrivilege(Privilege("foo", ActionType::userAdmin))); - ASSERT_TRUE(capSet.hasPrivilege(Privilege("foo", ActionType::update))); - ASSERT_TRUE(capSet.hasPrivilege(Privilege("foo", ActionType::userAdmin))); - ASSERT_TRUE(capSet.hasPrivilege(Privilege("foo", ActionType::find|ActionType::remove))); - - // Revoke user2's privileges. - capSet.revokePrivilegesFromUser(user2); - - ASSERT_FALSE(capSet.hasPrivilege(Privilege("foo", ActionType::userAdmin))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("foo", ActionType::find|ActionType::remove))); - ASSERT_TRUE(capSet.hasPrivilege(Privilege("foo", ActionType::update))); - - // Revoke user2's privileges again; should be a no-op. - capSet.revokePrivilegesFromUser(user2); - - ASSERT_FALSE(capSet.hasPrivilege(Privilege("foo", ActionType::userAdmin))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("foo", ActionType::find|ActionType::remove))); - ASSERT_TRUE(capSet.hasPrivilege(Privilege("foo", ActionType::update))); - - // Re-grant "userAdmin", "update" and "remove" on "foo" to user2. - capSet.grantPrivilege( - Privilege("foo", ActionType::userAdmin|ActionType::update|ActionType::remove), - user2); - - // The set still contains no capabilities on "bar". - ASSERT_FALSE(capSet.hasPrivilege(Privilege("bar", ActionType::find))); - - // Let user2 "find" on "bar". - capSet.grantPrivilege(Privilege("bar", ActionType::find), user2); - - ASSERT_TRUE(capSet.hasPrivilege(Privilege("bar", ActionType::find))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("bar", ActionType::update))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("bar", ActionType::remove))); - - // Let user1 "find" and "update" on "bar". - capSet.grantPrivilege(Privilege("bar", ActionType::update|ActionType::find), user1); - - ASSERT_TRUE(capSet.hasPrivilege(Privilege("bar", ActionType::find|ActionType::update))); - ASSERT_FALSE(capSet.hasPrivilege( - Privilege("bar", - ActionType::find|ActionType::update|ActionType::remove))); - - // Revoke user1's privileges. - capSet.revokePrivilegesFromUser(user1); - - ASSERT_TRUE(capSet.hasPrivilege(Privilege("foo", ActionType::update))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("foo", ActionType::find))); - ASSERT_TRUE(capSet.hasPrivilege(Privilege("bar", ActionType::find))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("bar", ActionType::update))); - - // Revoke user2's privileges. - capSet.revokePrivilegesFromUser(user2); - - ASSERT_FALSE(capSet.hasPrivilege(Privilege("foo", ActionType::update))); - ASSERT_FALSE(capSet.hasPrivilege(Privilege("bar", ActionType::find))); - } - - TEST(PrivilegeSetTest, WildcardPrivileges) { - // Tests acquisition and revocation of privileges on WILDCARD_RESOURCE. - - PrivilegeSet privSet; - - UserName user("user", "db"); - Privilege wildcardFind("*", ActionType::find); - Privilege wildcardUpdate("*", ActionType::update); - Privilege wildcardFindAndUpdate("*", ActionType::find|ActionType::update); - Privilege fooFind("foo", ActionType::find); - Privilege fooUpdate("foo", ActionType::update); - Privilege fooFindAndUpdate("foo", ActionType::find|ActionType::update); - Privilege barFind("bar", ActionType::find); - Privilege barUpdate("bar", ActionType::update); - Privilege barFindAndUpdate("bar", ActionType::find|ActionType::update); - - // With no granted privileges, assert that hasPrivilege returns false. - ASSERT_FALSE(privSet.hasPrivilege(wildcardFind)); - ASSERT_FALSE(privSet.hasPrivilege(wildcardUpdate)); - ASSERT_FALSE(privSet.hasPrivilege(wildcardFindAndUpdate)); - - ASSERT_FALSE(privSet.hasPrivilege(fooFind)); - ASSERT_FALSE(privSet.hasPrivilege(fooUpdate)); - ASSERT_FALSE(privSet.hasPrivilege(fooFindAndUpdate)); - - ASSERT_FALSE(privSet.hasPrivilege(barFind)); - ASSERT_FALSE(privSet.hasPrivilege(barUpdate)); - ASSERT_FALSE(privSet.hasPrivilege(barFindAndUpdate)); - - // Grant some privileges, and ensure that exactly those privileges are granted. - std::vector<Privilege> grantedPrivileges; - grantedPrivileges.push_back(wildcardFind); - grantedPrivileges.push_back(fooUpdate); - - privSet.grantPrivileges(grantedPrivileges, user); - - ASSERT_TRUE(privSet.hasPrivilege(wildcardFind)); - ASSERT_FALSE(privSet.hasPrivilege(wildcardUpdate)); - ASSERT_FALSE(privSet.hasPrivilege(wildcardFindAndUpdate)); - - ASSERT_TRUE(privSet.hasPrivilege(fooFind)); - ASSERT_TRUE(privSet.hasPrivilege(fooUpdate)); - ASSERT_TRUE(privSet.hasPrivilege(fooFindAndUpdate)); - - ASSERT_TRUE(privSet.hasPrivilege(barFind)); - ASSERT_FALSE(privSet.hasPrivilege(barUpdate)); - ASSERT_FALSE(privSet.hasPrivilege(barFindAndUpdate)); - - // Revoke the granted privileges, and assert that hasPrivilege returns false. - privSet.revokePrivilegesFromUser(user); - - ASSERT_FALSE(privSet.hasPrivilege(wildcardFind)); - ASSERT_FALSE(privSet.hasPrivilege(wildcardUpdate)); - ASSERT_FALSE(privSet.hasPrivilege(wildcardFindAndUpdate)); - - ASSERT_FALSE(privSet.hasPrivilege(fooFind)); - ASSERT_FALSE(privSet.hasPrivilege(fooUpdate)); - ASSERT_FALSE(privSet.hasPrivilege(fooFindAndUpdate)); - - ASSERT_FALSE(privSet.hasPrivilege(barFind)); - ASSERT_FALSE(privSet.hasPrivilege(barUpdate)); - ASSERT_FALSE(privSet.hasPrivilege(barFindAndUpdate)); - } - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp index 2c15d76c393..8b84f3639ad 100644 --- a/src/mongo/db/commands/authentication_commands.cpp +++ b/src/mongo/db/commands/authentication_commands.cpp @@ -225,8 +225,6 @@ namespace mongo { AuthorizationSession* authorizationSession = ClientBasic::getCurrent()->getAuthorizationSession(); - Principal* principal = new Principal(user); - authorizationSession->addAndAuthorizePrincipal(principal); status = authorizationSession->addAndAuthorizeUser(user); if (!status.isOK()) { return status; diff --git a/src/mongo/db/dbeval.cpp b/src/mongo/db/dbeval.cpp index 97c430fcf3a..94b80c796f3 100644 --- a/src/mongo/db/dbeval.cpp +++ b/src/mongo/db/dbeval.cpp @@ -24,7 +24,6 @@ #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/authorization_manager_global.h" #include "mongo/db/auth/authorization_session.h" -#include "mongo/db/auth/privilege_set.h" #include "mongo/db/cmdline.h" #include "mongo/db/commands.h" #include "mongo/db/introspect.h" diff --git a/src/mongo/db/dbwebserver.cpp b/src/mongo/db/dbwebserver.cpp index 3006c96d98d..2c6311d463a 100644 --- a/src/mongo/db/dbwebserver.cpp +++ b/src/mongo/db/dbwebserver.cpp @@ -30,7 +30,6 @@ #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/authorization_manager_global.h" #include "mongo/db/auth/authorization_session.h" -#include "mongo/db/auth/principal.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/auth/user_name.h" #include "mongo/db/background.h" diff --git a/src/mongo/db/repl/rs.cpp b/src/mongo/db/repl/rs.cpp index 9521be707ed..01a552be5d9 100644 --- a/src/mongo/db/repl/rs.cpp +++ b/src/mongo/db/repl/rs.cpp @@ -20,7 +20,6 @@ #include "mongo/base/status.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/authorization_session.h" -#include "mongo/db/auth/principal.h" #include "mongo/db/client.h" #include "mongo/db/cmdline.h" #include "mongo/db/dbhelpers.h" |