diff options
author | Spencer T Brody <spencer@10gen.com> | 2013-10-17 20:12:21 -0400 |
---|---|---|
committer | Spencer T Brody <spencer@10gen.com> | 2013-10-21 17:22:16 -0400 |
commit | 4e5bb06c7156a2a6e7bf878f3cf2c90a94771b2d (patch) | |
tree | 2fbf3eb990490d022c1ead9ac12540d514238fd9 /src/mongo | |
parent | b67de10c6307468636b91fddd5d67b066f86b526 (diff) | |
download | mongo-4e5bb06c7156a2a6e7bf878f3cf2c90a94771b2d.tar.gz |
SERVER-11260 Remove all code related to advanced role delegation
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/audit.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/audit.h | 4 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager_test.cpp | 91 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_d.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/auth/user.cpp | 31 | ||||
-rw-r--r-- | src/mongo/db/auth/user.h | 33 | ||||
-rw-r--r-- | src/mongo/db/auth/user_document_parser.cpp | 52 | ||||
-rw-r--r-- | src/mongo/db/auth/user_document_parser.h | 5 | ||||
-rw-r--r-- | src/mongo/db/auth/user_document_parser_test.cpp | 65 | ||||
-rw-r--r-- | src/mongo/db/auth/user_management_commands_parser.cpp | 61 | ||||
-rw-r--r-- | src/mongo/db/auth/user_management_commands_parser.h | 2 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.cpp | 151 |
13 files changed, 158 insertions, 379 deletions
diff --git a/src/mongo/db/audit.cpp b/src/mongo/db/audit.cpp index 2355f7cb81d..7389b49db1e 100644 --- a/src/mongo/db/audit.cpp +++ b/src/mongo/db/audit.cpp @@ -104,7 +104,7 @@ namespace audit { const UserName& username, bool password, const BSONObj* customData, - const std::vector<User::RoleData>& roles) MONGO_AUDIT_STUB + const std::vector<RoleName>& roles) MONGO_AUDIT_STUB void logDropUser(ClientBasic* client, const UserName& username) MONGO_AUDIT_STUB @@ -116,7 +116,7 @@ namespace audit { const UserName& username, bool password, const BSONObj* customData, - const std::vector<User::RoleData>* roles) MONGO_AUDIT_STUB + const std::vector<RoleName>* roles) MONGO_AUDIT_STUB void logGrantRolesToUser(ClientBasic* client, const UserName& username, diff --git a/src/mongo/db/audit.h b/src/mongo/db/audit.h index d9e589d89c4..b879b84fdd1 100644 --- a/src/mongo/db/audit.h +++ b/src/mongo/db/audit.h @@ -163,7 +163,7 @@ namespace audit { const UserName& username, bool password, const BSONObj* customData, - const std::vector<User::RoleData>& roles); + const std::vector<RoleName>& roles); /** * Logs the result of a dropUser command. @@ -184,7 +184,7 @@ namespace audit { const UserName& username, bool password, const BSONObj* customData, - const std::vector<User::RoleData>* roles); + const std::vector<RoleName>* roles); /** * Logs the result of a grantRolesToUser command. diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp index c0fd77a6852..75875b5fe78 100644 --- a/src/mongo/db/auth/authorization_manager.cpp +++ b/src/mongo/db/auth/authorization_manager.cpp @@ -391,13 +391,10 @@ namespace mongo { } static void _initializeUserPrivilegesFromRolesV1(User* user) { - const User::RoleDataMap& roles = user->getRoles(); PrivilegeVector privileges; - for (User::RoleDataMap::const_iterator it = roles.begin(); it != roles.end(); ++it) { - const User::RoleData& role= it->second; - if (role.hasRole) { - RoleGraph::addPrivilegesForBuiltinRole(role.name, &privileges); - } + RoleNameIterator roles = user->getRoles(); + while(roles.more()) { + RoleGraph::addPrivilegesForBuiltinRole(roles.next(), &privileges); } user->addPrivileges(privileges); } @@ -668,14 +665,12 @@ namespace mongo { } BSONArrayBuilder rolesArray(builder.subarrayStart("roles")); - const User::RoleDataMap& roles = user.getRoles(); - for (User::RoleDataMap::const_iterator it = roles.begin(); it != roles.end(); ++it) { - const User::RoleData& role = it->second; + RoleNameIterator roles = user.getRoles(); + while(roles.more()) { + const RoleName& role = roles.next(); BSONObjBuilder roleBuilder(rolesArray.subobjStart()); - roleBuilder.append(AuthorizationManager::USER_NAME_FIELD_NAME, role.name.getRole()); - roleBuilder.append(AuthorizationManager::USER_SOURCE_FIELD_NAME, role.name.getDB()); - roleBuilder.appendBool("canDelegate", role.canDelegate); - roleBuilder.appendBool("hasRole", role.hasRole); + roleBuilder.append(AuthorizationManager::USER_NAME_FIELD_NAME, role.getRole()); + roleBuilder.append(AuthorizationManager::USER_SOURCE_FIELD_NAME, role.getDB()); roleBuilder.doneFast(); } rolesArray.doneFast(); diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp index 334eae3c79a..6199048dc6b 100644 --- a/src/mongo/db/auth/authorization_manager_test.cpp +++ b/src/mongo/db/auth/authorization_manager_test.cpp @@ -174,12 +174,9 @@ namespace { ASSERT_EQUALS(UserName("v0RW", "test"), v0RW->getName()); ASSERT(v0RW->isValid()); ASSERT_EQUALS(1U, v0RW->getRefCount()); - const User::RoleDataMap& roles = v0RW->getRoles(); - ASSERT_EQUALS(1U, roles.size()); - User::RoleData role = roles.begin()->second; - ASSERT_EQUALS(RoleName("dbOwner", "test"), role.name); - ASSERT(role.hasRole); - ASSERT(!role.canDelegate); + RoleNameIterator roles = v0RW->getRoles(); + ASSERT_EQUALS(RoleName("dbOwner", "test"), roles.next()); + ASSERT_FALSE(roles.more()); // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(v0RW); @@ -188,12 +185,9 @@ namespace { ASSERT(UserName("v0AdminRO", "admin") == v0AdminRO->getName()); ASSERT(v0AdminRO->isValid()); ASSERT_EQUALS((uint32_t)1, v0AdminRO->getRefCount()); - const User::RoleDataMap& adminRoles = v0AdminRO->getRoles(); - ASSERT_EQUALS(1U, adminRoles.size()); - role = adminRoles.begin()->second; - ASSERT_EQUALS(RoleName("readAnyDatabase", "admin"), role.name); - ASSERT(role.hasRole); - ASSERT(!role.canDelegate); + RoleNameIterator adminRoles = v0AdminRO->getRoles(); + ASSERT_EQUALS(RoleName("readAnyDatabase", "admin"), adminRoles.next()); + ASSERT_FALSE(adminRoles.more()); // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(v0AdminRO); } @@ -219,12 +213,9 @@ namespace { ASSERT(v1read->isValid()); ASSERT_EQUALS((uint32_t)1, v1read->getRefCount()); - const User::RoleDataMap& roles = v1read->getRoles(); - ASSERT_EQUALS(1U, roles.size()); - User::RoleData role = roles.begin()->second; - ASSERT_EQUALS(RoleName("read", "test"), role.name); - ASSERT(role.hasRole); - ASSERT(!role.canDelegate); + RoleNameIterator roles = v1read->getRoles(); + ASSERT_EQUALS(RoleName("read", "test"), roles.next()); + ASSERT_FALSE(roles.more()); // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(v1read); @@ -233,12 +224,9 @@ namespace { ASSERT_EQUALS(UserName("v1cluster", "admin"), v1cluster->getName()); ASSERT(v1cluster->isValid()); ASSERT_EQUALS((uint32_t)1, v1cluster->getRefCount()); - const User::RoleDataMap& clusterRoles = v1cluster->getRoles(); - ASSERT_EQUALS(1U, clusterRoles.size()); - role = clusterRoles.begin()->second; - ASSERT_EQUALS(RoleName("clusterAdmin", "admin"), role.name); - ASSERT(role.hasRole); - ASSERT(!role.canDelegate); + RoleNameIterator clusterRoles = v1cluster->getRoles(); + ASSERT_EQUALS(RoleName("clusterAdmin", "admin"), clusterRoles.next()); + ASSERT_FALSE(clusterRoles.more()); // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(v1cluster); } @@ -275,12 +263,9 @@ namespace { ASSERT_EQUALS(UserName("readOnly", "test"), readOnly->getName()); ASSERT(readOnly->isValid()); ASSERT_EQUALS((uint32_t)2, readOnly->getRefCount()); - const User::RoleDataMap& roles = readOnly->getRoles(); - ASSERT_EQUALS(1U, roles.size()); - User::RoleData role = roles.begin()->second; - ASSERT_EQUALS(RoleName("read", "test"), role.name); - ASSERT(role.hasRole); - ASSERT(!role.canDelegate); + RoleNameIterator roles = readOnly->getRoles(); + ASSERT_EQUALS(RoleName("read", "test"), roles.next()); + ASSERT_FALSE(roles.more()); // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(readOnly); @@ -289,12 +274,9 @@ namespace { ASSERT_EQUALS(UserName("clusterAdmin", "$external"), clusterAdmin->getName()); ASSERT(clusterAdmin->isValid()); ASSERT_EQUALS((uint32_t)2, clusterAdmin->getRefCount()); - const User::RoleDataMap& clusterRoles = clusterAdmin->getRoles(); - ASSERT_EQUALS(1U, clusterRoles.size()); - role = clusterRoles.begin()->second; - ASSERT_EQUALS(RoleName("clusterAdmin", "admin"), role.name); - ASSERT(role.hasRole); - ASSERT(!role.canDelegate); + RoleNameIterator clusterRoles = clusterAdmin->getRoles(); + ASSERT_EQUALS(RoleName("clusterAdmin", "admin"), clusterRoles.next()); + ASSERT_FALSE(clusterRoles.more()); // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(clusterAdmin); @@ -308,16 +290,15 @@ namespace { ASSERT(multiDB->isValid()); ASSERT_EQUALS((uint32_t)2, multiDB->getRefCount()); - const User::RoleDataMap& multiDBRoles = multiDB->getRoles(); - ASSERT_EQUALS(2U, multiDBRoles.size()); - role = mapFindWithDefault(multiDBRoles, RoleName("readWrite", "test"), User::RoleData()); - ASSERT_EQUALS(RoleName("readWrite", "test"), role.name); - ASSERT(role.hasRole); - ASSERT(!role.canDelegate); - role = mapFindWithDefault(multiDBRoles, RoleName("readWrite", "test2"), User::RoleData()); - ASSERT_EQUALS(RoleName("readWrite", "test2"), role.name); - ASSERT(role.hasRole); - ASSERT(!role.canDelegate); + RoleNameIterator multiDBRoles = multiDB->getRoles(); + RoleName role = multiDBRoles.next(); + if (role == RoleName("readWrite", "test")) { + ASSERT_EQUALS(RoleName("readWrite", "test2"), multiDBRoles.next()); + } else { + ASSERT_EQUALS(RoleName("readWrite", "test2"), role); + ASSERT_EQUALS(RoleName("readWrite", "test"), multiDBRoles.next()); + } + ASSERT_FALSE(multiDBRoles.more()); // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(multiDB); @@ -360,12 +341,9 @@ namespace { ASSERT_EQUALS(UserName("v2read", "test"), v2read->getName()); ASSERT(v2read->isValid()); ASSERT_EQUALS((uint32_t)1, v2read->getRefCount()); - const User::RoleDataMap& roles = v2read->getRoles(); - ASSERT_EQUALS(1U, roles.size()); - User::RoleData role = roles.begin()->second; - ASSERT_EQUALS(RoleName("read", "test"), role.name); - ASSERT(role.hasRole); - ASSERT(!role.canDelegate); + RoleNameIterator roles = v2read->getRoles(); + ASSERT_EQUALS(RoleName("read", "test"), roles.next()); + ASSERT_FALSE(roles.more()); // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(v2read); @@ -374,12 +352,9 @@ namespace { ASSERT_EQUALS(UserName("v2cluster", "admin"), v2cluster->getName()); ASSERT(v2cluster->isValid()); ASSERT_EQUALS((uint32_t)1, v2cluster->getRefCount()); - const User::RoleDataMap& clusterRoles = v2cluster->getRoles(); - ASSERT_EQUALS(1U, clusterRoles.size()); - role = clusterRoles.begin()->second; - ASSERT_EQUALS(RoleName("clusterAdmin", "admin"), role.name); - ASSERT(role.hasRole); - ASSERT(role.canDelegate); + RoleNameIterator clusterRoles = v2cluster->getRoles(); + ASSERT_EQUALS(RoleName("clusterAdmin", "admin"), clusterRoles.next()); + ASSERT_FALSE(clusterRoles.more()); // Make sure user's refCount is 0 at the end of the test to avoid an assertion failure authzManager->releaseUser(v2cluster); } diff --git a/src/mongo/db/auth/authz_manager_external_state_d.cpp b/src/mongo/db/auth/authz_manager_external_state_d.cpp index 79cb611d50a..ca50128e7e4 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_d.cpp @@ -154,9 +154,9 @@ namespace { status = bsonExtractTypedField(userDoc, "roles", Array, &directRolesElement); if (!status.isOK()) return status; - std::vector<User::RoleData> directRoles; + std::vector<RoleName> directRoles; status = V2UserDocumentParser::parseRoleVector(BSONArray(directRolesElement.Obj()), - &directRoles); + &directRoles); if (!status.isOK()) return status; @@ -167,13 +167,10 @@ namespace { boost::lock_guard<boost::mutex> lk(_roleGraphMutex); isRoleGraphInconsistent = _roleGraphState == roleGraphStateConsistent; for (size_t i = 0; i < directRoles.size(); ++i) { - const User::RoleData& role(directRoles[i]); - if (!role.hasRole) - continue; - indirectRoles.insert(role.name); + const RoleName& role(directRoles[i]); + indirectRoles.insert(role); if (isRoleGraphInconsistent) { - for (RoleNameIterator subordinates = _roleGraph.getIndirectSubordinates( - role.name); + for (RoleNameIterator subordinates = _roleGraph.getIndirectSubordinates(role); subordinates.more(); subordinates.next()) { @@ -182,8 +179,8 @@ namespace { } const PrivilegeVector& rolePrivileges( isRoleGraphInconsistent ? - _roleGraph.getAllPrivileges(role.name) : - _roleGraph.getDirectPrivileges(role.name)); + _roleGraph.getAllPrivileges(role) : + _roleGraph.getDirectPrivileges(role)); for (PrivilegeVector::const_iterator priv = rolePrivileges.begin(), end = rolePrivileges.end(); priv != end; diff --git a/src/mongo/db/auth/user.cpp b/src/mongo/db/auth/user.cpp index 6895cd27398..9a28f9b062e 100644 --- a/src/mongo/db/auth/user.cpp +++ b/src/mongo/db/auth/user.cpp @@ -36,8 +36,8 @@ namespace mongo { return _name; } - const User::RoleDataMap& User::getRoles() const { - return _roles; + RoleNameIterator User::getRoles() const { + return makeRoleNameIteratorForContainer(_roles); } bool User::hasRole(const RoleName& roleName) const { @@ -77,11 +77,10 @@ namespace mongo { _credentials = credentials; } - void User::setRoleData(const std::vector<User::RoleData>& roles) { + void User::setRoles(RoleNameIterator roles) { _roles.clear(); - for (size_t i = 0; i < roles.size(); ++i) { - const User::RoleData& role = roles[i]; - _roles[role.name] = role; + while (roles.more()) { + _roles.insert(roles.next()); } } @@ -94,11 +93,7 @@ namespace mongo { } void User::addRole(const RoleName& roleName) { - RoleData& role = _roles[roleName]; - if (role.name.empty()) { - role.name = roleName; - } - role.hasRole = true; + _roles.insert(roleName); } void User::addRoles(const std::vector<RoleName>& roles) { @@ -107,20 +102,6 @@ namespace mongo { } } - void User::addDelegatableRole(const RoleName& roleName) { - RoleData& role = _roles[roleName]; - if (role.name.empty()) { - role.name = roleName; - } - role.canDelegate = true; - } - - void User::addDelegatableRoles(const std::vector<RoleName>& roles) { - for (std::vector<RoleName>::const_iterator it = roles.begin(); it != roles.end(); ++it) { - addDelegatableRole(*it); - } - } - void User::addPrivilege(const Privilege& privilegeToAdd) { ResourcePrivilegeMap::iterator it = _privileges.find(privilegeToAdd.getResourcePattern()); if (it == _privileges.end()) { diff --git a/src/mongo/db/auth/user.h b/src/mongo/db/auth/user.h index 053e045fe1e..2964d373cc8 100644 --- a/src/mongo/db/auth/user.h +++ b/src/mongo/db/auth/user.h @@ -25,6 +25,7 @@ #include "mongo/db/auth/user_name.h" #include "mongo/platform/atomic_word.h" #include "mongo/platform/unordered_map.h" +#include "mongo/platform/unordered_set.h" namespace mongo { @@ -50,17 +51,7 @@ namespace mongo { bool isExternal; }; - struct RoleData { - RoleName name; - bool hasRole; - bool canDelegate; - RoleData() : hasRole(false), canDelegate(false) {} - RoleData(const RoleName& _name, bool _hasRole, bool _canDelegate) : - name(_name), hasRole(_hasRole), canDelegate(_canDelegate) {} - }; - typedef unordered_map<ResourcePattern, Privilege> ResourcePrivilegeMap; - typedef unordered_map<RoleName, RoleData> RoleDataMap; explicit User(const UserName& name); ~User(); @@ -71,9 +62,9 @@ namespace mongo { const UserName& getName() const; /** - * Returns a reference to the information about the users' role membership. + * Returns an iterator over the names of the user's direct roles */ - const RoleDataMap& getRoles() const; + RoleNameIterator getRoles() const; /** * Returns true if this user is a member of the given role. @@ -122,9 +113,9 @@ namespace mongo { void setCredentials(const CredentialData& credentials); /** - * Replaces any existing user role membership information with "roles". + * Replaces any existing user role membership information with the roles from "roles". */ - void setRoleData(const std::vector<RoleData>& roles); + void setRoles(RoleNameIterator roles); /** * Replaces any existing user privilege information with "privileges". @@ -142,16 +133,6 @@ namespace mongo { void addRoles(const std::vector<RoleName>& roles); /** - * Adds the given role name to the list of roles that this user is allowed to delegate. - */ - void addDelegatableRole(const RoleName& role); - - /** - * Adds the given role names to the list of roles that this user is allowed to delegate. - */ - void addDelegatableRoles(const std::vector<RoleName>& roles); - - /** * Adds the given privilege to the list of privileges this user is authorized for. */ void addPrivilege(const Privilege& privilege); @@ -194,8 +175,8 @@ namespace mongo { // Maps resource name to privilege on that resource ResourcePrivilegeMap _privileges; - // Roles the user has privileges from and/or can delegate - RoleDataMap _roles; + // Roles the user has privileges from + unordered_set<RoleName> _roles; CredentialData _credentials; diff --git a/src/mongo/db/auth/user_document_parser.cpp b/src/mongo/db/auth/user_document_parser.cpp index f8adf40eb8f..15b3bea0ca6 100644 --- a/src/mongo/db/auth/user_document_parser.cpp +++ b/src/mongo/db/auth/user_document_parser.cpp @@ -49,8 +49,6 @@ namespace { const std::string CREDENTIALS_FIELD_NAME = "credentials"; const std::string ROLE_NAME_FIELD_NAME = "role"; const std::string ROLE_SOURCE_FIELD_NAME = "db"; - const std::string ROLE_CAN_DELEGATE_FIELD_NAME = "canDelegate"; - const std::string ROLE_HAS_ROLE_FIELD_NAME = "hasRole"; const std::string MONGODB_CR_CREDENTIAL_FIELD_NAME = "MONGODB-CR"; inline Status _badValue(const char* reason, int location) { @@ -327,14 +325,10 @@ namespace { static Status _extractRoleDocumentElements( const BSONObj& roleObject, BSONElement* roleNameElement, - BSONElement* roleSourceElement, - BSONElement* canDelegateElement, - BSONElement* hasRoleElement) { + BSONElement* roleSourceElement) { *roleNameElement = roleObject[ROLE_NAME_FIELD_NAME]; *roleSourceElement = roleObject[ROLE_SOURCE_FIELD_NAME]; - *canDelegateElement = roleObject[ROLE_CAN_DELEGATE_FIELD_NAME]; - *hasRoleElement = roleObject[ROLE_HAS_ROLE_FIELD_NAME]; if (roleNameElement->type() != String || makeStringDataFromBSONElement(*roleNameElement).empty()) { @@ -346,59 +340,40 @@ namespace { return Status(ErrorCodes::UnsupportedFormat, "Role db must be non-empty strings"); } - if (!canDelegateElement->eoo() && canDelegateElement->type() != Bool) { - return Status(ErrorCodes::UnsupportedFormat, - "'canDelegate' field must be a boolean if provided"); - } - if (!hasRoleElement->eoo() && hasRoleElement->type() != Bool) { - return Status(ErrorCodes::UnsupportedFormat, - "'hasRole' field must be a boolean if provided"); - } return Status::OK(); } - Status V2UserDocumentParser::checkValidRoleObject(const BSONObj& roleObject) { BSONElement roleNameElement; BSONElement roleSourceElement; - BSONElement canDelegateElement; - BSONElement hasRoleElement; return _extractRoleDocumentElements( roleObject, &roleNameElement, - &roleSourceElement, - &canDelegateElement, - &hasRoleElement); + &roleSourceElement); } - Status V2UserDocumentParser::parseRoleData(const BSONObj& roleObject, User::RoleData* result) { + Status V2UserDocumentParser::parseRoleName(const BSONObj& roleObject, RoleName* result) { BSONElement roleNameElement; BSONElement roleSourceElement; - BSONElement canDelegateElement; - BSONElement hasRoleElement; Status status = _extractRoleDocumentElements( roleObject, &roleNameElement, - &roleSourceElement, - &canDelegateElement, - &hasRoleElement); + &roleSourceElement); if (!status.isOK()) return status; - result->name = RoleName(roleNameElement.str(), roleSourceElement.str()); - result->canDelegate = canDelegateElement.eoo() ? false : canDelegateElement.trueValue(); - result->hasRole = hasRoleElement.eoo() ? true : hasRoleElement.trueValue(); + *result = RoleName(roleNameElement.str(), roleSourceElement.str()); return status; } Status V2UserDocumentParser::parseRoleVector(const BSONArray& rolesArray, - std::vector<User::RoleData>* result) { - std::vector<User::RoleData> roles; + std::vector<RoleName>* result) { + std::vector<RoleName> roles; for (BSONObjIterator it(rolesArray); it.more(); it.next()) { if ((*it).type() != Object) { return Status(ErrorCodes::TypeMismatch, "Roles must be objects."); } - User::RoleData role; - Status status = parseRoleData((*it).Obj(), &role); + RoleName role; + Status status = parseRoleName((*it).Obj(), &role); if (!status.isOK()) return status; roles.push_back(role); @@ -417,7 +392,7 @@ namespace { "User document needs 'roles' field to be an array"); } - std::vector<User::RoleData> roles; + std::vector<RoleName> roles; for (BSONObjIterator it(rolesElement.Obj()); it.more(); it.next()) { if ((*it).type() != Object) { return Status(ErrorCodes::UnsupportedFormat, @@ -425,13 +400,14 @@ namespace { } BSONObj roleObject = (*it).Obj(); - roles.resize(roles.size() + 1); - Status status = parseRoleData(roleObject, &roles.back()); + RoleName role; + Status status = parseRoleName(roleObject, &role); if (!status.isOK()) { return status; } + roles.push_back(role); } - user->setRoleData(roles); + user->setRoles(makeRoleNameIteratorForContainer(roles)); return Status::OK(); } diff --git a/src/mongo/db/auth/user_document_parser.h b/src/mongo/db/auth/user_document_parser.h index 524621545c1..be68330239e 100644 --- a/src/mongo/db/auth/user_document_parser.h +++ b/src/mongo/db/auth/user_document_parser.h @@ -60,10 +60,9 @@ namespace mongo { */ static Status checkValidRoleObject(const BSONObj& roleObject); - static Status parseRoleData(const BSONObj& roleObject, User::RoleData* result); + static Status parseRoleName(const BSONObj& roleObject, RoleName* result); - static Status parseRoleVector(const BSONArray& rolesArray, - std::vector<User::RoleData>* result); + static Status parseRoleVector(const BSONArray& rolesArray, std::vector<RoleName>* result); std::string extractUserNameFromUserDocument(const BSONObj& doc) const; diff --git a/src/mongo/db/auth/user_document_parser_test.cpp b/src/mongo/db/auth/user_document_parser_test.cpp index 158b59435e1..0fba05a5168 100644 --- a/src/mongo/db/auth/user_document_parser_test.cpp +++ b/src/mongo/db/auth/user_document_parser_test.cpp @@ -59,26 +59,30 @@ namespace { ASSERT_OK(v1parser.initializeUserRolesFromUserDocument( user.get(), readOnly, "test")); - ASSERT_EQUALS(1U, user->getRoles().size()); - ASSERT_EQUALS(1U, user->getRoles().count(RoleName("read", "test"))); + RoleNameIterator roles = user->getRoles(); + ASSERT_EQUALS(RoleName("read", "test"), roles.next()); + ASSERT_FALSE(roles.more()); resetUsers(); ASSERT_OK(v1parser.initializeUserRolesFromUserDocument( user.get(), readWrite, "test")); - ASSERT_EQUALS(1U, user->getRoles().size()); - ASSERT_EQUALS(1U, user->getRoles().count(RoleName("dbOwner", "test"))); + roles = user->getRoles(); + ASSERT_EQUALS(RoleName("dbOwner", "test"), roles.next()); + ASSERT_FALSE(roles.more()); resetUsers(); ASSERT_OK(v1parser.initializeUserRolesFromUserDocument( adminUser.get(), readOnlyAdmin, "admin")); - ASSERT_EQUALS(1U, adminUser->getRoles().size()); - ASSERT_EQUALS(1U, adminUser->getRoles().count(RoleName("readAnyDatabase", "admin"))); + roles = adminUser->getRoles(); + ASSERT_EQUALS(RoleName("readAnyDatabase", "admin"), roles.next()); + ASSERT_FALSE(roles.more()); resetUsers(); ASSERT_OK(v1parser.initializeUserRolesFromUserDocument( adminUser.get(), readWriteAdmin, "admin")); - ASSERT_EQUALS(1U, adminUser->getRoles().size()); - ASSERT_EQUALS(1U, adminUser->getRoles().count(RoleName("root", "admin"))); + roles = adminUser->getRoles(); + ASSERT_EQUALS(RoleName("root", "admin"), roles.next()); + ASSERT_FALSE(roles.more()); } TEST_F(V1UserDocumentParsing, VerifyRolesFieldMustBeAnArray) { @@ -86,7 +90,7 @@ namespace { user.get(), BSON("user" << "spencer" << "pwd" << "" << "roles" << "read"), "test")); - ASSERT_EQUALS(0U, user->getRoles().size()); + ASSERT_FALSE(user->getRoles().more()); } TEST_F(V1UserDocumentParsing, VerifySemanticallyInvalidRolesStillParse) { @@ -96,9 +100,15 @@ namespace { "pwd" << "" << "roles" << BSON_ARRAY("read" << "frim")), "test")); - ASSERT_EQUALS(2U, user->getRoles().size()); - ASSERT_EQUALS(1U, user->getRoles().count(RoleName("read", "test"))); - ASSERT_EQUALS(1U, user->getRoles().count(RoleName("frim", "test"))); + RoleNameIterator roles = user->getRoles(); + RoleName role = roles.next(); + if (role == RoleName("read", "test")) { + ASSERT_EQUALS(RoleName("frim", "test"), roles.next()); + } else { + ASSERT_EQUALS(RoleName("frim", "test"), role); + ASSERT_EQUALS(RoleName("read", "test"), roles.next()); + } + ASSERT_FALSE(roles.more()); } TEST_F(V1UserDocumentParsing, VerifyOtherDBRolesMustBeAnObjectOfArraysOfStrings) { @@ -128,7 +138,7 @@ namespace { "roles" << BSONArrayBuilder().arr() << "otherDBRoles" << BSON("test2" << BSON_ARRAY("read"))), "test")); - ASSERT_EQUALS(0U, user->getRoles().size()); + ASSERT_FALSE(user->getRoles().more()); } TEST_F(V1UserDocumentParsing, GrantUserAdminOnTestViaAdmin) { @@ -140,8 +150,9 @@ namespace { "roles" << BSONArrayBuilder().arr() << "otherDBRoles" << BSON("test" << BSON_ARRAY("userAdmin"))), "admin")); - ASSERT_EQUALS(1U, adminUser->getRoles().size()); - ASSERT_EQUALS(1U, adminUser->getRoles().count(RoleName("userAdmin", "test"))); + RoleNameIterator roles = adminUser->getRoles(); + ASSERT_EQUALS(RoleName("userAdmin", "test"), roles.next()); + ASSERT_FALSE(roles.more()); } TEST_F(V1UserDocumentParsing, MixedV0V1UserDocumentsAreInvalid) { @@ -153,7 +164,7 @@ namespace { "readOnly" << false << "roles" << BSON_ARRAY("read")), "test")); - ASSERT_EQUALS(0U, user->getRoles().size()); + ASSERT_FALSE(user->getRoles().more()); } class V2UserDocumentParsing : public ::mongo::unittest::Test { @@ -348,10 +359,9 @@ namespace { "roles" << BSON_ARRAY(BSON("role" << "roleA" << "db" << "dbA"))), user.get())); - const User::RoleDataMap& roles2 = user->getRoles(); - ASSERT_EQUALS(1U, roles2.size()); - User::RoleData role = roles2.begin()->second; - ASSERT_EQUALS(RoleName("roleA", "dbA"), role.name); + RoleNameIterator roles = user->getRoles(); + ASSERT_EQUALS(RoleName("roleA", "dbA"), roles.next()); + ASSERT_FALSE(roles.more()); // Multiple roles OK ASSERT_OK(v2parser.initializeUserRolesFromUserDocument( @@ -361,12 +371,15 @@ namespace { BSON("role" << "roleB" << "db" << "dbB"))), user.get())); - const User::RoleDataMap& roles3 = user->getRoles(); - ASSERT_EQUALS(2U, roles3.size()); - role = roles3.find(RoleName("roleA", "dbA"))->second; - ASSERT_EQUALS(RoleName("roleA", "dbA"), role.name); - role = roles3.find(RoleName("roleB", "dbB"))->second; - ASSERT_EQUALS(RoleName("roleB", "dbB"), role.name); + roles = user->getRoles(); + RoleName role = roles.next(); + if (role == RoleName("roleA", "dbA")) { + ASSERT_EQUALS(RoleName("roleB", "dbB"), roles.next()); + } else { + ASSERT_EQUALS(RoleName("roleB", "dbB"), role); + ASSERT_EQUALS(RoleName("roleA", "dbA"), roles.next()); + } + ASSERT_FALSE(roles.more()); } } // namespace diff --git a/src/mongo/db/auth/user_management_commands_parser.cpp b/src/mongo/db/auth/user_management_commands_parser.cpp index 85f73490ee5..e03ff1c4478 100644 --- a/src/mongo/db/auth/user_management_commands_parser.cpp +++ b/src/mongo/db/auth/user_management_commands_parser.cpp @@ -157,63 +157,6 @@ namespace auth { parsedRoleNames); } - Status _extractRoleDataFromBSONArray(const BSONElement& rolesElement, - const std::string& dbname, - std::vector<User::RoleData> *parsedRoleData) { - for (BSONObjIterator it(rolesElement.Obj()); it.more(); it.next()) { - BSONElement element = *it; - if (element.type() == String) { - RoleName roleName(element.String(), dbname); - parsedRoleData->push_back(User::RoleData(roleName, true, false)); - } else if (element.type() == Object) { - // Check that the role object is valid - V2UserDocumentParser parser; - BSONObj roleObj = element.Obj(); - Status status = parser.checkValidRoleObject(roleObj); - if (!status.isOK()) { - return status; - } - - std::string roleName; - std::string roleSource; - bool hasRole; - bool canDelegate; - status = bsonExtractStringField(roleObj, - AuthorizationManager::ROLE_NAME_FIELD_NAME, - &roleName); - if (!status.isOK()) { - return status; - } - status = bsonExtractStringField(roleObj, - AuthorizationManager::ROLE_SOURCE_FIELD_NAME, - &roleSource); - if (!status.isOK()) { - return status; - } - status = bsonExtractBooleanFieldWithDefault(roleObj, "hasRole", true, &hasRole); - if (!status.isOK()) { - return status; - } - status = bsonExtractBooleanFieldWithDefault(roleObj, - "canDelegate", - false, - &canDelegate); - if (!status.isOK()) { - return status; - } - - parsedRoleData->push_back(User::RoleData(RoleName(roleName, roleSource), - hasRole, - canDelegate)); - } else { - return Status(ErrorCodes::UnsupportedFormat, - "Values in 'roles' array must be sub-documents or strings"); - } - } - - return Status::OK(); - } - Status parseRolePossessionManipulationCommands(const BSONObj& cmdObj, const StringData& cmdName, const StringData& rolesFieldName, @@ -327,7 +270,9 @@ namespace auth { if (!status.isOK()) { return status; } - status = _extractRoleDataFromBSONArray(rolesElement, dbname, &parsedArgs->roles); + status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), + dbname, + &parsedArgs->roles); if (!status.isOK()) { return status; } diff --git a/src/mongo/db/auth/user_management_commands_parser.h b/src/mongo/db/auth/user_management_commands_parser.h index 58c0a427828..7581343cb0d 100644 --- a/src/mongo/db/auth/user_management_commands_parser.h +++ b/src/mongo/db/auth/user_management_commands_parser.h @@ -48,7 +48,7 @@ namespace auth { bool hasCustomData; BSONObj customData; bool hasRoles; - std::vector<User::RoleData> roles; + std::vector<RoleName> roles; BSONObj writeConcern; CreateOrUpdateUserArgs() : hasHashedPassword(false), hasCustomData(false), hasRoles(false) {} diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp index d062774b6b0..758f505bf66 100644 --- a/src/mongo/db/commands/user_management_commands.cpp +++ b/src/mongo/db/commands/user_management_commands.cpp @@ -78,49 +78,26 @@ namespace mongo { } } - static BSONArray roleDataMapToBSONArray(const User::RoleDataMap& roles) { - BSONArrayBuilder arrBuilder; - for (User::RoleDataMap::const_iterator it = roles.begin(); it != roles.end(); ++it) { - const User::RoleData& role = it->second; - arrBuilder.append( - BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.name.getRole() << - AuthorizationManager::ROLE_SOURCE_FIELD_NAME << role.name.getDB() << - "hasRole" << role.hasRole << - "canDelegate" << role.canDelegate)); - } - return arrBuilder.arr(); - } - - static Status rolesVectorToBSONArray(const std::vector<RoleName>& roles, BSONArray* result) { + static BSONArray roleSetToBSONArray(const unordered_set<RoleName>& roles) { BSONArrayBuilder rolesArrayBuilder; - for (std::vector<RoleName>::const_iterator it = roles.begin(); it != roles.end(); ++it) { + for (unordered_set<RoleName>::const_iterator it = roles.begin(); it != roles.end(); ++it) { const RoleName& role = *it; rolesArrayBuilder.append( BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() << AuthorizationManager::ROLE_SOURCE_FIELD_NAME << role.getDB())); } - *result = rolesArrayBuilder.arr(); - return Status::OK(); + return rolesArrayBuilder.arr(); } - static Status roleDataVectorToBSONArray(const std::vector<User::RoleData>& roles, - BSONArray* result) { + static BSONArray rolesVectorToBSONArray(const std::vector<RoleName>& roles) { BSONArrayBuilder rolesArrayBuilder; - for (std::vector<User::RoleData>::const_iterator it = roles.begin(); - it != roles.end(); ++it) { - const User::RoleData& role = *it; - if (!role.hasRole && !role.canDelegate) { - return Status(ErrorCodes::BadValue, "At least one of \"hasRole\" and " - "\"canDelegate\" must be true for every role object"); - } + for (std::vector<RoleName>::const_iterator it = roles.begin(); it != roles.end(); ++it) { + const RoleName& role = *it; rolesArrayBuilder.append( - BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.name.getRole() << - AuthorizationManager::ROLE_SOURCE_FIELD_NAME << role.name.getDB() << - "hasRole" << role.hasRole << - "canDelegate" << role.canDelegate)); + BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() << + AuthorizationManager::ROLE_SOURCE_FIELD_NAME << role.getDB())); } - *result = rolesArrayBuilder.arr(); - return Status::OK(); + return rolesArrayBuilder.arr(); } static Status privilegeVectorToBSONArray(const PrivilegeVector& privileges, BSONArray* result) { @@ -147,13 +124,16 @@ namespace mongo { static Status getCurrentUserRoles(AuthorizationManager* authzManager, const UserName& userName, - User::RoleDataMap* roles) { + unordered_set<RoleName>* roles) { User* user; Status status = authzManager->acquireUser(userName, &user); if (!status.isOK()) { return status; } - *roles = user->getRoles(); + RoleNameIterator rolesIt = user->getRoles(); + while (rolesIt.more()) { + roles->insert(rolesIt.next()); + } authzManager->releaseUser(user); return Status::OK(); } @@ -250,13 +230,7 @@ namespace mongo { args.userName.getDB()); } - // TODO(spencer): building this vector won't be necessary once the roles coming - // from the parsed args are RoleNames, not User::RoleInfo structs. - std::vector<RoleName> roles; - for (size_t i = 0; i < args.roles.size(); ++i) { - roles.push_back(args.roles[i].name); - } - return checkAuthorizedToGrantRoles(authzSession, roles); + return checkAuthorizedToGrantRoles(authzSession, args.roles); } bool run(const string& dbname, @@ -310,13 +284,7 @@ namespace mongo { if (args.hasCustomData) { userObjBuilder.append("customData", args.customData); } - BSONArray rolesArray; - status = roleDataVectorToBSONArray(args.roles, &rolesArray); - if (!status.isOK()) { - addStatus(status, result); - return false; - } - userObjBuilder.append("roles", rolesArray); + userObjBuilder.append("roles", rolesVectorToBSONArray(args.roles)); BSONObj userObj = userObjBuilder.obj(); V2UserDocumentParser parser; @@ -337,7 +305,7 @@ namespace mongo { // Role existence has to be checked after acquiring the update lock for (size_t i = 0; i < args.roles.size(); ++i) { BSONObj ignored; - Status status = authzManager->getRoleDescription(args.roles[i].name, &ignored); + Status status = authzManager->getRoleDescription(args.roles[i], &ignored); if (!status.isOK()) { addStatus(status, result); return false; @@ -431,13 +399,7 @@ namespace mongo { "authorized to revoke any role in the system"); } - // TODO(spencer): building this vector won't be necessary once the roles coming - // from the parsed args are RoleNames, not User::RoleInfo structs. - std::vector<RoleName> roles; - for (size_t i = 0; i < args.roles.size(); ++i) { - roles.push_back(args.roles[i].name); - } - return checkAuthorizedToGrantRoles(authzSession, roles); + return checkAuthorizedToGrantRoles(authzSession, args.roles); } return Status::OK(); } @@ -473,13 +435,7 @@ namespace mongo { updateSetBuilder.append("customData", args.customData); } if (args.hasRoles) { - BSONArray rolesArray; - status = roleDataVectorToBSONArray(args.roles, &rolesArray); - if (!status.isOK()) { - addStatus(status, result); - return false; - } - updateSetBuilder.append("roles", rolesArray); + updateSetBuilder.append("roles", rolesVectorToBSONArray(args.roles)); } AuthorizationManager* authzManager = getGlobalAuthorizationManager(); @@ -494,7 +450,7 @@ namespace mongo { if (args.hasRoles) { for (size_t i = 0; i < args.roles.size(); ++i) { BSONObj ignored; - status = authzManager->getRoleDescription(args.roles[i].name, &ignored); + status = authzManager->getRoleDescription(args.roles[i], &ignored); if (!status.isOK()) { addStatus(status, result); return false; @@ -775,7 +731,7 @@ namespace mongo { } UserName userName(userNameString, dbname); - User::RoleDataMap userRoles; + unordered_set<RoleName> userRoles; status = getCurrentUserRoles(authzManager, userName, &userRoles); if (!status.isOK()) { addStatus(status, result); @@ -791,14 +747,10 @@ namespace mongo { return false; } - User::RoleData& role = userRoles[roleName]; - if (role.name.empty()) { - role.name = roleName; - } - role.hasRole = true; + userRoles.insert(roleName); } - BSONArray newRolesBSONArray = roleDataMapToBSONArray(userRoles); + BSONArray newRolesBSONArray = roleSetToBSONArray(userRoles); status = authzManager->updatePrivilegeDocument( userName, BSON("$set" << BSON("roles" << newRolesBSONArray)), writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? @@ -885,7 +837,7 @@ namespace mongo { } UserName userName(userNameString, dbname); - User::RoleDataMap userRoles; + unordered_set<RoleName> userRoles; status = getCurrentUserRoles(authzManager, userName, &userRoles); if (!status.isOK()) { addStatus(status, result); @@ -901,22 +853,10 @@ namespace mongo { return false; } - User::RoleDataMap::iterator roleDataIt = userRoles.find(roleName); - if (roleDataIt == userRoles.end()) { - continue; // User already doesn't have the role, nothing to do - } - User::RoleData& role = roleDataIt->second; - if (role.canDelegate) { - // If the user can still delegate the role, need to leave it in the roles array - role.hasRole = false; - } else { - // If the user can't delegate the role, and now doesn't have it either, remove - // the role from that user's roles array entirely - userRoles.erase(roleDataIt); - } + userRoles.erase(roleName); } - BSONArray newRolesBSONArray = roleDataMapToBSONArray(userRoles); + BSONArray newRolesBSONArray = roleSetToBSONArray(userRoles); status = authzManager->updatePrivilegeDocument( userName, BSON("$set" << BSON("roles" << newRolesBSONArray)), writeConcern); // Must invalidate even on bad status - what if the write succeeded but the GLE failed? @@ -1167,13 +1107,7 @@ namespace mongo { } roleObjBuilder.append("privileges", privileges); - BSONArray roles; - status = rolesVectorToBSONArray(args.roles, &roles); - if (!status.isOK()) { - addStatus(status, result); - return false; - } - roleObjBuilder.append("roles", roles); + roleObjBuilder.append("roles", rolesVectorToBSONArray(args.roles)); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); AuthzDocumentsUpdateGuard updateGuard(authzManager); @@ -1295,14 +1229,7 @@ namespace mongo { } if (args.hasRoles) { - BSONArray roles; - status = rolesVectorToBSONArray(args.roles, &roles); - if (!status.isOK()) { - addStatus(status, result); - return false; - } - - updateSetBuilder.append("roles", roles); + updateSetBuilder.append("roles", rolesVectorToBSONArray(args.roles)); } AuthorizationManager* authzManager = getGlobalAuthorizationManager(); @@ -1759,19 +1686,14 @@ namespace mongo { roles.push_back(*it); } - BSONArray newRolesBSONArray; - status = rolesVectorToBSONArray(roles, &newRolesBSONArray); - if (!status.isOK()) { - addStatus(status, result); - return false; - } - audit::logGrantRolesToRole(ClientBasic::getCurrent(), roleName, roles); status = authzManager->updateRoleDocument( - roleName, BSON("$set" << BSON("roles" << newRolesBSONArray)), writeConcern); + roleName, + BSON("$set" << BSON("roles" << rolesVectorToBSONArray(roles))), + writeConcern); if (!status.isOK()) { addStatus(status, result); return false; @@ -1885,19 +1807,14 @@ namespace mongo { } } - BSONArray newRolesBSONArray; - status = rolesVectorToBSONArray(roles, &newRolesBSONArray); - if (!status.isOK()) { - addStatus(status, result); - return false; - } - audit::logRevokeRolesFromRole(ClientBasic::getCurrent(), roleName, roles); status = authzManager->updateRoleDocument( - roleName, BSON("$set" << BSON("roles" << newRolesBSONArray)), writeConcern); + roleName, + BSON("$set" << BSON("roles" << rolesVectorToBSONArray(roles))), + writeConcern); if (!status.isOK()) { addStatus(status, result); return false; |