summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/auth/role_graph.cpp82
-rw-r--r--src/mongo/db/auth/role_graph.h10
-rw-r--r--src/mongo/db/auth/role_graph_test.cpp24
-rw-r--r--src/mongo/db/auth/role_name.h2
4 files changed, 101 insertions, 17 deletions
diff --git a/src/mongo/db/auth/role_graph.cpp b/src/mongo/db/auth/role_graph.cpp
index 17b28e502c4..a34fa853260 100644
--- a/src/mongo/db/auth/role_graph.cpp
+++ b/src/mongo/db/auth/role_graph.cpp
@@ -40,6 +40,41 @@ namespace mongo {
namespace {
PrivilegeVector emptyPrivilegeVector;
+
+ // RoleNameIterator for iterating over an unordered_set of RoleNames.
+ class RoleNameSetIterator : public RoleNameIterator::Impl {
+ MONGO_DISALLOW_COPYING(RoleNameSetIterator);
+
+ public:
+ RoleNameSetIterator(const unordered_set<RoleName>::const_iterator& begin,
+ const unordered_set<RoleName>::const_iterator& end) :
+ _begin(begin), _end(end) {}
+
+ virtual ~RoleNameSetIterator() {}
+
+ virtual bool more() const {
+ return _begin != _end;
+ }
+
+ virtual const RoleName& next() {
+ const RoleName& toReturn = get();
+ ++_begin;
+ return toReturn;
+ }
+
+
+ virtual const RoleName& get() const {
+ return *_begin;
+ }
+
+ private:
+ virtual Impl* doClone() const {
+ return new RoleNameSetIterator(_begin, _end);
+ }
+
+ unordered_set<RoleName>::const_iterator _begin;
+ unordered_set<RoleName>::const_iterator _end;
+ };
} // namespace
RoleGraph::RoleGraph() {};
@@ -148,6 +183,13 @@ namespace {
return RoleNameIterator(new RoleNameVectorIterator(edges.begin(), edges.end()));
}
+ RoleNameIterator RoleGraph::getIndirectSubordinates(const RoleName& role) {
+ if (!roleExists(role))
+ return RoleNameIterator(NULL);
+ const unordered_set<RoleName>& subs = _roleToIndirectSubordinates.find(role)->second;
+ return RoleNameIterator(new RoleNameSetIterator(subs.begin(), subs.end()));
+ }
+
RoleNameIterator RoleGraph::getDirectMembers(const RoleName& role) {
if (!roleExists(role))
return RoleNameIterator(NULL);
@@ -171,20 +213,17 @@ namespace {
if (!roleExists(recipient)) {
return Status(ErrorCodes::RoleNotFound,
mongoutils::str::stream() << "Role: " << recipient.getFullName() <<
- " does not exist",
- 0);
+ " does not exist");
}
if (isBuiltinRole(recipient)) {
return Status(ErrorCodes::InvalidRoleModification,
mongoutils::str::stream() << "Cannot grant roles to built-in role: " <<
- role.getFullName(),
- 0);
+ role.getFullName());
}
if (!roleExists(role)) {
return Status(ErrorCodes::RoleNotFound,
mongoutils::str::stream() << "Role: " << role.getFullName() <<
- " does not exist",
- 0);
+ " does not exist");
}
if (std::find(_roleToSubordinates[recipient].begin(),
@@ -438,17 +477,22 @@ namespace {
// Need to clear out the "all privileges" vector for the current role, and re-fill it with
// just the direct privileges for this role.
PrivilegeVector& currentRoleAllPrivileges = _allPrivilegesForRole[currentRole];
- const PrivilegeVector& currentRoleDirectPrivileges = _directPrivilegesForRole[currentRole];
- currentRoleAllPrivileges.clear();
- for (PrivilegeVector::const_iterator it = currentRoleDirectPrivileges.begin();
- it != currentRoleDirectPrivileges.end(); ++it) {
- currentRoleAllPrivileges.push_back(*it);
+ currentRoleAllPrivileges = _directPrivilegesForRole[currentRole];
+
+ // Need to do the same thing for the indirect roles
+ unordered_set<RoleName>& currentRoleIndirectRoles =
+ _roleToIndirectSubordinates[currentRole];
+ currentRoleIndirectRoles.clear();
+ const std::vector<RoleName>& currentRoleDirectRoles = _roleToSubordinates[currentRole];
+ for (std::vector<RoleName>::const_iterator it = currentRoleDirectRoles.begin();
+ it != currentRoleDirectRoles.end(); ++it) {
+ currentRoleIndirectRoles.insert(*it);
}
- // Recursively add children's privileges to current role's "all privileges" vector.
- const std::vector<RoleName>& children = _roleToSubordinates[currentRole];
- for (std::vector<RoleName>::const_iterator roleIt = children.begin();
- roleIt != children.end(); ++roleIt) {
+ // Recursively add children's privileges to current role's "all privileges" vector, and
+ // children's roles to current roles's "indirect roles" vector.
+ for (std::vector<RoleName>::const_iterator roleIt = currentRoleDirectRoles.begin();
+ roleIt != currentRoleDirectRoles.end(); ++roleIt) {
const RoleName& childRole = *roleIt;
Status status = _recomputePrivilegeDataHelper(childRole, inProgressRoles, visitedRoles);
if (status != Status::OK()) {
@@ -462,6 +506,14 @@ namespace {
privIt != childsPrivileges.end(); ++privIt) {
Privilege::addPrivilegeToPrivilegeVector(&currentRoleAllPrivileges, *privIt);
}
+
+ // We also know that the "indirect roles" for the child is also correct, so we can add
+ // those roles to our "indirect roles" set.
+ const unordered_set<RoleName>& childsRoles = _roleToIndirectSubordinates[childRole];
+ for (unordered_set<RoleName>::const_iterator childsRoleIt = childsRoles.begin();
+ childsRoleIt != childsRoles.end(); ++childsRoleIt) {
+ currentRoleIndirectRoles.insert(*childsRoleIt);
+ }
}
if (inProgressRoles.back() != currentRole)
diff --git a/src/mongo/db/auth/role_graph.h b/src/mongo/db/auth/role_graph.h
index be6c12a93c0..b7dcbbaa80f 100644
--- a/src/mongo/db/auth/role_graph.h
+++ b/src/mongo/db/auth/role_graph.h
@@ -89,6 +89,13 @@ namespace mongo {
RoleNameIterator getDirectSubordinates(const RoleName& role);
/**
+ * Returns an iterator that can be used to get a full list of roles that this role inherits
+ * privileges from. This includes its direct subordinate roles as well as the subordinates
+ * of its subordinates, and so on.
+ */
+ RoleNameIterator getIndirectSubordinates(const RoleName& role);
+
+ /**
* Returns a vector of the privileges that the given role has been directly granted.
* Privileges that have been granted transitively through this role's subordinate roles are
* not included.
@@ -232,11 +239,12 @@ namespace mongo {
// Represents all the outgoing edges to other roles from any given role.
- typedef unordered_map<RoleName, vector<RoleName> > EdgeSet;
+ typedef unordered_map<RoleName, std::vector<RoleName> > EdgeSet;
// Maps a role name to a list of privileges associated with that role.
typedef unordered_map<RoleName, PrivilegeVector> RolePrivilegeMap;
EdgeSet _roleToSubordinates;
+ unordered_map<RoleName, unordered_set<RoleName> > _roleToIndirectSubordinates;
EdgeSet _roleToMembers;
RolePrivilegeMap _directPrivilegesForRole;
RolePrivilegeMap _allPrivilegesForRole;
diff --git a/src/mongo/db/auth/role_graph_test.cpp b/src/mongo/db/auth/role_graph_test.cpp
index 6f907cc67d3..3abb14974a1 100644
--- a/src/mongo/db/auth/role_graph_test.cpp
+++ b/src/mongo/db/auth/role_graph_test.cpp
@@ -108,6 +108,30 @@ namespace {
}
ASSERT_FALSE(it.more());
+ it = graph.getIndirectSubordinates(roleA); // should have roleB, roleC and roleD
+ bool hasB = false;
+ bool hasC = false;
+ bool hasD = false;
+ int num = 0;
+ while (it.more()) {
+ ++num;
+ RoleName cur = it.next();
+ if (cur == roleB) {
+ hasB = true;
+ } else if (cur == roleC) {
+ hasC = true;
+ } else if (cur == roleD) {
+ hasD = true;
+ } else {
+ FAIL(mongoutils::str::stream() << "unexpected role returned: " <<
+ cur.getFullName());
+ }
+ }
+ ASSERT_EQUALS(3, num);
+ ASSERT(hasB);
+ ASSERT(hasC);
+ ASSERT(hasD);
+
it = graph.getDirectSubordinates(roleB); // should be roleC and roleD, order doesn't matter
cur = it.next();
if (cur == roleC) {
diff --git a/src/mongo/db/auth/role_name.h b/src/mongo/db/auth/role_name.h
index 45fb8a007fd..93942e14c67 100644
--- a/src/mongo/db/auth/role_name.h
+++ b/src/mongo/db/auth/role_name.h
@@ -149,7 +149,7 @@ MONGO_HASH_NAMESPACE_END
namespace mongo {
- // RoleNameIterator for iterating over an unordered_set of RoleNames.
+ // RoleNameIterator for iterating over a vector of RoleNames.
class RoleNameVectorIterator : public RoleNameIterator::Impl {
MONGO_DISALLOW_COPYING(RoleNameVectorIterator);