Status AuthzManagerExternalStateMongos::getRoleDescription(OperationContext* opCtx, const RoleName& roleName, PrivilegeFormat showPrivileges, BSONObj* result) { BSONObjBuilder rolesInfoCmd; rolesInfoCmd.append("rolesInfo", BSON_ARRAY(BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << roleName.getRole() << AuthorizationManager::ROLE_DB_FIELD_NAME << roleName.getDB()))); addShowPrivilegesToBuilder(&rolesInfoCmd, showPrivileges); BSONObjBuilder builder; const bool ok = Grid::get(opCtx)->catalogClient()->runUserManagementReadCommand( opCtx, "admin", rolesInfoCmd.obj(), &builder); BSONObj cmdResult = builder.obj(); if (!ok) { return getStatusFromCommandResult(cmdResult); } std::vector<BSONElement> foundRoles = cmdResult[rolesFieldName(showPrivileges)].Array(); if (foundRoles.size() == 0) { return Status(ErrorCodes::RoleNotFound, "Role \"" + roleName.toString() + "\" not found"); } if (foundRoles.size() > 1) { return Status(ErrorCodes::RoleDataInconsistent, str::stream() << "Found multiple roles on the \"" << roleName.getDB() << "\" database with name \"" << roleName.getRole() << "\""); } *result = foundRoles[0].Obj().getOwned(); return Status::OK(); }
Status AuthorizationManager::updateRoleDocument(OperationContext* txn, const RoleName& role, const BSONObj& updateObj, const BSONObj& writeConcern) const { Status status = _externalState->updateOne( txn, rolesCollectionNamespace, BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << role.getRole() << AuthorizationManager::ROLE_DB_FIELD_NAME << role.getDB()), updateObj, false, writeConcern); if (status.isOK()) { return status; } if (status.code() == ErrorCodes::NoMatchingDocument) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role " << role.getFullName() << " not found"); } if (status.code() == ErrorCodes::UnknownError) { return Status(ErrorCodes::RoleModificationFailed, status.reason()); } return status; }
Status AuthzManagerExternalStateMongos::getRoleDescription(OperationContext* txn, const RoleName& roleName, bool showPrivileges, BSONObj* result) { BSONObj rolesInfoCmd = BSON("rolesInfo" << BSON_ARRAY(BSON( AuthorizationManager::ROLE_NAME_FIELD_NAME << roleName.getRole() << AuthorizationManager::ROLE_DB_FIELD_NAME << roleName.getDB())) << "showPrivileges" << showPrivileges); BSONObjBuilder builder; const bool ok = grid.catalogManager(txn) ->runUserManagementReadCommand(txn, "admin", rolesInfoCmd, &builder); BSONObj cmdResult = builder.obj(); if (!ok) { return Command::getStatusFromCommandResult(cmdResult); } std::vector<BSONElement> foundRoles = cmdResult["roles"].Array(); if (foundRoles.size() == 0) { return Status(ErrorCodes::RoleNotFound, "Role \"" + roleName.toString() + "\" not found"); } if (foundRoles.size() > 1) { return Status(ErrorCodes::RoleDataInconsistent, str::stream() << "Found multiple roles on the \"" << roleName.getDB() << "\" database with name \"" << roleName.getRole() << "\""); } *result = foundRoles[0].Obj().getOwned(); return Status::OK(); }
Status RoleGraph::removeAllRolesFromRole(const RoleName& victim) { typedef std::vector<RoleName> RoleNameVector; if (!roleExists(victim)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << victim.getFullName() << " does not exist", 0); } if (isBuiltinRole(victim)) { return Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << "Cannot remove roles from built-in role: " << victim.getFullName(), 0); } RoleNameVector& subordinatesOfVictim = _roleToSubordinates[victim]; for (RoleNameVector::const_iterator subordinateRole = subordinatesOfVictim.begin(), end = subordinatesOfVictim.end(); subordinateRole != end; ++subordinateRole) { RoleNameVector& membersOfSubordinate = _roleToMembers[*subordinateRole]; RoleNameVector::iterator toErase = std::find(membersOfSubordinate.begin(), membersOfSubordinate.end(), victim); fassert(17173, toErase != membersOfSubordinate.end()); membersOfSubordinate.erase(toErase); } subordinatesOfVictim.clear(); return Status::OK(); }
Status RoleGraph::addRoleToRole(const RoleName& recipient, const RoleName& role) { if (!roleExists(recipient)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << recipient.getFullName() << " does not exist"); } if (isBuiltinRole(recipient)) { return Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << "Cannot grant roles to built-in role: " << role.getFullName()); } if (!roleExists(role)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << role.getFullName() << " does not exist"); } if (std::find(_roleToSubordinates[recipient].begin(), _roleToSubordinates[recipient].end(), role) == _roleToSubordinates[recipient].end()) { // Only add role if it's not already present _roleToSubordinates[recipient].push_back(role); _roleToMembers[role].push_back(recipient); } return Status::OK(); }
Status RoleGraph::deleteRole(const RoleName& role) { if (!roleExists(role)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << role.getFullName() << " does not exist", 0); } if (isBuiltinRole(role)) { return Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << "Cannot delete built-in role: " << role.getFullName(), 0); } for (std::vector<RoleName>::iterator it = _roleToSubordinates[role].begin(); it != _roleToSubordinates[role].end(); ++it) { _roleToMembers[*it].erase( std::find(_roleToMembers[*it].begin(), _roleToMembers[*it].end(), role)); } for (std::vector<RoleName>::iterator it = _roleToMembers[role].begin(); it != _roleToMembers[role].end(); ++it) { _roleToSubordinates[*it].erase( std::find(_roleToSubordinates[*it].begin(), _roleToSubordinates[*it].end(), role)); } _roleToSubordinates.erase(role); _roleToIndirectSubordinates.erase(role); _roleToMembers.erase(role); _directPrivilegesForRole.erase(role); _allPrivilegesForRole.erase(role); _allRoles.erase(role); return Status::OK(); }
Status AuthzManagerExternalStateMongos::getRoleDescription(const RoleName& roleName, BSONObj* result) { try { scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection( AuthorizationManager::rolesCollectionNamespace)); BSONObj cmdResult; conn->get()->runCommand( "admin", BSON("rolesInfo" << BSON_ARRAY(BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << roleName.getRole() << AuthorizationManager::ROLE_SOURCE_FIELD_NAME << roleName.getDB()))), cmdResult); if (!cmdResult["ok"].trueValue()) { int code = cmdResult["code"].numberInt(); if (code == 0) code = ErrorCodes::UnknownError; return Status(ErrorCodes::Error(code), cmdResult["errmsg"].str()); } *result = cmdResult["roles"]["0"].Obj().getOwned(); conn->done(); return Status::OK(); } catch (const DBException& e) { return e.toStatus(); } }
Status AuthzManagerExternalStateLocal::_getRoleDescription_inlock(const RoleName& roleName, bool showPrivileges, BSONObj* result) { if (!_roleGraph.roleExists(roleName)) return Status(ErrorCodes::RoleNotFound, "No role named " + roleName.toString()); mutablebson::Document resultDoc; fassert(17162, resultDoc.root().appendString( AuthorizationManager::ROLE_NAME_FIELD_NAME, roleName.getRole())); fassert(17163, resultDoc.root().appendString( AuthorizationManager::ROLE_SOURCE_FIELD_NAME, roleName.getDB())); fassert(17267, resultDoc.root().appendBool("isBuiltin", _roleGraph.isBuiltinRole(roleName))); mutablebson::Element rolesElement = resultDoc.makeElementArray("roles"); fassert(17164, resultDoc.root().pushBack(rolesElement)); mutablebson::Element inheritedRolesElement = resultDoc.makeElementArray("inheritedRoles"); fassert(17165, resultDoc.root().pushBack(inheritedRolesElement)); mutablebson::Element privilegesElement = resultDoc.makeElementArray("privileges"); mutablebson::Element inheritedPrivilegesElement = resultDoc.makeElementArray("inheritedPrivileges"); if (showPrivileges) { fassert(17166, resultDoc.root().pushBack(privilegesElement)); } mutablebson::Element warningsElement = resultDoc.makeElementArray("warnings"); addRoleNameObjectsToArrayElement(rolesElement, _roleGraph.getDirectSubordinates(roleName)); if (_roleGraphState == roleGraphStateConsistent) { addRoleNameObjectsToArrayElement( inheritedRolesElement, _roleGraph.getIndirectSubordinates(roleName)); if (showPrivileges) { addPrivilegeObjectsOrWarningsToArrayElement( privilegesElement, warningsElement, _roleGraph.getDirectPrivileges(roleName)); addPrivilegeObjectsOrWarningsToArrayElement( inheritedPrivilegesElement, warningsElement, _roleGraph.getAllPrivileges(roleName)); fassert(17323, resultDoc.root().pushBack(inheritedPrivilegesElement)); } } else if (showPrivileges) { warningsElement.appendString( "", "Role graph state inconsistent; only direct privileges available."); addPrivilegeObjectsOrWarningsToArrayElement( privilegesElement, warningsElement, _roleGraph.getDirectPrivileges(roleName)); } if (warningsElement.hasChildren()) { fassert(17167, resultDoc.root().pushBack(warningsElement)); } *result = resultDoc.getObject(); return Status::OK(); }
void AuthorizationSession::_buildAuthenticatedRolesVector() { _authenticatedRoleNames.clear(); for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end(); ++it) { RoleNameIterator roles = (*it)->getIndirectRoles(); while (roles.more()) { RoleName roleName = roles.next(); _authenticatedRoleNames.push_back(RoleName(roleName.getRole(), roleName.getDB())); } } }
Status RoleGraph::removeAllPrivilegesFromRole(const RoleName& role) { if (!roleExists(role)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << role.getFullName() << " does not exist", 0); } if (isBuiltinRole(role)) { return Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << "Cannot remove privileges from built-in role: " << role.getFullName()); } _directPrivilegesForRole[role].clear(); return Status::OK(); }
Status RoleGraph::removePrivilegeFromRole(const RoleName& role, const Privilege& privilegeToRemove) { if (!roleExists(role)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << role.getFullName() << " does not exist", 0); } if (isBuiltinRole(role)) { return Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << "Cannot remove privileges from built-in role: " << role.getFullName()); } PrivilegeVector& currentPrivileges = _directPrivilegesForRole[role]; for (PrivilegeVector::iterator it = currentPrivileges.begin(); it != currentPrivileges.end(); ++it) { Privilege& curPrivilege = *it; if (curPrivilege.getResourcePattern() == privilegeToRemove.getResourcePattern()) { ActionSet curActions = curPrivilege.getActions(); if (!curActions.isSupersetOf(privilegeToRemove.getActions())) { // Didn't possess all the actions being removed. return Status( ErrorCodes::PrivilegeNotFound, mongoutils::str::stream() << "Role: " << role.getFullName() << " does not contain a privilege on " << privilegeToRemove.getResourcePattern().toString() << " with actions: " << privilegeToRemove.getActions().toString(), 0); } curPrivilege.removeActions(privilegeToRemove.getActions()); if (curPrivilege.getActions().empty()) { currentPrivileges.erase(it); } return Status::OK(); } } return Status(ErrorCodes::PrivilegeNotFound, mongoutils::str::stream() << "Role: " << role.getFullName() << " does not " "contain any privileges on " << privilegeToRemove.getResourcePattern().toString(), 0); }
Status RoleGraph::addPrivilegeToRole(const RoleName& role, const Privilege& privilegeToAdd) { if (!roleExists(role)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << role.getFullName() << " does not exist", 0); } if (isBuiltinRole(role)) { return Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << "Cannot grant privileges to built-in role: " << role.getFullName(), 0); } _addPrivilegeToRoleNoChecks(role, privilegeToAdd); return Status::OK(); }
Status checkAuthForDropRoleCommand(Client* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = AuthorizationSession::get(client); RoleName roleName; Status status = auth::parseDropRoleCommand(cmdObj, dbname, &roleName); if (!status.isOK()) { return status; } if (!authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(roleName.getDB()), ActionType::dropRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to drop roles from the " << roleName.getDB() << " database"); } return Status::OK(); }
Status RoleGraph::createRole(const RoleName& role) { if (roleExists(role)) { return Status(ErrorCodes::DuplicateKey, mongoutils::str::stream() << "Role: " << role.getFullName() << " already exists", 0); } _createRoleDontCheckIfRoleExists(role); return Status::OK(); }
// NOTE: Current runtime of this is O(n*m) where n is the size of the current PrivilegeVector // for the given role, and m is the size of the privilegesToAdd vector. // If this was a PrivilegeSet (sorted on resource) rather than a PrivilegeVector, we // could do this in O(n+m) instead. Status RoleGraph::addPrivilegesToRole(const RoleName& role, const PrivilegeVector& privilegesToAdd) { if (!roleExists(role)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << role.getFullName() << " does not exist", 0); } if (isBuiltinRole(role)) { return Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << "Cannot grant privileges to built-in role: " << role.getFullName(), 0); } for (PrivilegeVector::const_iterator it = privilegesToAdd.begin(); it != privilegesToAdd.end(); ++it) { _addPrivilegeToRoleNoChecks(role, *it); } return Status::OK(); }
Status AuthzManagerExternalStateMongos::getRoleDescription(const RoleName& roleName, bool showPrivileges, BSONObj* result) { try { scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection( AuthorizationManager::rolesCollectionNamespace)); BSONObj cmdResult; conn->get()->runCommand( "admin", BSON("rolesInfo" << BSON_ARRAY(BSON(AuthorizationManager::ROLE_NAME_FIELD_NAME << roleName.getRole() << AuthorizationManager::ROLE_SOURCE_FIELD_NAME << roleName.getDB())) << "showPrivileges" << showPrivileges), cmdResult); if (!cmdResult["ok"].trueValue()) { int code = cmdResult["code"].numberInt(); if (code == 0) code = ErrorCodes::UnknownError; return Status(ErrorCodes::Error(code), cmdResult["errmsg"].str()); } std::vector<BSONElement> foundRoles = cmdResult["roles"].Array(); if (foundRoles.size() == 0) { return Status(ErrorCodes::RoleNotFound, "Role \"" + roleName.toString() + "\" not found"); } if (foundRoles.size() > 1) { return Status(ErrorCodes::RoleDataInconsistent, mongoutils::str::stream() << "Found multiple roles on the \"" << roleName.getDB() << "\" database with name \"" << roleName.getRole() << "\""); } *result = foundRoles[0].Obj().getOwned(); conn->done(); return Status::OK(); } catch (const DBException& e) { return e.toStatus(); } }
Status AuthorizationManager::getBSONForRole(RoleGraph* graph, const RoleName& roleName, mutablebson::Element result) { if (!graph->roleExists(roleName)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << roleName.getFullName() << "does not name an existing role"); } std::string id = mongoutils::str::stream() << roleName.getDB() << "." << roleName.getRole(); result.appendString("_id", id); result.appendString(ROLE_NAME_FIELD_NAME, roleName.getRole()); result.appendString(ROLE_SOURCE_FIELD_NAME, roleName.getDB()); // Build privileges array mutablebson::Element privilegesArrayElement = result.getDocument().makeElementArray("privileges"); result.pushBack(privilegesArrayElement); const PrivilegeVector& privileges = graph->getDirectPrivileges(roleName); Status status = getBSONForPrivileges(privileges, privilegesArrayElement); if (!status.isOK()) { return status; } // Build roles array mutablebson::Element rolesArrayElement = result.getDocument().makeElementArray("roles"); result.pushBack(rolesArrayElement); for (RoleNameIterator roles = graph->getDirectSubordinates(roleName); roles.more(); roles.next()) { const RoleName& subRole = roles.get(); mutablebson::Element roleObj = result.getDocument().makeElementObject(""); roleObj.appendString(ROLE_NAME_FIELD_NAME, subRole.getRole()); roleObj.appendString(ROLE_SOURCE_FIELD_NAME, subRole.getDB()); rolesArrayElement.pushBack(roleObj); } return Status::OK(); }
Status RoleGraph::removeRoleFromRole(const RoleName& recipient, const RoleName& role) { if (!roleExists(recipient)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << recipient.getFullName() << " does not exist", 0); } if (isBuiltinRole(recipient)) { return Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << "Cannot remove roles from built-in role: " << role.getFullName(), 0); } if (!roleExists(role)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << role.getFullName() << " does not exist", 0); } std::vector<RoleName>::iterator itToRm = std::find(_roleToMembers[role].begin(), _roleToMembers[role].end(), recipient); if (itToRm != _roleToMembers[role].end()) { _roleToMembers[role].erase(itToRm); } else { return Status(ErrorCodes::RolesNotRelated, mongoutils::str::stream() << recipient.getFullName() << " is not a member" " of " << role.getFullName(), 0); } itToRm = std::find( _roleToSubordinates[recipient].begin(), _roleToSubordinates[recipient].end(), role); fassert(16827, itToRm != _roleToSubordinates[recipient].end()); _roleToSubordinates[recipient].erase(itToRm); return Status::OK(); }
bool RoleGraph::isBuiltinRole(const RoleName& role) { if (!NamespaceString::validDBName(role.getDB()) || role.getDB() == "$external") { return false; } bool isAdminDB = role.getDB() == ADMIN_DBNAME; if (role.getRole() == BUILTIN_ROLE_READ) { return true; } else if (role.getRole() == BUILTIN_ROLE_READ_WRITE) { return true; } else if (role.getRole() == BUILTIN_ROLE_USER_ADMIN) { return true; } else if (role.getRole() == BUILTIN_ROLE_DB_ADMIN) { return true; } else if (role.getRole() == BUILTIN_ROLE_DB_OWNER) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_READ_ANY_DB) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_READ_WRITE_ANY_DB) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_USER_ADMIN_ANY_DB) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_DB_ADMIN_ANY_DB) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_CLUSTER_MONITOR) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_HOST_MANAGEMENT) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_CLUSTER_MANAGEMENT) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_CLUSTER_ADMIN) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_BACKUP) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_RESTORE) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_ROOT) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_INTERNAL) { return true; } return false; }
bool AuthorizationSession::isAuthorizedToRevokeRole(const RoleName& role) { return isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName(role.getDB()), ActionType::revokeRole); }
bool RoleGraph::isBuiltinRole(const RoleName& role) { bool isAdminDB = role.getDB() == ADMIN_DBNAME; if (role.getRole() == BUILTIN_ROLE_READ) { return true; } else if (role.getRole() == BUILTIN_ROLE_READ_WRITE) { return true; } else if (role.getRole() == BUILTIN_ROLE_USER_ADMIN) { return true; } else if (role.getRole() == BUILTIN_ROLE_DB_ADMIN) { return true; } else if (role.getRole() == BUILTIN_ROLE_DB_OWNER) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_READ_ANY_DB) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_READ_WRITE_ANY_DB) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_USER_ADMIN_ANY_DB) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_DB_ADMIN_ANY_DB) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_CLUSTER_MONITOR) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_HOST_MANAGEMENT) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_CLUSTER_MANAGEMENT) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_CLUSTER_ADMIN) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_ROOT) { return true; } else if (isAdminDB && role.getRole() == BUILTIN_ROLE_INTERNAL) { return true; } return false; }
bool RoleGraph::addPrivilegesForBuiltinRole(const RoleName& roleName, PrivilegeVector* result) { const bool isAdminDB = (roleName.getDB() == ADMIN_DBNAME); if (roleName.getRole() == BUILTIN_ROLE_READ) { addReadOnlyDbPrivileges(result, roleName.getDB()); } else if (roleName.getRole() == BUILTIN_ROLE_READ_WRITE) { addReadWriteDbPrivileges(result, roleName.getDB()); } else if (roleName.getRole() == BUILTIN_ROLE_USER_ADMIN) { addUserAdminDbPrivileges(result, roleName.getDB()); } else if (roleName.getRole() == BUILTIN_ROLE_DB_ADMIN) { addDbAdminDbPrivileges(result, roleName.getDB()); } else if (roleName.getRole() == BUILTIN_ROLE_DB_OWNER) { addDbOwnerPrivileges(result, roleName.getDB()); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_READ_ANY_DB) { addReadOnlyAnyDbPrivileges(result); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_READ_WRITE_ANY_DB) { addReadWriteAnyDbPrivileges(result); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_USER_ADMIN_ANY_DB) { addUserAdminAnyDbPrivileges(result); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_DB_ADMIN_ANY_DB) { addDbAdminAnyDbPrivileges(result); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_CLUSTER_MONITOR) { addClusterMonitorPrivileges(result); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_HOST_MANAGEMENT) { addHostManagerPrivileges(result); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_CLUSTER_MANAGEMENT) { addClusterManagerPrivileges(result); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_CLUSTER_ADMIN) { addClusterAdminPrivileges(result); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_ROOT) { addRootRolePrivileges(result); } else if (isAdminDB && roleName.getRole() == BUILTIN_ROLE_INTERNAL) { addInternalRolePrivileges(result); } else { return false; } return true; }
bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); AuthzDocumentsUpdateGuard updateGuard(authzManager); if (!updateGuard.tryLock("Grant privileges to role")) { addStatus(Status(ErrorCodes::LockBusy, "Could not lock auth data update lock."), result); return false; } RoleName roleName; PrivilegeVector privilegesToAdd; BSONObj writeConcern; Status status = auth::parseAndValidateRolePrivilegeManipulationCommands( cmdObj, "grantPrivilegesToRole", dbname, &roleName, &privilegesToAdd, &writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } if (!authzManager->roleExists(roleName)) { addStatus(Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << roleName.getFullName() << " does not name an existing role"), result); return false; } if (authzManager->isBuiltinRole(roleName)) { addStatus(Status(ErrorCodes::InvalidRoleModification, mongoutils::str::stream() << roleName.getFullName() << " is a built-in role and cannot be modified."), result); return false; } PrivilegeVector privileges = authzManager->getDirectPrivilegesForRole(roleName); for (PrivilegeVector::iterator it = privilegesToAdd.begin(); it != privilegesToAdd.end(); ++it) { Privilege::addPrivilegeToPrivilegeVector(&privileges, *it); } // Build up update modifier object to $set privileges. mutablebson::Document updateObj; mutablebson::Element setElement = updateObj.makeElementObject("$set"); status = updateObj.root().pushBack(setElement); if (!status.isOK()) { addStatus(status, result); return false; } mutablebson::Element privilegesElement = updateObj.makeElementArray("privileges"); status = setElement.pushBack(privilegesElement); if (!status.isOK()) { addStatus(status, result); return false; } status = authzManager->getBSONForPrivileges(privileges, privilegesElement); if (!status.isOK()) { addStatus(status, result); return false; } BSONObjBuilder updateBSONBuilder; updateObj.writeTo(&updateBSONBuilder); status = authzManager->updateRoleDocument( roleName, updateBSONBuilder.done(), writeConcern); if (!status.isOK()) { addStatus(status, result); return false; } return true; }
Status RoleGraph::_recomputePrivilegeDataHelper(const RoleName& startingRole, unordered_set<RoleName>& visitedRoles) { if (visitedRoles.count(startingRole)) { return Status::OK(); } std::vector<RoleName> inProgressRoles; inProgressRoles.push_back(startingRole); while (inProgressRoles.size()) { const RoleName currentRole = inProgressRoles.back(); fassert(17277, !visitedRoles.count(currentRole)); if (!roleExists(currentRole)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << "Role: " << currentRole.getFullName() << " does not exist", 0); } // Check for cycles { const std::vector<RoleName>::const_iterator begin = inProgressRoles.begin(); // The currentRole will always be last so don't look there. const std::vector<RoleName>::const_iterator end = --inProgressRoles.end(); const std::vector<RoleName>::const_iterator firstOccurence = std::find(begin, end, currentRole); if (firstOccurence != end) { std::ostringstream os; os << "Cycle in dependency graph: "; for (std::vector<RoleName>::const_iterator it = firstOccurence; it != end; ++it) { os << it->getFullName() << " -> "; } os << currentRole.getFullName(); return Status(ErrorCodes::GraphContainsCycle, os.str()); } } // Make sure we've already visited all subordinate roles before worrying about this one. const std::vector<RoleName>& currentRoleDirectRoles = _roleToSubordinates[currentRole]; std::vector<RoleName>::const_iterator roleIt; for (roleIt = currentRoleDirectRoles.begin(); roleIt != currentRoleDirectRoles.end(); ++roleIt) { const RoleName& childRole = *roleIt; if (!visitedRoles.count(childRole)) { inProgressRoles.push_back(childRole); break; } } // If roleIt didn't reach the end of currentRoleDirectRoles that means we found a child // of currentRole that we haven't visited yet. if (roleIt != currentRoleDirectRoles.end()) { continue; } // At this point, we know that we've already visited all child roles of currentRole // and thus their "all privileges" sets are correct and can be added to currentRole's // "all privileges" set // 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]; currentRoleAllPrivileges = _directPrivilegesForRole[currentRole]; // Need to do the same thing for the indirect roles unordered_set<RoleName>& currentRoleIndirectRoles = _roleToIndirectSubordinates[currentRole]; currentRoleIndirectRoles.clear(); 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, and // children's roles to current roles's "indirect roles" vector. for (std::vector<RoleName>::const_iterator roleIt = currentRoleDirectRoles.begin(); roleIt != currentRoleDirectRoles.end(); ++roleIt) { // At this point, we already know that the "all privilege" set for the child is // correct, so add those privileges to our "all privilege" set. const RoleName& childRole = *roleIt; const PrivilegeVector& childsPrivileges = _allPrivilegesForRole[childRole]; for (PrivilegeVector::const_iterator privIt = childsPrivileges.begin(); privIt != childsPrivileges.end(); ++privIt) { Privilege::addPrivilegeToPrivilegeVector(¤tRoleAllPrivileges, *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); } } visitedRoles.insert(currentRole); inProgressRoles.pop_back(); } return Status::OK(); }