AuthorizationManager::AuthorizationManager(AuthzManagerExternalState* externalState) : _authEnabled(false), _externalState(externalState), _version(schemaVersionInvalid), _isFetchPhaseBusy(false) { _updateCacheGeneration_inlock(); }
void AuthorizationManagerImpl::_invalidateUserCache_inlock(const CacheGuard& guard) { _updateCacheGeneration_inlock(guard); _userCache.invalidateIf([](const UserName& a, const User*) { return true; }); // Reread the schema version before acquiring the next user. _version = schemaVersionInvalid; }
std::vector<UserHandle> AuthorizationManagerImpl::invalidateUserByNameNoPin( OperationContext* opCtx, const UserName& userName) { CacheGuard guard(opCtx, this); _updateCacheGeneration_inlock(guard); _userCache.invalidate(userName); return _fetchPinnedUsers(guard, opCtx); }
void AuthorizationManagerImpl::invalidateUsersFromDB(OperationContext* opCtx, StringData dbname) { CacheGuard guard(opCtx, this); _updateCacheGeneration_inlock(guard); _userCache.invalidateIf( [&](const UserName& user, const User*) { return user.getDB() == dbname; }); setPinnedUsers_inlock(guard, _fetchPinnedUsers(guard, opCtx)); }
void AuthorizationManager::_invalidateUserCache_inlock() { _updateCacheGeneration_inlock(); for (unordered_map<UserName, User*>::iterator it = _userCache.begin(); it != _userCache.end(); ++it) { fassert(17266, it->second != internalSecurity.user); it->second->invalidate(); } _userCache.clear(); // Reread the schema version before acquiring the next user. _version = schemaVersionInvalid; }
void AuthorizationManager::invalidateUserByName(const UserName& userName) { CacheGuard guard(this, CacheGuard::fetchSynchronizationManual); _updateCacheGeneration_inlock(); unordered_map<UserName, User*>::iterator it = _userCache.find(userName); if (it == _userCache.end()) { return; } User* user = it->second; _userCache.erase(it); user->invalidate(); }
StatusWith<UserHandle> AuthorizationManagerImpl::acquireUser(OperationContext* opCtx, const UserName& userName) { if (userName == internalSecurity.user->getName()) { return internalSecurity.user; } boost::optional<UserHandle> cachedUser = _userCache.get(userName); auto returnUser = [&](boost::optional<UserHandle> cachedUser) { auto ret = *cachedUser; fassert(16914, ret.get()); LOG(1) << "Returning user " << userName << " from cache"; return ret; }; // The userCache is thread-safe, so if we can get a user out of the cache we don't need to // take any locks! if (cachedUser) { return returnUser(cachedUser); } // Otherwise make sure we have the locks we need and check whether and wait on another // thread is fetching into the cache CacheGuard guard(opCtx, this); while ((boost::none == (cachedUser = _userCache.get(userName))) && guard.otherUpdateInFetchPhase()) { guard.wait(); } if (cachedUser != boost::none) { return returnUser(cachedUser); } guard.beginFetchPhase(); // If there's still no user in the cache, then we need to go to disk. Take the slow path. LOG(1) << "Getting user " << userName << " from disk"; auto ret = _acquireUserSlowPath(guard, opCtx, userName); guard.endFetchPhase(); if (!ret.isOK()) { return ret.getStatus(); } auto user = std::move(ret.getValue()); if (user->isValid()) { _updateCacheGeneration_inlock(guard); } return user; }
void AuthorizationManager::invalidateUsersFromDB(const std::string& dbname) { CacheGuard guard(this, CacheGuard::fetchSynchronizationManual); _updateCacheGeneration_inlock(); unordered_map<UserName, User*>::iterator it = _userCache.begin(); while (it != _userCache.end()) { User* user = it->second; if (user->getName().getDB() == dbname) { _userCache.erase(it++); user->invalidate(); } else { ++it; } } }
std::vector<UserHandle> AuthorizationManagerImpl::_fetchPinnedUsers(CacheGuard& guard, OperationContext* opCtx) { // Get the list of users to pin const auto usersToPin = authorizationManagerPinnedUsers.getUserNames(); if (usersToPin.empty()) { return {}; } // Remove any users that shouldn't be pinned anymore or that are invalid. std::vector<UserHandle> newPinnedUsers; std::copy_if(_pinnedUsers.begin(), _pinnedUsers.end(), std::back_inserter(newPinnedUsers), [&](const UserHandle& user) { if (!user->isValid()) return false; return std::any_of( usersToPin.begin(), usersToPin.end(), [&](const UserName& userName) { return (user->getName() == userName); }); }); const auto findPinnedUser = [&](const auto& userName) { return std::find_if( newPinnedUsers.begin(), newPinnedUsers.end(), [&](const auto& userHandle) { return (userHandle->getName() == userName); }); }; while (guard.otherUpdateInFetchPhase()) { guard.wait(); } // Begin the fetch phase but don't yield any locks. We want re-pinning of users to block other // operations until all the users are refreshed. guard.beginFetchPhaseNoYield(); bool cacheUpdated = false; for (const auto& userName : usersToPin) { auto existingPin = findPinnedUser(userName); if (existingPin != newPinnedUsers.end()) { newPinnedUsers.push_back(*existingPin); continue; } cacheUpdated = true; auto swUser = _acquireUserSlowPath(guard, opCtx, userName); if (swUser.isOK()) { newPinnedUsers.emplace(newPinnedUsers.end(), std::move(swUser.getValue())); } else { const auto& status = swUser.getStatus(); // If the user is not found, then it might just not exist yet. Skip this user for now. if (status != ErrorCodes::UserNotFound) { warning() << "Unable to fetch pinned user " << userName.toString() << ": " << status; } } } if (cacheUpdated) _updateCacheGeneration_inlock(guard); return newPinnedUsers; }