summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorSpencer T Brody <spencer@10gen.com>2013-10-17 20:12:21 -0400
committerSpencer T Brody <spencer@10gen.com>2013-10-21 17:22:16 -0400
commit4e5bb06c7156a2a6e7bf878f3cf2c90a94771b2d (patch)
tree2fbf3eb990490d022c1ead9ac12540d514238fd9 /src/mongo
parentb67de10c6307468636b91fddd5d67b066f86b526 (diff)
downloadmongo-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.cpp4
-rw-r--r--src/mongo/db/audit.h4
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp21
-rw-r--r--src/mongo/db/auth/authorization_manager_test.cpp91
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_d.cpp17
-rw-r--r--src/mongo/db/auth/user.cpp31
-rw-r--r--src/mongo/db/auth/user.h33
-rw-r--r--src/mongo/db/auth/user_document_parser.cpp52
-rw-r--r--src/mongo/db/auth/user_document_parser.h5
-rw-r--r--src/mongo/db/auth/user_document_parser_test.cpp65
-rw-r--r--src/mongo/db/auth/user_management_commands_parser.cpp61
-rw-r--r--src/mongo/db/auth/user_management_commands_parser.h2
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp151
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;