Privilege AuthorizationSession::_modifyPrivilegeForSpecialCases(const Privilege& privilege) { ActionSet newActions; newActions.addAllActionsFromSet(privilege.getActions()); NamespaceString ns( privilege.getResource() ); if (ns.coll() == "system.users") { if (newActions.contains(ActionType::insert) || newActions.contains(ActionType::update) || newActions.contains(ActionType::remove)) { // End users can't modify system.users directly, only the system can. newActions.addAction(ActionType::userAdminV1); } else { newActions.addAction(ActionType::userAdmin); } newActions.removeAction(ActionType::find); newActions.removeAction(ActionType::insert); newActions.removeAction(ActionType::update); newActions.removeAction(ActionType::remove); } else if (ns.coll() == "system.profile") { newActions.removeAction(ActionType::find); newActions.addAction(ActionType::profileRead); } else if (ns.coll() == "system.indexes" && newActions.contains(ActionType::find)) { newActions.removeAction(ActionType::find); newActions.addAction(ActionType::indexRead); } return Privilege(privilege.getResource(), newActions); }
bool AuthorizationSession::_isAuthorizedForPrivilege(const Privilege& privilege) { AuthorizationManager& authMan = getAuthorizationManager(); const ResourcePattern& target(privilege.getResourcePattern()); ResourcePattern resourceSearchList[resourceSearchListCapacity]; const int resourceSearchListLength = buildResourceSearchList(target, resourceSearchList); ActionSet unmetRequirements = privilege.getActions(); UserSet::iterator it = _authenticatedUsers.begin(); while (it != _authenticatedUsers.end()) { User* user = *it; if (!user->isValid()) { // Make a good faith effort to acquire an up-to-date user object, since the one // we've cached is marked "out-of-date." UserName name = user->getName(); User* updatedUser; Status status = authMan.acquireUser(name, &updatedUser); switch (status.code()) { case ErrorCodes::OK: { // Success! Replace the old User object with the updated one. fassert(17067, _authenticatedUsers.replaceAt(it, updatedUser) == user); authMan.releaseUser(user); user = updatedUser; LOG(1) << "Updated session cache of user information for " << name; break; } case ErrorCodes::UserNotFound: { // User does not exist anymore; remove it from _authenticatedUsers. fassert(17068, _authenticatedUsers.removeAt(it) == user); authMan.releaseUser(user); LOG(1) << "Removed deleted user " << name << " from session cache of user information."; continue; // No need to advance "it" in this case. } default: // Unrecognized error; assume that it's transient, and continue working with the // out-of-date privilege data. warning() << "Could not fetch updated user privilege information for " << name << "; continuing to use old information. Reason is " << status; break; } } for (int i = 0; i < resourceSearchListLength; ++i) { ActionSet userActions = user->getActionsForResource(resourceSearchList[i]); unmetRequirements.removeAllActionsFromSet(userActions); if (unmetRequirements.empty()) return true; } ++it; } return false; }
void User::addPrivilege(const Privilege& privilegeToAdd) { ResourcePrivilegeMap::iterator it = _privileges.find(privilegeToAdd.getResourcePattern()); if (it == _privileges.end()) { // No privilege exists yet for this resource _privileges.insert(std::make_pair(privilegeToAdd.getResourcePattern(), privilegeToAdd)); } else { dassert(it->first == privilegeToAdd.getResourcePattern()); it->second.addActions(privilegeToAdd.getActions()); } }
void Privilege::addPrivilegeToPrivilegeVector(PrivilegeVector* privileges, const Privilege& privilegeToAdd) { for (PrivilegeVector::iterator it = privileges->begin(); it != privileges->end(); ++it) { if (it->getResourcePattern() == privilegeToAdd.getResourcePattern()) { it->addActions(privilegeToAdd.getActions()); return; } } // No privilege exists yet for this resource privileges->push_back(privilegeToAdd); }
bool AuthorizationSession::_isAuthorizedForPrivilege(const Privilege& privilege) { const ResourcePattern& target(privilege.getResourcePattern()); ResourcePattern resourceSearchList[resourceSearchListCapacity]; const int resourceSearchListLength = buildResourceSearchList(target, resourceSearchList); ActionSet unmetRequirements = privilege.getActions(); for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end(); ++it) { User* user = *it; if (user->getSchemaVersion() == AuthorizationManager::schemaVersion24 && (target.isDatabasePattern() || target.isExactNamespacePattern()) && !user->hasProbedV1(target.databaseToMatch())) { UserName name = user->getName(); User* updatedUser; Status status = getAuthorizationManager().acquireV1UserProbedForDb( name, target.databaseToMatch(), &updatedUser); if (status.isOK()) { if (user != updatedUser) { LOG(1) << "Updated session cache with privileges on the " << target.databaseToMatch() << " database for V1 user " << name; fassert(17226, _authenticatedUsers.replaceAt(it, updatedUser) == user); } getAuthorizationManager().releaseUser(user); user = updatedUser; } else if (status != ErrorCodes::UserNotFound) { warning() << "Could not fetch updated user privilege information for V1-style " "user " << name << "; continuing to use old information. Reason is " << status; } } for (int i = 0; i < resourceSearchListLength; ++i) { ActionSet userActions = user->getActionsForResource(resourceSearchList[i]); unmetRequirements.removeAllActionsFromSet(userActions); if (unmetRequirements.empty()) return true; } } return false; }
Privilege AuthorizationManager::_modifyPrivilegeForSpecialCases(const Privilege& privilege) { ActionSet newActions; newActions.addAllActionsFromSet(privilege.getActions()); std::string collectionName = NamespaceString(privilege.getResource()).coll; if (collectionName == "system.users") { newActions.removeAction(ActionType::find); newActions.removeAction(ActionType::insert); newActions.removeAction(ActionType::update); newActions.removeAction(ActionType::remove); newActions.addAction(ActionType::userAdmin); } else if (collectionName == "system.profle" && newActions.contains(ActionType::find)) { newActions.removeAction(ActionType::find); newActions.addAction(ActionType::profileRead); } return Privilege(privilege.getResource(), newActions); }
bool PrivilegeSet::hasPrivilege(const Privilege& desiredPrivilege) { if (desiredPrivilege.getActions().empty()) return true; StringData resourceSearchList[2]; resourceSearchList[0] = WILDCARD_RESOURCE; resourceSearchList[1] = desiredPrivilege.getResource(); ActionSet unmetRequirements = desiredPrivilege.getActions(); for (int i = 0; i < boost::size(resourceSearchList); ++i) { ResourcePrivilegeCacheEntry* entry = _lookupEntry(resourceSearchList[i]); if (NULL == entry) continue; if (entry->dirty) _rebuildEntry(resourceSearchList[i], entry); unmetRequirements.removeAllActionsFromSet(entry->actions); if (unmetRequirements.empty()) return true; } return false; }
Status AuthorizationManager::_probeForPrivilege(const Privilege& privilege) { Privilege modifiedPrivilege = _modifyPrivilegeForSpecialCases(privilege); if (_acquiredPrivileges.hasPrivilege(modifiedPrivilege)) return Status::OK(); std::string dbname = nsToDatabase(modifiedPrivilege.getResource()); for (PrincipalSet::iterator iter = _authenticatedPrincipals.begin(), end = _authenticatedPrincipals.end(); iter != end; ++iter) { Principal* principal = *iter; if (!principal->isImplicitPrivilegeAcquisitionEnabled()) continue; if (principal->isDatabaseProbed(dbname)) continue; _acquirePrivilegesForPrincipalFromDatabase(dbname, principal->getName()); principal->markDatabaseAsProbed(dbname); if (_acquiredPrivileges.hasPrivilege(modifiedPrivilege)) return Status::OK(); } return Status(ErrorCodes::Unauthorized, "unauthorized", 0); }
bool AuthorizationSession::_isAuthorizedForPrivilege(const Privilege& privilege) { const ResourcePattern& target(privilege.getResourcePattern()); ResourcePattern resourceSearchList[resourceSearchListCapacity]; const int resourceSearchListLength = buildResourceSearchList(target, resourceSearchList); ActionSet unmetRequirements = privilege.getActions(); PrivilegeVector defaultPrivileges = getDefaultPrivileges(); for (PrivilegeVector::iterator it = defaultPrivileges.begin(); it != defaultPrivileges.end(); ++it) { for (int i = 0; i < resourceSearchListLength; ++i) { if (!(it->getResourcePattern() == resourceSearchList[i])) continue; ActionSet userActions = it->getActions(); unmetRequirements.removeAllActionsFromSet(userActions); if (unmetRequirements.empty()) return true; } } for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end(); ++it) { User* user = *it; for (int i = 0; i < resourceSearchListLength; ++i) { ActionSet userActions = user->getActionsForResource(resourceSearchList[i]); unmetRequirements.removeAllActionsFromSet(userActions); if (unmetRequirements.empty()) return true; } } return false; }
Status AuthorizationSession::checkAuthorizedToRevokePrivilege(const Privilege& privilege) { const ResourcePattern& resource = privilege.getResourcePattern(); if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) { if (!isAuthorizedForActionsOnResource( ResourcePattern::forDatabaseName(resource.databaseToMatch()), ActionType::revokeRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to revoke privileges on the " << resource.databaseToMatch() << "database"); } } else if (!isAuthorizedForActionsOnResource(ResourcePattern::forDatabaseName("admin"), ActionType::revokeRole)) { return Status(ErrorCodes::Unauthorized, "To revoke privileges affecting multiple databases or the cluster," " must be authorized to revoke roles from the admin database"); } 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 AuthorizationSession::_checkAuthForPrivilegeHelper(const Privilege& privilege) { AuthorizationManager& authMan = getAuthorizationManager(); Privilege modifiedPrivilege = _modifyPrivilegeForSpecialCases(privilege); // Need to check not just the resource of the privilege, but also just the database // component and the "*" resource. std::string resourceSearchList[3]; resourceSearchList[0] = AuthorizationManager::WILDCARD_RESOURCE_NAME; resourceSearchList[1] = nsToDatabase(modifiedPrivilege.getResource()); resourceSearchList[2] = modifiedPrivilege.getResource(); ActionSet unmetRequirements = modifiedPrivilege.getActions(); UserSet::iterator it = _authenticatedUsers.begin(); while (it != _authenticatedUsers.end()) { User* user = *it; if (!user->isValid()) { // Make a good faith effort to acquire an up-to-date user object, since the one // we've cached is marked "out-of-date." UserName name = user->getName(); User* updatedUser; Status status = authMan.acquireUser(name, &updatedUser); switch (status.code()) { case ErrorCodes::OK: { // Success! Replace the old User object with the updated one. fassert(17067, _authenticatedUsers.replaceAt(it, updatedUser) == user); authMan.releaseUser(user); user = updatedUser; LOG(1) << "Updated session cache of user information for " << name; break; } case ErrorCodes::UserNotFound: { // User does not exist anymore; remove it from _authenticatedUsers. fassert(17068, _authenticatedUsers.removeAt(it) == user); authMan.releaseUser(user); LOG(1) << "Removed deleted user " << name << " from session cache of user information."; continue; // No need to advance "it" in this case. } default: // Unrecognized error; assume that it's transient, and continue working with the // out-of-date privilege data. warning() << "Could not fetch updated user privilege information for " << name << "; continuing to use old information. Reason is " << status; break; } } for (int i = 0; i < static_cast<int>(boost::size(resourceSearchList)); ++i) { ActionSet userActions = user->getActionsForResource(resourceSearchList[i]); unmetRequirements.removeAllActionsFromSet(userActions); if (unmetRequirements.empty()) return Status::OK(); } ++it; } return Status(ErrorCodes::Unauthorized, "unauthorized"); }
bool ParsedPrivilege::privilegeToParsedPrivilege(const Privilege& privilege, ParsedPrivilege* result, std::string* errmsg) { ParsedResource parsedResource; if (privilege.getResourcePattern().isExactNamespacePattern()) { parsedResource.setDb(privilege.getResourcePattern().databaseToMatch()); parsedResource.setCollection(privilege.getResourcePattern().collectionToMatch()); } else if (privilege.getResourcePattern().isDatabasePattern()) { parsedResource.setDb(privilege.getResourcePattern().databaseToMatch()); parsedResource.setCollection(""); } else if (privilege.getResourcePattern().isCollectionPattern()) { parsedResource.setDb(""); parsedResource.setCollection(privilege.getResourcePattern().collectionToMatch()); } else if (privilege.getResourcePattern().isAnyNormalResourcePattern()) { parsedResource.setDb(""); parsedResource.setCollection(""); } else if (privilege.getResourcePattern().isClusterResourcePattern()) { parsedResource.setCluster(true); } else if (privilege.getResourcePattern().isAnyResourcePattern()) { parsedResource.setAnyResource(true); } else { *errmsg = stream() << privilege.getResourcePattern().toString() << " is not a valid user-grantable resource pattern"; return false; } result->clear(); result->setResource(parsedResource); result->setActions(privilege.getActions().getActionsAsStrings()); return result->isValid(errmsg); }