summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2022-05-10 17:54:01 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-05-24 05:17:25 +0000
commit4fab61e9c5006e9a4c06860dc9e49e1d422ee859 (patch)
treec383da8e16d40422c3dff8dea6a38c6e2935e256
parentd3dae653da44b8cb87ff2a9687c0468aa52b6b44 (diff)
downloadmongo-4fab61e9c5006e9a4c06860dc9e49e1d422ee859.tar.gz
SERVER-66360 Remove multi-user authentication support
-rw-r--r--buildscripts/idl/idl_check_compatibility.py29
-rw-r--r--src/mongo/db/audit.h2
-rw-r--r--src/mongo/db/auth/SConscript2
-rw-r--r--src/mongo/db/auth/access_checks.idl6
-rw-r--r--src/mongo/db/auth/authorization_checks.cpp2
-rw-r--r--src/mongo/db/auth/authorization_checks.h3
-rw-r--r--src/mongo/db/auth/authorization_session.cpp4
-rw-r--r--src/mongo/db/auth/authorization_session.h37
-rw-r--r--src/mongo/db/auth/authorization_session_for_test.cpp31
-rw-r--r--src/mongo/db/auth/authorization_session_for_test.h22
-rw-r--r--src/mongo/db/auth/authorization_session_impl.cpp503
-rw-r--r--src/mongo/db/auth/authorization_session_impl.h23
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp44
-rw-r--r--src/mongo/db/auth/impersonation_session.cpp3
-rw-r--r--src/mongo/db/auth/user_set.cpp121
-rw-r--r--src/mongo/db/auth/user_set.h127
-rw-r--r--src/mongo/db/auth/user_set_test.cpp112
-rw-r--r--src/mongo/db/clientcursor.cpp2
-rw-r--r--src/mongo/db/clientcursor.h19
-rw-r--r--src/mongo/db/commands/connection_status.cpp11
-rw-r--r--src/mongo/db/commands/create.idl2
-rw-r--r--src/mongo/db/commands/end_sessions_command.cpp4
-rw-r--r--src/mongo/db/commands/find_cmd.cpp2
-rw-r--r--src/mongo/db/commands/getmore_cmd.cpp6
-rw-r--r--src/mongo/db/commands/kill_op_cmd_base.cpp7
-rw-r--r--src/mongo/db/commands/kill_sessions_command.cpp9
-rw-r--r--src/mongo/db/commands/list_collections.cpp2
-rw-r--r--src/mongo/db/commands/list_indexes.cpp2
-rw-r--r--src/mongo/db/commands/refresh_sessions_command.cpp4
-rw-r--r--src/mongo/db/commands/run_aggregate.cpp2
-rw-r--r--src/mongo/db/commands/sessions_commands.idl4
-rw-r--r--src/mongo/db/curop.cpp25
-rw-r--r--src/mongo/db/cursor_manager.cpp4
-rw-r--r--src/mongo/db/dollar_tenant_decoration_test.cpp6
-rw-r--r--src/mongo/db/exec/js_function.cpp6
-rw-r--r--src/mongo/db/index_builds_coordinator_mongod.cpp2
-rw-r--r--src/mongo/db/introspect.cpp1
-rw-r--r--src/mongo/db/kill_sessions.cpp42
-rw-r--r--src/mongo/db/kill_sessions.h4
-rw-r--r--src/mongo/db/kill_sessions_common.cpp7
-rw-r--r--src/mongo/db/kill_sessions_common.h6
-rw-r--r--src/mongo/db/logical_session_id_helpers.cpp55
-rw-r--r--src/mongo/db/pipeline/aggregate_command.idl2
-rw-r--r--src/mongo/db/pipeline/document_source_list_local_sessions.cpp7
-rw-r--r--src/mongo/db/s/forwardable_operation_metadata.cpp6
-rw-r--r--src/mongo/embedded/embedded_auth_session.cpp15
-rw-r--r--src/mongo/rpc/metadata/impersonated_user_metadata.cpp18
-rw-r--r--src/mongo/s/commands/cluster_killcursors_cmd.cpp5
-rw-r--r--src/mongo/s/commands/cluster_list_collections_cmd.cpp6
-rw-r--r--src/mongo/s/query/cluster_aggregation_planner.cpp4
-rw-r--r--src/mongo/s/query/cluster_cursor_manager.cpp12
-rw-r--r--src/mongo/s/query/cluster_cursor_manager.h15
-rw-r--r--src/mongo/s/query/cluster_cursor_manager_test.cpp126
-rw-r--r--src/mongo/s/query/cluster_find.cpp8
-rw-r--r--src/mongo/s/query/store_possible_cursor.cpp4
55 files changed, 539 insertions, 994 deletions
diff --git a/buildscripts/idl/idl_check_compatibility.py b/buildscripts/idl/idl_check_compatibility.py
index 1a30f29428a..82428ef7e3b 100644
--- a/buildscripts/idl/idl_check_compatibility.py
+++ b/buildscripts/idl/idl_check_compatibility.py
@@ -200,6 +200,13 @@ IGNORE_COMMANDS_LIST: List[str] = [
'setChangeStreamOptions',
]
+RENAMED_COMPLEX_ACCESS_CHECKS = dict(
+ # Changed during 6.1 as part of removing multi-auth support.
+ get_single_user='get_authenticated_user',
+ get_authenticated_usernames='get_authenticated_username',
+ get_impersonated_usernames='get_impersonated_username',
+)
+
class FieldCompatibility:
"""Information about a Field to check compatibility."""
@@ -1069,6 +1076,26 @@ def split_complex_checks(
return checks, sorted(privileges, key=lambda x: len(x.action_type), reverse=True)
+def compare_complex_access_checks(new_checks: List[str], old_checks: List[str]) -> bool:
+ """Compare two sets of access check names for equivalence."""
+ # Quick path, common case where access checks match exactly.
+ if set(new_checks).issubset(old_checks):
+ return True
+
+ def map_complex_access_check_name(name: str) -> str:
+ """Returns normalized name if it exists in the map, otherwise returns self."""
+ if name in RENAMED_COMPLEX_ACCESS_CHECKS:
+ return RENAMED_COMPLEX_ACCESS_CHECKS[name]
+ else:
+ return name
+
+ # Slow path allowing for access check renames.
+ old_normalized = [map_complex_access_check_name(name) for name in old_checks]
+ new_normalized = [map_complex_access_check_name(name) for name in new_checks]
+
+ return set(new_normalized).issubset(old_normalized)
+
+
def check_complex_checks(ctxt: IDLCompatibilityContext,
old_complex_checks: List[syntax.AccessCheck],
new_complex_checks: List[syntax.AccessCheck], cmd: syntax.Command,
@@ -1080,7 +1107,7 @@ def check_complex_checks(ctxt: IDLCompatibilityContext,
else:
old_checks, old_privileges = split_complex_checks(old_complex_checks)
new_checks, new_privileges = split_complex_checks(new_complex_checks)
- if not set(new_checks).issubset(old_checks):
+ if not compare_complex_access_checks(new_checks, old_checks):
ctxt.add_new_complex_checks_not_subset_error(cmd_name, new_idl_file_path)
if len(new_privileges) > len(old_privileges):
diff --git a/src/mongo/db/audit.h b/src/mongo/db/audit.h
index 684983bf7be..418c73e408c 100644
--- a/src/mongo/db/audit.h
+++ b/src/mongo/db/audit.h
@@ -75,7 +75,7 @@ extern std::function<void(ServiceContext*)> initializeSynchronizeJob;
* roleNames stored in ImpersonatedClientAttrs.
*/
struct ImpersonatedClientAttrs {
- std::vector<UserName> userNames;
+ UserName userName;
std::vector<RoleName> roleNames;
ImpersonatedClientAttrs() = default;
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index 57af14b709d..a2bcc5b3295 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -181,7 +181,6 @@ env.Library(
'authorization_session_impl.cpp',
'authz_manager_external_state.cpp',
'authz_session_external_state.cpp',
- 'user_set.cpp',
'authorization_manager_impl_parameters.idl',
],
LIBDEPS=[
@@ -541,7 +540,6 @@ env.CppUnitTest(
'sasl_scram_test.cpp',
'security_key_test.cpp',
'user_document_parser_test.cpp',
- 'user_set_test.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
diff --git a/src/mongo/db/auth/access_checks.idl b/src/mongo/db/auth/access_checks.idl
index d51e03d111c..3fd6549a842 100644
--- a/src/mongo/db/auth/access_checks.idl
+++ b/src/mongo/db/auth/access_checks.idl
@@ -37,10 +37,10 @@ enums:
kCheckCursorSessionPrivilege : "check_cursor_session_privilege"
kClearImpersonatedUserData : "clear_impersonated_user_data"
kGetAuthenticatedRoleNames : "get_authenticated_role_names"
- kGetAuthenticatedUserNames : "get_authenticated_user_names"
+ kGetAuthenticatedUserName : "get_authenticated_user_name"
kGetImpersonatedRoleNames : "get_impersonated_role_names"
- kGetImpersonatedUserNames : "get_impersonated_user_names"
- kGetSingleUser : "get_single_user"
+ kGetImpersonatedUserName : "get_impersonated_user_name"
+ kGetAuthenticatedUser : "get_authenticated_user"
kIsAuthenticated : "is_authenticated"
kIsAuthenticatedAsUserWithRole : "is_authenticated_as_user_with_role"
kIsAuthorizedForAnyActionOnAnyResourceInDB : "is_authorized_for_any_action_on_any_resource_in_db"
diff --git a/src/mongo/db/auth/authorization_checks.cpp b/src/mongo/db/auth/authorization_checks.cpp
index 06fa2164fbc..fa3d947f3f1 100644
--- a/src/mongo/db/auth/authorization_checks.cpp
+++ b/src/mongo/db/auth/authorization_checks.cpp
@@ -175,7 +175,7 @@ Status checkAuthForDelete(AuthorizationSession* authSession,
Status checkAuthForKillCursors(AuthorizationSession* authSession,
const NamespaceString& ns,
- UserNameIterator cursorOwner) {
+ const boost::optional<UserName>& cursorOwner) {
if (authSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
ActionType::killAnyCursor)) {
return Status::OK();
diff --git a/src/mongo/db/auth/authorization_checks.h b/src/mongo/db/auth/authorization_checks.h
index 4a211fb0ee1..10979dc263c 100644
--- a/src/mongo/db/auth/authorization_checks.h
+++ b/src/mongo/db/auth/authorization_checks.h
@@ -32,7 +32,6 @@
#include "mongo/base/status.h"
#include "mongo/db/auth/authorization_session.h"
-#include "mongo/db/auth/user_set.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/ops/write_ops.h"
@@ -79,7 +78,7 @@ Status checkAuthForDelete(AuthorizationSession* authSession,
// identifier.
Status checkAuthForKillCursors(AuthorizationSession* authSession,
const NamespaceString& cursorNss,
- UserNameIterator cursorOwner);
+ const boost::optional<UserName>& cursorOwner);
// Attempts to get the privileges necessary to run the aggregation pipeline specified in
// 'request' on the namespace 'ns' either directly on mongoD or via mongoS.
diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp
index fc5810e7a18..807d2bc66d7 100644
--- a/src/mongo/db/auth/authorization_session.cpp
+++ b/src/mongo/db/auth/authorization_session.cpp
@@ -57,9 +57,9 @@ namespace mongo {
AuthorizationSession::~AuthorizationSession() = default;
void AuthorizationSession::ScopedImpersonate::swap() {
- auto impersonations = _authSession._getImpersonations();
using std::swap;
- swap(*std::get<0>(impersonations), _users);
+ auto impersonations = _authSession._getImpersonations();
+ swap(*std::get<0>(impersonations), _user);
swap(*std::get<1>(impersonations), _roles);
}
diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h
index b6cab1ae951..777da1ad56d 100644
--- a/src/mongo/db/auth/authorization_session.h
+++ b/src/mongo/db/auth/authorization_session.h
@@ -40,7 +40,6 @@
#include "mongo/db/auth/authz_session_external_state.h"
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/user_name.h"
-#include "mongo/db/auth/user_set.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
@@ -79,9 +78,9 @@ public:
class ScopedImpersonate {
public:
ScopedImpersonate(AuthorizationSession* authSession,
- std::vector<UserName>* users,
+ boost::optional<UserName>* user,
std::vector<RoleName>* roles)
- : _authSession(*authSession), _users(*users), _roles(*roles) {
+ : _authSession(*authSession), _user(*user), _roles(*roles) {
swap();
}
@@ -93,7 +92,7 @@ public:
void swap();
AuthorizationSession& _authSession;
- std::vector<UserName>& _users;
+ boost::optional<UserName>& _user;
std::vector<RoleName>& _roles;
};
@@ -153,9 +152,8 @@ public:
// and ownership of the user stays with the AuthorizationManager
virtual User* lookupUser(const UserName& name) = 0;
- // Returns the single user on this auth session. If no user is authenticated, or if
- // multiple users are authenticated, this method will throw an exception.
- virtual User* getSingleUser() = 0;
+ // Get the authenticated user's object handle, if any.
+ virtual boost::optional<UserHandle> getAuthenticatedUser() = 0;
// Is auth disabled? Returns true if auth is disabled.
virtual bool shouldIgnoreAuthChecks() = 0;
@@ -163,8 +161,8 @@ public:
// Is authenticated as at least one user.
virtual bool isAuthenticated() = 0;
- // Gets an iterator over the names of all authenticated users stored in this manager.
- virtual UserNameIterator getAuthenticatedUserNames() = 0;
+ // Gets the name of the currently authenticated user (if any).
+ virtual boost::optional<UserName> getAuthenticatedUserName() = 0;
// Gets an iterator over the roles of all authenticated users stored in this manager.
virtual RoleNameIterator getAuthenticatedRoleNames() = 0;
@@ -258,13 +256,13 @@ public:
// Returns true if the current session possesses a privilege which applies to the resource.
virtual bool isAuthorizedForAnyActionOnResource(const ResourcePattern& resource) = 0;
- // Replaces the data for users that a system user is impersonating with new data.
- // The auditing system adds these users and their roles to each audit record in the log.
- virtual void setImpersonatedUserData(const std::vector<UserName>& usernames,
+ // Replaces the data for the user that a system user is impersonating with new data.
+ // The auditing system adds this user and their roles to each audit record in the log.
+ virtual void setImpersonatedUserData(const UserName& username,
const std::vector<RoleName>& roles) = 0;
- // Gets an iterator over the names of all users that the system user is impersonating.
- virtual UserNameIterator getImpersonatedUserNames() = 0;
+ // Gets the name of the user, if any, that the system user is impersonating.
+ virtual boost::optional<UserName> getImpersonatedUserName() = 0;
// Gets an iterator over the roles of all users that the system user is impersonating.
virtual RoleNameIterator getImpersonatedRoleNames() = 0;
@@ -283,10 +281,11 @@ public:
// in common.
virtual bool isCoauthorizedWithClient(Client* opClient, WithLock opClientLock) = 0;
- // Returns true if the session and 'userNameIter' share an authenticated user, or if both have
- // no authenticated users. Impersonated users are not considered as 'authenticated' for the
- // purpose of this check. This always returns true if auth is not enabled.
- virtual bool isCoauthorizedWith(UserNameIterator userNameIter) = 0;
+ // Returns true if the specified userName is the currently authenticated user,
+ // or if the session is unauthenticated and `boost::none` is specified.
+ // Impersonated users are not considered as 'authenticated' for the purpose of this check.
+ // This always returns true if auth is not enabled.
+ virtual bool isCoauthorizedWith(const boost::optional<UserName>& userName) = 0;
// Tells whether impersonation is active or not. This state is set when
// setImpersonatedUserData is called and cleared when clearImpersonatedUserData is
@@ -308,7 +307,7 @@ public:
virtual bool mayBypassWriteBlockingMode() const = 0;
protected:
- virtual std::tuple<std::vector<UserName>*, std::vector<RoleName>*> _getImpersonations() = 0;
+ virtual std::tuple<boost::optional<UserName>*, std::vector<RoleName>*> _getImpersonations() = 0;
};
// Returns a status encoding whether the current session in the specified `opCtx` has privilege to
diff --git a/src/mongo/db/auth/authorization_session_for_test.cpp b/src/mongo/db/auth/authorization_session_for_test.cpp
index 2bf9fae9e2b..3b0d7f247db 100644
--- a/src/mongo/db/auth/authorization_session_for_test.cpp
+++ b/src/mongo/db/auth/authorization_session_for_test.cpp
@@ -38,26 +38,19 @@
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/user.h"
#include "mongo/db/auth/user_name.h"
-#include "mongo/db/auth/user_set.h"
namespace mongo {
constexpr StringData AuthorizationSessionForTest::kTestDBName;
-AuthorizationSessionForTest::~AuthorizationSessionForTest() {
- revokeAllPrivileges();
-}
-
void AuthorizationSessionForTest::assumePrivilegesForDB(Privilege privilege, StringData dbName) {
assumePrivilegesForDB(std::vector<Privilege>{privilege}, dbName);
}
void AuthorizationSessionForTest::assumePrivilegesForDB(PrivilegeVector privileges,
StringData dbName) {
- UserHandle userHandle(User(UserName("authorizationSessionForTestUser", dbName)));
- userHandle->addPrivileges(privileges);
-
- _authenticatedUsers.add(userHandle);
- _testUsers.emplace_back(std::move(userHandle));
+ _authenticatedUser = UserHandle(User(UserName("authorizationSessionForTestUser", dbName)));
+ _authenticatedUser.get()->addPrivileges(privileges);
+ _authenticationMode = AuthorizationSession::AuthenticationMode::kConnection;
_updateInternalAuthorizationState();
}
@@ -73,22 +66,4 @@ void AuthorizationSessionForTest::assumePrivilegesForBuiltinRole(const RoleName&
assumePrivilegesForDB(privileges, db);
}
-void AuthorizationSessionForTest::revokePrivilegesForDB(StringData dbName) {
- _authenticatedUsers.removeByDBName(dbName);
- _testUsers.erase(
- std::remove_if(_testUsers.begin(),
- _testUsers.end(),
- [&](const auto& user) { return dbName == user->getName().getDB(); }),
- _testUsers.end());
-}
-
-void AuthorizationSessionForTest::revokeAllPrivileges() {
- _testUsers.erase(std::remove_if(_testUsers.begin(),
- _testUsers.end(),
- [&](const auto& user) {
- _authenticatedUsers.removeByDBName(user->getName().getDB());
- return true;
- }),
- _testUsers.end());
-}
} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_session_for_test.h b/src/mongo/db/auth/authorization_session_for_test.h
index bc6a75c798f..61145661a95 100644
--- a/src/mongo/db/auth/authorization_session_for_test.h
+++ b/src/mongo/db/auth/authorization_session_for_test.h
@@ -50,11 +50,6 @@ public:
static constexpr StringData kTestDBName = "authorizationSessionForTestDB"_sd;
/**
- * Cleans up any privileges granted via assumePrivilegesForDB().
- */
- ~AuthorizationSessionForTest();
-
- /**
* Grants this session all privileges in 'privileges' for the database named 'dbName'. Any prior
* privileges granted on 'dbName' via a call to this method are erased.
*
@@ -64,25 +59,8 @@ public:
void assumePrivilegesForDB(Privilege privilege, StringData dbName = kTestDBName);
/**
- * Revoke all privileges granted via assumePrivilegesForDB() on the database named 'dbName'.
- *
- * Do not use this method if also adding users via addAndAuthorizeUser() in the same database.
- */
- void revokePrivilegesForDB(StringData dbName);
-
- /**
- * Revokes all privileges granted via assumePrivilegesForDB() on every database.
- *
- * Do not use this method if also adding users via addAndAuthorizeUser() in the same database.
- */
- void revokeAllPrivileges();
-
- /**
* Grants this session all privileges for the given builtin role. Do not mix with other methods.
*/
void assumePrivilegesForBuiltinRole(const RoleName& roleName);
-
-private:
- std::vector<UserHandle> _testUsers;
};
} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_session_impl.cpp b/src/mongo/db/auth/authorization_session_impl.cpp
index b18cc379089..173a19cfd58 100644
--- a/src/mongo/db/auth/authorization_session_impl.cpp
+++ b/src/mongo/db/auth/authorization_session_impl.cpp
@@ -165,8 +165,8 @@ AuthorizationSessionImpl::AuthorizationSessionImpl(
_mayBypassWriteBlockingMode(false) {}
AuthorizationSessionImpl::~AuthorizationSessionImpl() {
- invariant(_authenticatedUsers.count() == 0,
- "All authenticated users should be logged out by the Client destruction hook");
+ invariant(_authenticatedUser == boost::none,
+ "The authenticated user should have been logged out by the Client destruction hook");
}
AuthorizationManager& AuthorizationSessionImpl::getAuthorizationManager() {
@@ -179,13 +179,12 @@ void AuthorizationSessionImpl::startRequest(OperationContext* opCtx) {
if (_authenticationMode == AuthenticationMode::kSecurityToken) {
// Previously authenticated using SecurityToken,
// clear that user and reset to unauthenticated state.
- invariant(_authenticatedUsers.count() <= 1);
- if (auto users = std::exchange(_authenticatedUsers, {}); users.count()) {
+ if (auto user = std::exchange(_authenticatedUser, boost::none); user) {
LOGV2_DEBUG(6161507,
3,
"security token based user still authenticated at start of request, "
"clearing from authentication state",
- "user"_attr = users.getNames().get().toBSON(true /* encode tenant */));
+ "user"_attr = user.get()->getName().toBSON(true /* encode tenant */));
_updateInternalAuthorizationState();
}
_authenticationMode = AuthenticationMode::kNone;
@@ -202,15 +201,11 @@ void AuthorizationSessionImpl::startContractTracking() {
Status AuthorizationSessionImpl::addAndAuthorizeUser(OperationContext* opCtx,
const UserName& userName) try {
- auto checkForMultipleUsers = [&]() {
- const auto userCount = _authenticatedUsers.count();
- if (userCount == 0) {
- // This is the first authentication.
- return;
- }
- invariant(userCount == 1);
-
- auto previousUser = _authenticatedUsers.begin()->get()->getName();
+ // Check before we start to reveal as little as possible. Note that we do not need the lock
+ // because only the Client thread can mutate _authenticatedUser.
+ if (_authenticatedUser) {
+ // Already logged in.
+ auto previousUser = _authenticatedUser.get()->getName();
if (previousUser == userName) {
// Allow reauthenticating as the same user, but warn.
LOGV2_WARNING(5626700,
@@ -222,6 +217,8 @@ Status AuthorizationSessionImpl::addAndAuthorizeUser(OperationContext* opCtx,
uassert(5626703,
"Each client connection may only be authenticated once",
!hasStrictAPI || allowMultipleUsersWithApiStrict.shouldFail());
+
+ return Status::OK();
} else {
uassert(5626701,
str::stream() << "Each client connection may only be authenticated once. "
@@ -231,19 +228,11 @@ Status AuthorizationSessionImpl::addAndAuthorizeUser(OperationContext* opCtx,
str::stream() << "Client has attempted to authenticate on multiple databases."
<< "Already authenticated as: " << previousUser);
}
- };
-
- // Check before we start to reveal as little as possible. Note that we do not need the lock
- // because only the Client thread can mutate _authenticatedUsers.
- checkForMultipleUsers();
-
- AuthorizationManager* authzManager = AuthorizationManager::get(opCtx->getServiceContext());
- auto swUser = authzManager->acquireUser(opCtx, userName);
- if (!swUser.isOK()) {
- return swUser.getStatus();
+ MONGO_UNREACHABLE;
}
- auto user = std::move(swUser.getValue());
+ AuthorizationManager* authzManager = AuthorizationManager::get(opCtx->getServiceContext());
+ auto user = uassertStatusOK(authzManager->acquireUser(opCtx, userName));
auto restrictionStatus = user->validateRestrictions(opCtx);
if (!restrictionStatus.isOK()) {
@@ -269,7 +258,7 @@ Status AuthorizationSessionImpl::addAndAuthorizeUser(OperationContext* opCtx,
} else {
_authenticationMode = AuthenticationMode::kConnection;
}
- _authenticatedUsers.add(std::move(user));
+ _authenticatedUser = std::move(user);
// If there are any users and roles in the impersonation data, clear it out.
clearImpersonatedUserData();
@@ -284,29 +273,15 @@ Status AuthorizationSessionImpl::addAndAuthorizeUser(OperationContext* opCtx,
User* AuthorizationSessionImpl::lookupUser(const UserName& name) {
_contract.addAccessCheck(AccessCheckEnum::kLookupUser);
- auto user = _authenticatedUsers.lookup(name);
- return user ? user.get() : nullptr;
-}
-
-User* AuthorizationSessionImpl::getSingleUser() {
- UserName userName;
-
- _contract.addAccessCheck(AccessCheckEnum::kGetSingleUser);
-
- auto userNameItr = getAuthenticatedUserNames();
- if (userNameItr.more()) {
- userName = userNameItr.next();
- if (userNameItr.more()) {
- uasserted(
- ErrorCodes::Unauthorized,
- "logical sessions can't have multiple authenticated users (for more details see: "
- "https://docs.mongodb.com/manual/core/authentication/#authentication-methods)");
- }
- } else {
- uasserted(ErrorCodes::Unauthorized, "there are no users authenticated");
+ if (!_authenticatedUser || (_authenticatedUser.get()->getName() != name)) {
+ return nullptr;
}
+ return _authenticatedUser->get();
+}
- return lookupUser(userName);
+boost::optional<UserHandle> AuthorizationSessionImpl::getAuthenticatedUser() {
+ _contract.addAccessCheck(AccessCheckEnum::kGetAuthenticatedUser);
+ return _authenticatedUser;
}
void AuthorizationSessionImpl::logoutSecurityTokenUser(Client* client) {
@@ -316,13 +291,12 @@ void AuthorizationSessionImpl::logoutSecurityTokenUser(Client* client) {
"Attempted to deauth a security token user while using standard login",
_authenticationMode != AuthenticationMode::kConnection);
- auto users = std::exchange(_authenticatedUsers, {});
- invariant(users.count() <= 1);
- if (users.count() == 1) {
+ auto user = std::exchange(_authenticatedUser, boost::none);
+ if (user) {
LOGV2_DEBUG(6161506,
5,
"security token based user explicitly logged out",
- "user"_attr = users.getNames().get().toBSON(true /* encode tenant */));
+ "user"_attr = user.get()->getName().toBSON(true /* encode tenant */));
}
// Explicitly skip auditing the logout event,
@@ -338,12 +312,13 @@ void AuthorizationSessionImpl::logoutAllDatabases(Client* client, StringData rea
"May not log out while using a security token based authentication",
_authenticationMode != AuthenticationMode::kSecurityToken);
- auto users = std::exchange(_authenticatedUsers, {});
- if (users.count() == 0) {
+ auto user = std::exchange(_authenticatedUser, boost::none);
+ if (user == boost::none) {
return;
}
- audit::logLogout(client, reason, users.toBSON(), BSONArray());
+ auto names = BSON_ARRAY(user.get()->getName().toBSON());
+ audit::logLogout(client, reason, names, BSONArray());
clearImpersonatedUserData();
_updateInternalAuthorizationState();
@@ -359,22 +334,26 @@ void AuthorizationSessionImpl::logoutDatabase(Client* client,
"May not log out while using a security token based authentication",
_authenticationMode != AuthenticationMode::kSecurityToken);
- // Emit logout audit event and then remove all users logged into dbname.
- UserSet updatedUsers(_authenticatedUsers);
- updatedUsers.removeByDBName(dbname);
- if (updatedUsers.count() != _authenticatedUsers.count()) {
- audit::logLogout(client, reason, _authenticatedUsers.toBSON(), updatedUsers.toBSON());
+ if (!_authenticatedUser || (_authenticatedUser.get()->getName().getDB() != dbname)) {
+ return;
}
- std::swap(_authenticatedUsers, updatedUsers);
+
+ auto names = BSON_ARRAY(_authenticatedUser.get()->getName().toBSON());
+ audit::logLogout(client, reason, names, BSONArray());
+ _authenticatedUser = boost::none;
clearImpersonatedUserData();
_updateInternalAuthorizationState();
}
-UserNameIterator AuthorizationSessionImpl::getAuthenticatedUserNames() {
- _contract.addAccessCheck(AccessCheckEnum::kGetAuthenticatedUserNames);
+boost::optional<UserName> AuthorizationSessionImpl::getAuthenticatedUserName() {
+ _contract.addAccessCheck(AccessCheckEnum::kGetAuthenticatedUserName);
- return _authenticatedUsers.getNames();
+ if (_authenticatedUser) {
+ return _authenticatedUser.get()->getName();
+ } else {
+ return boost::none;
+ }
}
RoleNameIterator AuthorizationSessionImpl::getAuthenticatedRoleNames() {
@@ -385,9 +364,8 @@ RoleNameIterator AuthorizationSessionImpl::getAuthenticatedRoleNames() {
void AuthorizationSessionImpl::grantInternalAuthorization(Client* client) {
stdx::lock_guard<Client> lk(*client);
- if (MONGO_unlikely(_authenticatedUsers.count() > 0)) {
- invariant(_authenticatedUsers.count() == 1);
- auto previousUser = _authenticatedUsers.begin()->get()->getName();
+ if (MONGO_unlikely(_authenticatedUser != boost::none)) {
+ auto previousUser = _authenticatedUser.get()->getName();
uassert(ErrorCodes::Unauthorized,
str::stream() << "Unable to grant internal authorization, previously authorized as "
<< previousUser.getUnambiguousName(),
@@ -395,7 +373,7 @@ void AuthorizationSessionImpl::grantInternalAuthorization(Client* client) {
return;
}
- _authenticatedUsers.add(*internalSecurity.getUser());
+ _authenticatedUser = *internalSecurity.getUser();
_updateInternalAuthorizationState();
}
@@ -491,10 +469,8 @@ bool AuthorizationSessionImpl::isAuthorizedToCreateRole(const RoleName& roleName
// The user may create a role if the localhost exception is enabled, and they already own the
// role. This implies they have obtained the role through an external authorization mechanism.
if (_externalState->shouldAllowLocalhost()) {
- for (const auto& user : _authenticatedUsers) {
- if (user->hasRole(roleName)) {
- return true;
- }
+ if (_authenticatedUser && _authenticatedUser.get()->hasRole(roleName)) {
+ return true;
}
LOGV2(20241,
"Not authorized to create the first role in the system using the "
@@ -669,14 +645,7 @@ StatusWith<PrivilegeVector> AuthorizationSessionImpl::checkAuthorizedToListColle
bool AuthorizationSessionImpl::isAuthenticatedAsUserWithRole(const RoleName& roleName) {
_contract.addAccessCheck(AccessCheckEnum::kIsAuthenticatedAsUserWithRole);
-
- for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end();
- ++it) {
- if ((*it)->hasRole(roleName)) {
- return true;
- }
- }
- return false;
+ return (_authenticatedUser && _authenticatedUser.get()->hasRole(roleName));
}
bool AuthorizationSessionImpl::shouldIgnoreAuthChecks() {
@@ -688,113 +657,112 @@ bool AuthorizationSessionImpl::shouldIgnoreAuthChecks() {
bool AuthorizationSessionImpl::isAuthenticated() {
_contract.addAccessCheck(AccessCheckEnum::kIsAuthenticated);
- return _authenticatedUsers.begin() != _authenticatedUsers.end();
+ return _authenticatedUser != boost::none;
}
void AuthorizationSessionImpl::_refreshUserInfoAsNeeded(OperationContext* opCtx) {
- AuthorizationManager& authMan = getAuthorizationManager();
- UserSet::iterator it = _authenticatedUsers.begin();
- auto removeUser = [&](const auto& it) {
- // Take out a lock on the client here to ensure that no one reads while
- // _authenticatedUsers is being modified.
- stdx::lock_guard<Client> lk(*opCtx->getClient());
+ if (_authenticatedUser == boost::none) {
+ return;
+ }
- // The user is invalid, so make sure that we erase it from _authenticateUsers.
- _authenticatedUsers.removeAt(it);
+ auto currentUser = _authenticatedUser.get();
+ const auto& name = currentUser->getName();
+
+ const auto clearUser = [&] {
+ stdx::lock_guard<Client> lk(*opCtx->getClient());
+ _authenticatedUser = boost::none;
+ _authenticationMode = AuthenticationMode::kNone;
+ _updateInternalAuthorizationState();
};
- auto replaceUser = [&](const auto& it, UserHandle updatedUser) {
- // Take out a lock on the client here to ensure that no one reads while
- // _authenticatedUsers is being modified.
+ const auto updateUser = [&](auto&& user) {
stdx::lock_guard<Client> lk(*opCtx->getClient());
- _authenticatedUsers.replaceAt(it, std::move(updatedUser));
+ _authenticatedUser = std::move(user);
+ LOGV2_DEBUG(
+ 20244, 1, "Updated session cache of user information for user", "user"_attr = name);
+ _updateInternalAuthorizationState();
};
- while (it != _authenticatedUsers.end()) {
- // Anchor the UserHandle on the stack so we can refer to it throughout this iteration.
- const auto currentUser = *it;
- const auto& name = currentUser->getName();
- auto swUser = authMan.reacquireUser(opCtx, currentUser);
- if (!swUser.isOK()) {
- auto& status = swUser.getStatus();
- // If an external user is no longer in the cache and cannot be acquired from the cache's
- // backing external service, it should be removed from _authenticatedUsers. This
- // guarantees that no operations can be performed until the external authorization
- // provider comes back up.
- if (name.getDB() == "$external"_sd) {
- removeUser(it++);
- LOGV2(5914804,
- "Removed external user from session cache of user information because of "
- "error status",
- "user"_attr = name,
- "status"_attr = status);
- continue; // No need to advance "it" in this case.
- }
+ auto swUser = getAuthorizationManager().reacquireUser(opCtx, currentUser);
+ if (!swUser.isOK()) {
+ auto& status = swUser.getStatus();
+ // If an external user is no longer in the cache and cannot be acquired from the cache's
+ // backing external service, it should be cleared from _authenticatedUser. This
+ // guarantees that no operations can be performed until the external authorization
+ // provider comes back up.
+ if (name.getDB() == "$external"_sd) {
+ clearUser();
+ LOGV2(5914804,
+ "Removed external user from session cache of user information because of "
+ "error status",
+ "user"_attr = name,
+ "status"_attr = status);
+ return;
+ }
- switch (status.code()) {
- case ErrorCodes::UserNotFound: {
- // User does not exist anymore; remove it from _authenticatedUsers.
- removeUser(it++);
- LOGV2(20245,
- "Removed deleted user from session cache of user information",
- "user"_attr = name);
- continue; // No need to advance "it" in this case.
- }
- case ErrorCodes::UnsupportedFormat: {
- // An auth subsystem has explicitly indicated a failure.
- removeUser(it++);
- LOGV2(20246,
- "Removed user from session cache of user information because of "
- "refresh failure",
- "user"_attr = name,
- "error"_attr = status);
- 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.
- LOGV2_WARNING(20247,
- "Could not fetch updated user privilege information for {user}; "
- "continuing to use old information. Reason is {error}",
- "Could not fetch updated user privilege information, continuing "
- "to use old information",
- "user"_attr = name,
- "error"_attr = redact(status));
- break;
+ switch (status.code()) {
+ case ErrorCodes::UserNotFound: {
+ // User does not exist anymore.
+ clearUser();
+ LOGV2(20245,
+ "Removed deleted user from session cache of user information",
+ "user"_attr = name);
+ return;
}
- } else if (!currentUser.isValid() || currentUser->isInvalidated()) {
- // Our user handle has changed, update the our list of users.
- auto updatedUser = std::move(swUser.getValue());
- try {
- uassertStatusOK(updatedUser->validateRestrictions(opCtx));
- } catch (const DBException& ex) {
- removeUser(it++);
-
- LOGV2(20242,
- "Removed user with unmet authentication restrictions from "
- "session cache of user information. Restriction failed",
+ case ErrorCodes::UnsupportedFormat: {
+ // An auth subsystem has explicitly indicated a failure.
+ clearUser();
+ LOGV2(20246,
+ "Removed user from session cache of user information because of "
+ "refresh failure",
"user"_attr = name,
- "reason"_attr = ex.reason());
- continue; // No need to advance "it" in this case.
- } catch (...) {
- removeUser(it++);
-
- LOGV2(20243,
- "Evaluating authentication restrictions for user resulted in an "
- "unknown exception. Removing user from the session cache",
- "user"_attr = name);
- continue; // No need to advance "it" in this case.
+ "error"_attr = status);
+ return;
}
+ default:
+ // Unrecognized error; assume that it's transient, and continue working with the
+ // out-of-date privilege data.
+ LOGV2_WARNING(20247,
+ "Could not fetch updated user privilege information for {user}; "
+ "continuing to use old information. Reason is {error}",
+ "Could not fetch updated user privilege information, continuing "
+ "to use old information",
+ "user"_attr = name,
+ "error"_attr = redact(status));
+ return;
+ }
+ }
- replaceUser(it, std::move(updatedUser));
+ // !ok check above should never fallthrough.
+ invariant(swUser.isOK());
- LOGV2_DEBUG(
- 20244, 1, "Updated session cache of user information for user", "user"_attr = name);
- }
+ if (currentUser.isValid() && !currentUser->isInvalidated()) {
+ // Current user may carry on, no need to update.
+ return;
+ }
- ++it;
+ // Our user handle has changed, update it.
+ auto user = std::move(swUser.getValue());
+ try {
+ uassertStatusOK(user->validateRestrictions(opCtx));
+ } catch (const DBException& ex) {
+ clearUser();
+ LOGV2(20242,
+ "Removed user with unmet authentication restrictions from "
+ "session cache of user information. Restriction failed",
+ "user"_attr = name,
+ "reason"_attr = ex.reason());
+ return;
+ } catch (...) {
+ clearUser();
+ LOGV2(20243,
+ "Evaluating authentication restrictions for user resulted in an "
+ "unknown exception. Removing user from the session cache",
+ "user"_attr = name);
+ return;
}
- _updateInternalAuthorizationState();
+
+ updateUser(std::move(user));
}
bool AuthorizationSessionImpl::isAuthorizedForAnyActionOnAnyResourceInDB(StringData db) {
@@ -804,59 +772,61 @@ bool AuthorizationSessionImpl::isAuthorizedForAnyActionOnAnyResourceInDB(StringD
return true;
}
- for (const auto& user : _authenticatedUsers) {
- // First lookup any Privileges on this database specifying Database resources
- if (user->hasActionsForResource(ResourcePattern::forDatabaseName(db))) {
- return true;
- }
+ if (_authenticatedUser == boost::none) {
+ return false;
+ }
+
+ const auto& user = _authenticatedUser.get();
+ // First lookup any Privileges on this database specifying Database resources
+ if (user->hasActionsForResource(ResourcePattern::forDatabaseName(db))) {
+ return true;
+ }
- // Any resource will match any collection in the database
- if (user->hasActionsForResource(ResourcePattern::forAnyResource())) {
+ // Any resource will match any collection in the database
+ if (user->hasActionsForResource(ResourcePattern::forAnyResource())) {
+ return true;
+ }
+
+ // Any resource will match any system_buckets collection in the database
+ if (user->hasActionsForResource(ResourcePattern::forAnySystemBuckets()) ||
+ user->hasActionsForResource(ResourcePattern::forAnySystemBucketsInDatabase(db))) {
+ return true;
+ }
+
+ // If the user is authorized for anyNormalResource, then they implicitly have access
+ // to most databases.
+ if (db != "local" && db != "config" &&
+ user->hasActionsForResource(ResourcePattern::forAnyNormalResource())) {
+ return true;
+ }
+
+ // We've checked all the resource types that can be directly expressed. Now we must
+ // iterate all privileges, until we see something that could reside in the target database.
+ auto map = user->getPrivileges();
+ for (const auto& privilege : map) {
+ // If the user has a Collection privilege, then they're authorized for this resource
+ // on all databases.
+ if (privilege.first.isCollectionPattern()) {
return true;
}
- // Any resource will match any system_buckets collection in the database
- if (user->hasActionsForResource(ResourcePattern::forAnySystemBuckets()) ||
- user->hasActionsForResource(ResourcePattern::forAnySystemBucketsInDatabase(db))) {
+ // User can see system_buckets in any database so we consider them to have permission in
+ // this database
+ if (privilege.first.isAnySystemBucketsCollectionInAnyDB()) {
return true;
}
- // If the user is authorized for anyNormalResource, then they implicitly have access
- // to most databases.
- if (db != "local" && db != "config" &&
- user->hasActionsForResource(ResourcePattern::forAnyNormalResource())) {
+ // If the user has an exact namespace privilege on a collection in this database, they
+ // have access to a resource in this database.
+ if (privilege.first.isExactNamespacePattern() && privilege.first.databaseToMatch() == db) {
return true;
}
- // We've checked all the resource types that can be directly expressed. Now we must
- // iterate all privileges, until we see something that could reside in the target database.
- User::ResourcePrivilegeMap map = user->getPrivileges();
- for (const auto& privilege : map) {
- // If the user has a Collection privilege, then they're authorized for this resource
- // on all databases.
- if (privilege.first.isCollectionPattern()) {
- return true;
- }
-
- // User can see system_buckets in any database so we consider them to have permission in
- // this database
- if (privilege.first.isAnySystemBucketsCollectionInAnyDB()) {
- return true;
- }
-
- // If the user has an exact namespace privilege on a collection in this database, they
- // have access to a resource in this database.
- if (privilege.first.isExactNamespacePattern() &&
- privilege.first.databaseToMatch() == db) {
- return true;
- }
-
- // If the user has an exact namespace privilege on a system.buckets collection in this
- // database, they have access to a resource in this database.
- if (privilege.first.isExactSystemBucketsCollection() &&
- privilege.first.databaseToMatch() == db) {
- return true;
- }
+ // If the user has an exact namespace privilege on a system.buckets collection in this
+ // database, they have access to a resource in this database.
+ if (privilege.first.isExactSystemBucketsCollection() &&
+ privilege.first.databaseToMatch() == db) {
+ return true;
}
}
@@ -870,15 +840,18 @@ bool AuthorizationSessionImpl::isAuthorizedForAnyActionOnResource(const Resource
return true;
}
+ if (_authenticatedUser == boost::none) {
+ return false;
+ }
+
std::array<ResourcePattern, resourceSearchListCapacity> resourceSearchList;
const int resourceSearchListLength =
buildResourceSearchList(resource, resourceSearchList.data());
+ const auto& user = _authenticatedUser.get();
for (int i = 0; i < resourceSearchListLength; ++i) {
- for (const auto& user : _authenticatedUsers) {
- if (user->hasActionsForResource(resourceSearchList[i])) {
- return true;
- }
+ if (user->hasActionsForResource(resourceSearchList[i])) {
+ return true;
}
}
@@ -895,95 +868,75 @@ bool AuthorizationSessionImpl::_isAuthorizedForPrivilege(const Privilege& privil
const int resourceSearchListLength = buildResourceSearchList(target, resourceSearchList);
ActionSet unmetRequirements = privilege.getActions();
-
- PrivilegeVector defaultPrivileges = _getDefaultPrivileges();
- for (PrivilegeVector::iterator it = defaultPrivileges.begin(); it != defaultPrivileges.end();
- ++it) {
+ for (const auto& priv : _getDefaultPrivileges()) {
for (int i = 0; i < resourceSearchListLength; ++i) {
- if (!(it->getResourcePattern() == resourceSearchList[i]))
+ if (!(priv.getResourcePattern() == resourceSearchList[i])) {
continue;
+ }
- ActionSet userActions = it->getActions();
+ ActionSet userActions = priv.getActions();
unmetRequirements.removeAllActionsFromSet(userActions);
- if (unmetRequirements.empty())
+ if (unmetRequirements.empty()) {
return true;
+ }
}
}
- for (const auto& user : _authenticatedUsers) {
- for (int i = 0; i < resourceSearchListLength; ++i) {
- ActionSet userActions = user->getActionsForResource(resourceSearchList[i]);
- unmetRequirements.removeAllActionsFromSet(userActions);
+ if (_authenticatedUser == boost::none) {
+ return false;
+ }
- if (unmetRequirements.empty()) {
- return true;
- }
+ const auto& user = _authenticatedUser.get();
+ for (int i = 0; i < resourceSearchListLength; ++i) {
+ ActionSet userActions = user->getActionsForResource(resourceSearchList[i]);
+ unmetRequirements.removeAllActionsFromSet(userActions);
+
+ if (unmetRequirements.empty()) {
+ return true;
}
}
return false;
}
-void AuthorizationSessionImpl::setImpersonatedUserData(const std::vector<UserName>& usernames,
+void AuthorizationSessionImpl::setImpersonatedUserData(const UserName& username,
const std::vector<RoleName>& roles) {
- _impersonatedUserNames = usernames;
+ _impersonatedUserName = username;
_impersonatedRoleNames = roles;
_impersonationFlag = true;
}
bool AuthorizationSessionImpl::isCoauthorizedWithClient(Client* opClient, WithLock opClientLock) {
_contract.addAccessCheck(AccessCheckEnum::kIsCoauthorizedWithClient);
- auto getUserNames = [](AuthorizationSession* authSession) {
+ auto getUserName = [](AuthorizationSession* authSession) {
if (authSession->isImpersonating()) {
- return authSession->getImpersonatedUserNames();
+ return authSession->getImpersonatedUserName();
} else {
- return authSession->getAuthenticatedUserNames();
+ return authSession->getAuthenticatedUserName();
}
};
- UserNameIterator it = getUserNames(this);
- while (it.more()) {
- UserNameIterator opIt = getUserNames(AuthorizationSession::get(opClient));
- while (opIt.more()) {
- if (it.get() == opIt.get()) {
- return true;
- }
- opIt.next();
- }
- it.next();
+ if (auto myname = getUserName(this)) {
+ return myname == getUserName(AuthorizationSession::get(opClient));
+ } else {
+ return false;
}
-
- return false;
}
-bool AuthorizationSessionImpl::isCoauthorizedWith(UserNameIterator userNameIter) {
+bool AuthorizationSessionImpl::isCoauthorizedWith(const boost::optional<UserName>& userName) {
_contract.addAccessCheck(AccessCheckEnum::kIsCoauthorizedWith);
if (!getAuthorizationManager().isAuthEnabled()) {
return true;
}
- if (!userNameIter.more() && !isAuthenticated()) {
- return true;
- }
-
- for (; userNameIter.more(); userNameIter.next()) {
- for (UserNameIterator thisUserNameIter = getAuthenticatedUserNames();
- thisUserNameIter.more();
- thisUserNameIter.next()) {
- if (*userNameIter == *thisUserNameIter) {
- return true;
- }
- }
- }
-
- return false;
+ return getAuthenticatedUserName() == userName;
}
-UserNameIterator AuthorizationSessionImpl::getImpersonatedUserNames() {
- _contract.addAccessCheck(AccessCheckEnum::kGetImpersonatedUserNames);
+boost::optional<UserName> AuthorizationSessionImpl::getImpersonatedUserName() {
+ _contract.addAccessCheck(AccessCheckEnum::kGetImpersonatedUserName);
- return makeUserNameIterator(_impersonatedUserNames.begin(), _impersonatedUserNames.end());
+ return _impersonatedUserName;
}
RoleNameIterator AuthorizationSessionImpl::getImpersonatedRoleNames() {
@@ -1000,7 +953,7 @@ bool AuthorizationSessionImpl::isUsingLocalhostBypass() {
// Clear the vectors of impersonated usernames and roles.
void AuthorizationSessionImpl::clearImpersonatedUserData() {
- _impersonatedUserNames.clear();
+ _impersonatedUserName = boost::none;
_impersonatedRoleNames.clear();
_impersonationFlag = false;
}
@@ -1079,15 +1032,15 @@ void AuthorizationSessionImpl::verifyContract(const AuthorizationContract* contr
tempContract.addAccessCheck(AccessCheckEnum::kIsAuthenticated);
// These checks are done by auditing
+ tempContract.addAccessCheck(AccessCheckEnum::kGetAuthenticatedUserName);
tempContract.addAccessCheck(AccessCheckEnum::kGetAuthenticatedRoleNames);
- tempContract.addAccessCheck(AccessCheckEnum::kGetAuthenticatedUserNames);
- tempContract.addAccessCheck(AccessCheckEnum::kGetImpersonatedUserNames);
+ tempContract.addAccessCheck(AccessCheckEnum::kGetImpersonatedUserName);
tempContract.addAccessCheck(AccessCheckEnum::kGetImpersonatedRoleNames);
// Since internal sessions are started by the server, the generated authorization contract is
// missing the following user access checks, so we add them here to allow commands that spawn
// internal sessions to pass this authorization check.
- tempContract.addAccessCheck(AccessCheckEnum::kGetSingleUser);
+ tempContract.addAccessCheck(AccessCheckEnum::kGetAuthenticatedUser);
tempContract.addAccessCheck(AccessCheckEnum::kLookupUser);
// "internal" comes from readRequestMetadata and sharded clusters
@@ -1106,18 +1059,16 @@ void AuthorizationSessionImpl::verifyContract(const AuthorizationContract* contr
void AuthorizationSessionImpl::_updateInternalAuthorizationState() {
// Update the authenticated role names vector to reflect current state.
_authenticatedRoleNames.clear();
- for (const auto& userHandle : _authenticatedUsers) {
- RoleNameIterator roles = userHandle->getIndirectRoles();
+ if (_authenticatedUser == boost::none) {
+ _authenticationMode = AuthenticationMode::kNone;
+ } else {
+ RoleNameIterator roles = _authenticatedUser.get()->getIndirectRoles();
while (roles.more()) {
RoleName roleName = roles.next();
_authenticatedRoleNames.push_back(RoleName(roleName.getRole(), roleName.getDB()));
}
}
- if (_authenticatedUsers.count() == 0) {
- _authenticationMode = AuthenticationMode::kNone;
- }
-
// Update cached _mayBypassWriteBlockingMode to reflect current state.
_mayBypassWriteBlockingMode =
_isAuthorizedForPrivilege(kBypassWriteBlockingModeOnClusterPrivilege);
diff --git a/src/mongo/db/auth/authorization_session_impl.h b/src/mongo/db/auth/authorization_session_impl.h
index eefbcbfabe5..94a13c59249 100644
--- a/src/mongo/db/auth/authorization_session_impl.h
+++ b/src/mongo/db/auth/authorization_session_impl.h
@@ -40,7 +40,6 @@
#include "mongo/db/auth/authz_session_external_state.h"
#include "mongo/db/auth/privilege.h"
#include "mongo/db/auth/user_name.h"
-#include "mongo/db/auth/user_set.h"
#include "mongo/db/namespace_string.h"
namespace mongo {
@@ -54,7 +53,7 @@ class Client;
*
* An AuthorizationSession object is present within every mongo::Client object.
*
- * Users in the _authenticatedUsers cache may get marked as invalid by the AuthorizationManager,
+ * The active _authenticatedUser may get marked as invalid by the AuthorizationManager,
* for instance if their privileges are changed by a user or role modification command. At the
* beginning of every user-initiated operation startRequest() gets called which updates
* the cached information about any users who have been marked as invalid. This guarantees that
@@ -85,9 +84,9 @@ public:
bool isAuthenticated() override;
- User* getSingleUser() override;
+ boost::optional<UserHandle> getAuthenticatedUser() override;
- UserNameIterator getAuthenticatedUserNames() override;
+ boost::optional<UserName> getAuthenticatedUserName() override;
RoleNameIterator getAuthenticatedRoleNames() override;
@@ -137,10 +136,10 @@ public:
bool isAuthorizedForAnyActionOnResource(const ResourcePattern& resource) override;
- void setImpersonatedUserData(const std::vector<UserName>& usernames,
+ void setImpersonatedUserData(const UserName& username,
const std::vector<RoleName>& roles) override;
- UserNameIterator getImpersonatedUserNames() override;
+ boost::optional<UserName> getImpersonatedUserName() override;
RoleNameIterator getImpersonatedRoleNames() override;
@@ -148,7 +147,7 @@ public:
bool isCoauthorizedWithClient(Client* opClient, WithLock opClientLock) override;
- bool isCoauthorizedWith(UserNameIterator userNameIter) override;
+ bool isCoauthorizedWith(const boost::optional<UserName>& userName) override;
bool isImpersonating() const override;
@@ -173,8 +172,8 @@ protected:
void _updateInternalAuthorizationState();
- // All Users who have been authenticated on this connection.
- UserSet _authenticatedUsers;
+ // The User who has been authenticated on this connection.
+ boost::optional<UserHandle> _authenticatedUser;
// What authentication mode we're currently operating in.
AuthenticationMode _authenticationMode = AuthenticationMode::kNone;
@@ -194,8 +193,8 @@ private:
// lock on the admin database (to update out-of-date user privilege information).
bool _isAuthorizedForPrivilege(const Privilege& privilege);
- std::tuple<std::vector<UserName>*, std::vector<RoleName>*> _getImpersonations() override {
- return std::make_tuple(&_impersonatedUserNames, &_impersonatedRoleNames);
+ std::tuple<boost::optional<UserName>*, std::vector<RoleName>*> _getImpersonations() override {
+ return std::make_tuple(&_impersonatedUserName, &_impersonatedRoleNames);
}
@@ -211,7 +210,7 @@ private:
// A vector of impersonated UserNames and a vector of those users' RoleNames.
// These are used in the auditing system. They are not used for authz checks.
- std::vector<UserName> _impersonatedUserNames;
+ boost::optional<UserName> _impersonatedUserName;
std::vector<RoleName> _impersonatedRoleNames;
bool _impersonationFlag;
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp
index 4ecb9cca692..1336554897a 100644
--- a/src/mongo/db/auth/authorization_session_test.cpp
+++ b/src/mongo/db/auth/authorization_session_test.cpp
@@ -1054,45 +1054,33 @@ TEST_F(AuthorizationSessionTest,
ASSERT_TRUE(authzSession->isAuthorizedForPrivileges(privileges));
}
-TEST_F(AuthorizationSessionTest, UnauthorizedSessionIsCoauthorizedWithEmptyUserSet) {
- std::vector<UserName> userSet;
- ASSERT_TRUE(
- authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end())));
+TEST_F(AuthorizationSessionTest, UnauthorizedSessionIsCoauthorizedWithNobody) {
+ ASSERT_TRUE(authzSession->isCoauthorizedWith(boost::none));
}
-TEST_F(AuthorizationSessionTest, UnauthorizedSessionIsNotCoauthorizedWithNonemptyUserSet) {
- std::vector<UserName> userSet;
- userSet.emplace_back("spencer", "test");
- ASSERT_FALSE(
- authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end())));
+TEST_F(AuthorizationSessionTest, UnauthorizedSessionIsNotCoauthorizedWithAnybody) {
+ ASSERT_FALSE(authzSession->isCoauthorizedWith(UserName("spencer", "test")));
}
-TEST_F(AuthorizationSessionTest,
- UnauthorizedSessionIsCoauthorizedWithNonemptyUserSetWhenAuthIsDisabled) {
+TEST_F(AuthorizationSessionTest, UnauthorizedSessionIsCoauthorizedWithAnybodyWhenAuthIsDisabled) {
authzManager->setAuthEnabled(false);
- std::vector<UserName> userSet;
- userSet.emplace_back("spencer", "test");
- ASSERT_TRUE(
- authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end())));
+ ASSERT_TRUE(authzSession->isCoauthorizedWith(UserName("spencer", "test")));
}
-TEST_F(AuthorizationSessionTest, AuthorizedSessionIsNotCoauthorizedWithEmptyUserSet) {
- ASSERT_OK(createUser({"spencer", "test"}, {}));
- ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test")));
- std::vector<UserName> userSet;
- ASSERT_FALSE(
- authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end())));
+TEST_F(AuthorizationSessionTest, AuthorizedSessionIsNotCoauthorizedNobody) {
+ UserName user("spencer", "test");
+ ASSERT_OK(createUser(user, {}));
+ ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), user));
+ ASSERT_FALSE(authzSession->isCoauthorizedWith(boost::none));
authzSession->logoutDatabase(_client.get(), "test", "Kill the test!");
}
-TEST_F(AuthorizationSessionTest,
- AuthorizedSessionIsCoauthorizedWithEmptyUserSetWhenAuthIsDisabled) {
+TEST_F(AuthorizationSessionTest, AuthorizedSessionIsCoauthorizedNobodyWhenAuthIsDisabled) {
+ UserName user("spencer", "test");
authzManager->setAuthEnabled(false);
- ASSERT_OK(createUser({"spencer", "test"}, {}));
- ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), UserName("spencer", "test")));
- std::vector<UserName> userSet;
- ASSERT_TRUE(
- authzSession->isCoauthorizedWith(makeUserNameIterator(userSet.begin(), userSet.end())));
+ ASSERT_OK(createUser(user, {}));
+ ASSERT_OK(authzSession->addAndAuthorizeUser(_opCtx.get(), user));
+ ASSERT_TRUE(authzSession->isCoauthorizedWith(user));
authzSession->logoutDatabase(_client.get(), "test", "Kill the test!");
}
diff --git a/src/mongo/db/auth/impersonation_session.cpp b/src/mongo/db/auth/impersonation_session.cpp
index 3846b255bb0..88742e20357 100644
--- a/src/mongo/db/auth/impersonation_session.cpp
+++ b/src/mongo/db/auth/impersonation_session.cpp
@@ -55,7 +55,8 @@ ImpersonationSessionGuard::ImpersonationSessionGuard(OperationContext* opCtx) :
authSession->isAuthorizedForPrivilege(
Privilege(ResourcePattern::forClusterResource(), ActionType::impersonate)));
fassert(ErrorCodes::InternalError, !authSession->isImpersonating());
- authSession->setImpersonatedUserData(impersonatedUsersAndRoles->getUsers(),
+ fassert(ErrorCodes::InternalError, impersonatedUsersAndRoles->getUsers().size() == 1);
+ authSession->setImpersonatedUserData(impersonatedUsersAndRoles->getUsers()[0],
impersonatedUsersAndRoles->getRoles());
_active = true;
return;
diff --git a/src/mongo/db/auth/user_set.cpp b/src/mongo/db/auth/user_set.cpp
deleted file mode 100644
index cdc19034fbc..00000000000
--- a/src/mongo/db/auth/user_set.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/db/auth/user_set.h"
-
-#include <algorithm>
-
-namespace mongo {
-namespace {
-
-class UserSetNameIteratorImpl : public UserNameIterator::Impl {
- UserSetNameIteratorImpl(const UserSetNameIteratorImpl&) = delete;
- UserSetNameIteratorImpl& operator=(const UserSetNameIteratorImpl&) = delete;
-
-public:
- UserSetNameIteratorImpl(const UserSet::const_iterator& begin,
- const UserSet::const_iterator& end)
- : _curr(begin), _end(end) {}
-
- ~UserSetNameIteratorImpl() = default;
-
- bool more() const override {
- return _curr != _end;
- }
-
- const UserName& next() override {
- return (*(_curr++))->getName();
- }
-
- const UserName& get() const override {
- return (*_curr)->getName();
- }
-
- UserNameIterator::Impl* doClone() const override {
- return new UserSetNameIteratorImpl(_curr, _end);
- }
-
-private:
- UserSet::const_iterator _curr;
- UserSet::const_iterator _end;
-};
-
-} // namespace
-
-UserSet::UserSet() = default;
-
-void UserSet::add(UserHandle user) {
- auto it = std::find_if(_users.begin(), _users.end(), [&](const auto& storedUser) {
- return user->getName().getDB() == storedUser->getName().getDB();
- });
- if (it == _users.end()) {
- _users.push_back(std::move(user));
- } else {
- *it = std::move(user);
- }
-}
-
-void UserSet::removeByDBName(StringData dbname) {
- auto it = std::find_if(_users.begin(), _users.end(), [&](const auto& user) {
- return user->getName().getDB() == dbname;
- });
- if (it != _users.end()) {
- _users.erase(it);
- }
-}
-
-void UserSet::replaceAt(iterator it, UserHandle replacement) {
- *it = std::move(replacement);
-}
-
-void UserSet::removeAt(iterator it) {
- _users.erase(it);
-}
-
-UserHandle UserSet::lookup(const UserName& name) const {
- auto it = std::find_if(
- _users.begin(), _users.end(), [&](const auto& user) { return user->getName() == name; });
- return (it != _users.end()) ? *it : UserHandle();
-}
-
-UserHandle UserSet::lookupByDBName(StringData dbname) const {
- auto it = std::find_if(_users.begin(), _users.end(), [&](const auto& user) {
- return user->getName().getDB() == dbname;
- });
- return (it != _users.end()) ? *it : UserHandle();
-}
-
-UserNameIterator UserSet::getNames() const {
- return UserNameIterator(
- std::make_unique<UserSetNameIteratorImpl>(_users.cbegin(), _users.cend()));
-}
-
-} // namespace mongo
diff --git a/src/mongo/db/auth/user_set.h b/src/mongo/db/auth/user_set.h
deleted file mode 100644
index bc1bb633fcb..00000000000
--- a/src/mongo/db/auth/user_set.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <list>
-
-#include "mongo/db/auth/user.h"
-
-namespace mongo {
-
-/**
- * A collection of authenticated users.
- * This class does not do any locking/synchronization, the consumer will be responsible for
- * synchronizing access.
- */
-class UserSet {
-public:
- using iterator = std::list<UserHandle>::iterator;
- using const_iterator = std::list<UserHandle>::const_iterator;
-
- UserSet();
- UserSet(const UserSet&) = default;
- UserSet& operator=(const UserSet&) = default;
-
- /**
- * Adds a User to the UserSet.
- *
- * As there can only be one user per database in the UserSet, if a User already exists for
- * the new User's database, the old user will be removed from the set and returned. It is
- * the caller's responsibility to then release that user. If no user already exists for the
- * new user's database, returns NULL.
- *
- * Invalidates any outstanding iterators or NameIterators.
- */
- void add(UserHandle user);
-
- /**
- * Replaces the user at "it" with "replacement." Does not take ownership of the User.
- * Returns a pointer to the old user referenced by "it". Does _not_ invalidate "iterator"
- * instances.
- */
- void replaceAt(iterator it, UserHandle replacement);
-
- /**
- * Removes the user at "it", and returns a pointer to it. After this call, "it" remains
- * valid. It will either equal "end()", or refer to some user between the values of "it"
- * and "end()" before this call was made.
- */
- void removeAt(iterator it);
-
- /**
- * Removes the User whose authentication credentials came from dbname, and returns that
- * user. It is the caller's responsibility to then release that user back to the
- * authorizationManger. If no user exists for the given database, returns NULL;
- */
- void removeByDBName(StringData dbname);
-
- // Returns the User with the given name, or NULL if not found.
- // Ownership of the returned User remains with the UserSet. The pointer
- // returned is only guaranteed to remain valid until the next non-const method is called
- // on the UserSet.
- UserHandle lookup(const UserName& name) const;
-
- // Gets the user whose authentication credentials came from dbname, or NULL if none
- // exist. There should be at most one such user.
- UserHandle lookupByDBName(StringData dbname) const;
-
- // Gets an iterator over the names of the users stored in the set. The iterator is
- // valid until the next non-const method is called on the UserSet.
- UserNameIterator getNames() const;
-
- iterator begin() {
- return _users.begin();
- }
-
- iterator end() {
- return _users.end();
- }
-
- // Returns the number of users stored in the set.
- std::size_t count() const {
- return _users.size();
- }
-
- // Generates a BSONArray representation of the UserSet.
- BSONArray toBSON() const {
- BSONArrayBuilder userNamesArray;
- for (const auto& userHandle : _users) {
- userHandle->getName().serializeToBSON(&userNamesArray);
- }
- return userNamesArray.arr();
- }
-
-private:
- // The UserSet maintains ownership of the Users in it, and is responsible for
- // returning them to the AuthorizationManager when done with them.
- std::list<UserHandle> _users;
-};
-
-} // namespace mongo
diff --git a/src/mongo/db/auth/user_set_test.cpp b/src/mongo/db/auth/user_set_test.cpp
deleted file mode 100644
index e2a87b12b4c..00000000000
--- a/src/mongo/db/auth/user_set_test.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-/**
- * Unit tests of the UserSet type.
- */
-
-#include "mongo/db/auth/user.h"
-#include "mongo/db/auth/user_name.h"
-#include "mongo/db/auth/user_set.h"
-#include "mongo/unittest/unittest.h"
-
-#define ASSERT_NULL(EXPR) ASSERT_FALSE((EXPR))
-
-namespace mongo {
-namespace {
-
-TEST(UserSetTest, BasicTest) {
- UserSet set;
-
- UserHandle p1(User(UserName("Bob", "test")));
- UserHandle p2(User(UserName("George", "test")));
- UserHandle p3(User(UserName("Bob", "test2")));
-
- ASSERT_NULL(set.lookup(UserName("Bob", "test")));
- ASSERT_NULL(set.lookup(UserName("George", "test")));
- ASSERT_NULL(set.lookup(UserName("Bob", "test2")));
- ASSERT_NULL(set.lookupByDBName("test"));
- ASSERT_NULL(set.lookupByDBName("test2"));
-
- set.add(p1);
-
- ASSERT_EQUALS(p1, set.lookup(UserName("Bob", "test")));
- ASSERT_EQUALS(p1, set.lookupByDBName("test"));
- ASSERT_NULL(set.lookup(UserName("George", "test")));
- ASSERT_NULL(set.lookup(UserName("Bob", "test2")));
- ASSERT_NULL(set.lookupByDBName("test2"));
-
- // This should not replace the existing user "Bob" because they are different databases
- set.add(p3);
-
- ASSERT_EQUALS(p1, set.lookup(UserName("Bob", "test")));
- ASSERT_EQUALS(p1, set.lookupByDBName("test"));
- ASSERT_NULL(set.lookup(UserName("George", "test")));
- ASSERT_EQUALS(p3, set.lookup(UserName("Bob", "test2")));
- ASSERT_EQUALS(p3, set.lookupByDBName("test2"));
-
- set.add(p2); // This should replace Bob since they're on the same database
-
- ASSERT_NULL(set.lookup(UserName("Bob", "test")));
- ASSERT_EQUALS(p2, set.lookup(UserName("George", "test")));
- ASSERT_EQUALS(p2, set.lookupByDBName("test"));
- ASSERT_EQUALS(p3, set.lookup(UserName("Bob", "test2")));
- ASSERT_EQUALS(p3, set.lookupByDBName("test2"));
-
- set.removeByDBName("test"_sd);
-
- ASSERT_NULL(set.lookup(UserName("Bob", "test")));
- ASSERT_NULL(set.lookup(UserName("George", "test")));
- ASSERT_NULL(set.lookupByDBName("test"));
- ASSERT_EQUALS(p3, set.lookup(UserName("Bob", "test2")));
- ASSERT_EQUALS(p3, set.lookupByDBName("test2"));
-
- UserNameIterator iter = set.getNames();
- ASSERT_TRUE(iter.more());
- ASSERT_EQUALS(iter.next(), UserName("Bob", "test2"));
- ASSERT_FALSE(iter.more());
-}
-
-TEST(UserSetTest, IterateNames) {
- UserSet pset;
- UserNameIterator iter = pset.getNames();
- ASSERT(!iter.more());
-
- UserHandle user(User(UserName("bob", "test")));
- pset.add(std::move(user));
-
- iter = pset.getNames();
- ASSERT(iter.more());
- ASSERT_EQUALS(*iter, UserName("bob", "test"));
- ASSERT_EQUALS(iter.next(), UserName("bob", "test"));
- ASSERT(!iter.more());
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index bb205d784f2..9c1be7e4fc2 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -87,7 +87,7 @@ ClientCursor::ClientCursor(ClientCursorParams params,
Date_t now)
: _cursorid(cursorId),
_nss(std::move(params.nss)),
- _authenticatedUsers(std::move(params.authenticatedUsers)),
+ _authenticatedUser(std::move(params.authenticatedUser)),
_lsid(operationUsingCursor->getLogicalSessionId()),
_txnNumber(operationUsingCursor->getTxnNumber()),
_apiParameters(std::move(params.apiParameters)),
diff --git a/src/mongo/db/clientcursor.h b/src/mongo/db/clientcursor.h
index 0724c49d4dd..70b5143fe8e 100644
--- a/src/mongo/db/clientcursor.h
+++ b/src/mongo/db/clientcursor.h
@@ -58,7 +58,7 @@ class RecoveryUnit;
struct ClientCursorParams {
ClientCursorParams(std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> planExecutor,
NamespaceString nss,
- UserNameIterator authenticatedUsersIter,
+ boost::optional<UserName> authenticatedUser,
APIParameters apiParameters,
WriteConcernOptions writeConcernOptions,
repl::ReadConcernArgs readConcernArgs,
@@ -67,6 +67,7 @@ struct ClientCursorParams {
PrivilegeVector originatingPrivileges)
: exec(std::move(planExecutor)),
nss(std::move(nss)),
+ authenticatedUser(std::move(authenticatedUser)),
apiParameters(std::move(apiParameters)),
writeConcernOptions(std::move(writeConcernOptions)),
readConcernArgs(std::move(readConcernArgs)),
@@ -81,11 +82,7 @@ struct ClientCursorParams {
exec->getCanonicalQuery()->getFindCommandRequest())
: TailableModeEnum::kNormal),
originatingCommandObj(originatingCommandObj.getOwned()),
- originatingPrivileges(std::move(originatingPrivileges)) {
- while (authenticatedUsersIter.more()) {
- authenticatedUsers.emplace_back(authenticatedUsersIter.next());
- }
- }
+ originatingPrivileges(std::move(originatingPrivileges)) {}
void setTailableMode(TailableModeEnum newMode) {
tailableMode = newMode;
@@ -93,7 +90,7 @@ struct ClientCursorParams {
std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> exec;
const NamespaceString nss;
- std::vector<UserName> authenticatedUsers;
+ boost::optional<UserName> authenticatedUser;
const APIParameters apiParameters;
const WriteConcernOptions writeConcernOptions;
const repl::ReadConcernArgs readConcernArgs;
@@ -133,8 +130,8 @@ public:
return _nss;
}
- UserNameIterator getAuthenticatedUsers() const {
- return makeUserNameIterator(_authenticatedUsers.begin(), _authenticatedUsers.end());
+ boost::optional<UserName> getAuthenticatedUser() const {
+ return _authenticatedUser;
}
boost::optional<LogicalSessionId> getSessionId() const {
@@ -358,11 +355,11 @@ private:
// have the correct partition of the CursorManager locked (just like _authenticatedUsers).
const NamespaceString _nss;
- // The set of authenticated users when this cursor was created. Threads may read from this
+ // The authenticated user when this cursor was created. Threads may read from this
// field (using the getter) even if they don't have the cursor pinned as long as they hold the
// correct partition's lock in the CursorManager. They must hold the lock to prevent the cursor
// from being freed by another thread during the read.
- const std::vector<UserName> _authenticatedUsers;
+ const boost::optional<UserName> _authenticatedUser;
// A logical session id for this cursor, if it is running inside of a session.
const boost::optional<LogicalSessionId> _lsid;
diff --git a/src/mongo/db/commands/connection_status.cpp b/src/mongo/db/commands/connection_status.cpp
index 1e688d2274b..903fc7fce38 100644
--- a/src/mongo/db/commands/connection_status.cpp
+++ b/src/mongo/db/commands/connection_status.cpp
@@ -50,7 +50,11 @@ public:
auto* as = AuthorizationSession::get(opCtx->getClient());
ConnectionStatusReplyAuthInfo info;
- info.setAuthenticatedUsers(iteratorToVector<UserName>(as->getAuthenticatedUserNames()));
+ std::vector<UserName> userNames;
+ if (auto userName = as->getAuthenticatedUserName()) {
+ userNames.push_back(std::move(userName.get()));
+ }
+ info.setAuthenticatedUsers(std::move(userNames));
info.setAuthenticatedUserRoles(
iteratorToVector<RoleName>(as->getAuthenticatedRoleNames()));
if (request().getShowPrivileges()) {
@@ -77,9 +81,8 @@ public:
// entries in the connection status output.
User::ResourcePrivilegeMap unified;
- for (auto nameIt = as->getAuthenticatedUserNames(); nameIt.more(); nameIt.next()) {
- auto* authUser = as->lookupUser(*nameIt);
- for (const auto& privIter : authUser->getPrivileges()) {
+ if (auto authUser = as->getAuthenticatedUser()) {
+ for (const auto& privIter : authUser.get()->getPrivileges()) {
auto it = unified.find(privIter.first);
if (it == unified.end()) {
unified[privIter.first] = privIter.second;
diff --git a/src/mongo/db/commands/create.idl b/src/mongo/db/commands/create.idl
index 69747ea67f2..f45b6018ac2 100644
--- a/src/mongo/db/commands/create.idl
+++ b/src/mongo/db/commands/create.idl
@@ -61,7 +61,7 @@ commands:
access_check:
complex:
- check: should_ignore_auth_checks
- - check: get_single_user # Can be triggered by aggregation
+ - check: get_authenticated_user # Can be triggered by aggregation
- check: lookup_user # Can be triggered by aggregation
- privilege:
resource_pattern: exact_namespace
diff --git a/src/mongo/db/commands/end_sessions_command.cpp b/src/mongo/db/commands/end_sessions_command.cpp
index b1d5ae4ca3f..3d11bc0d03e 100644
--- a/src/mongo/db/commands/end_sessions_command.cpp
+++ b/src/mongo/db/commands/end_sessions_command.cpp
@@ -83,9 +83,7 @@ public:
void doCheckAuthorization(OperationContext* opCtx) const final {
// It is always ok to run this command, as long as you are authenticated
// as some user, if auth is enabled.
- uassert(ErrorCodes::Unauthorized,
- "Not authorized to run endSessions command",
- AuthorizationSession::get(opCtx->getClient())->getSingleUser());
+ // requiresAuth() => true covers this for us.
}
Reply typedRun(OperationContext* opCtx) final {
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index 9c46f14d1f1..ef292a00ead 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -686,7 +686,7 @@ public:
opCtx,
{std::move(exec),
nss,
- AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserName(),
APIParameters::get(opCtx),
opCtx->getWriteConcern(),
repl::ReadConcernArgs::get(opCtx),
diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp
index a344ab03278..6aed4fb7583 100644
--- a/src/mongo/db/commands/getmore_cmd.cpp
+++ b/src/mongo/db/commands/getmore_cmd.cpp
@@ -151,10 +151,8 @@ void validateTxnNumber(OperationContext* opCtx, int64_t cursorId, const ClientCu
void validateAuthorization(const OperationContext* opCtx, const ClientCursor& cursor) {
auto authzSession = AuthorizationSession::get(opCtx->getClient());
- // A user can only call getMore on their own cursor. If there were multiple users
- // authenticated when the cursor was created, then at least one of them must be
- // authenticated in order to run getMore on the cursor.
- if (!authzSession->isCoauthorizedWith(cursor.getAuthenticatedUsers())) {
+ // A user can only call getMore on their own cursor.
+ if (!authzSession->isCoauthorizedWith(cursor.getAuthenticatedUser())) {
uasserted(ErrorCodes::Unauthorized,
str::stream() << "cursor id " << cursor.cursorid()
<< " was not created by the authenticated user");
diff --git a/src/mongo/db/commands/kill_op_cmd_base.cpp b/src/mongo/db/commands/kill_op_cmd_base.cpp
index bace16861bc..a056e6cc514 100644
--- a/src/mongo/db/commands/kill_op_cmd_base.cpp
+++ b/src/mongo/db/commands/kill_op_cmd_base.cpp
@@ -53,8 +53,11 @@ void KillOpCmdBase::reportSuccessfulCompletion(OperationContext* opCtx,
auto client = opCtx->getClient();
if (client) {
if (AuthorizationManager::get(client->getServiceContext())->isAuthEnabled()) {
- auto user = AuthorizationSession::get(client)->getAuthenticatedUserNames();
- attr.add("user", user->toBSON());
+ if (auto user = AuthorizationSession::get(client)->getAuthenticatedUserName()) {
+ attr.add("user", BSON_ARRAY(user->toBSON()));
+ } else {
+ attr.add("user", BSONArray());
+ }
}
if (client->session()) {
diff --git a/src/mongo/db/commands/kill_sessions_command.cpp b/src/mongo/db/commands/kill_sessions_command.cpp
index 80d26ef32e7..298446164f9 100644
--- a/src/mongo/db/commands/kill_sessions_command.cpp
+++ b/src/mongo/db/commands/kill_sessions_command.cpp
@@ -58,13 +58,10 @@ KillAllSessionsByPatternSet patternsForLoggedInUser(OperationContext* opCtx) {
KillAllSessionsByPatternSet patterns;
if (AuthorizationManager::get(serviceContext)->isAuthEnabled()) {
- auto authzSession = AuthorizationSession::get(client);
- for (auto iter = authzSession->getAuthenticatedUserNames(); iter.more(); iter.next()) {
- User* user = authzSession->lookupUser(*iter);
- invariant(user);
-
+ auto* as = AuthorizationSession::get(client);
+ if (auto user = as->getAuthenticatedUser()) {
auto item = makeKillAllSessionsByPattern(opCtx);
- item.pattern.setUid(user->getDigest());
+ item.pattern.setUid(user.get()->getDigest());
patterns.emplace(std::move(item));
}
} else {
diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp
index 92cf819bda2..28cf8bbb451 100644
--- a/src/mongo/db/commands/list_collections.cpp
+++ b/src/mongo/db/commands/list_collections.cpp
@@ -544,7 +544,7 @@ public:
opCtx,
{std::move(exec),
cursorNss,
- AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserName(),
APIParameters::get(opCtx),
opCtx->getWriteConcern(),
repl::ReadConcernArgs::get(opCtx),
diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp
index 4b77947e520..8281615d664 100644
--- a/src/mongo/db/commands/list_indexes.cpp
+++ b/src/mongo/db/commands/list_indexes.cpp
@@ -353,7 +353,7 @@ public:
opCtx,
{std::move(exec),
nss,
- AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserName(),
APIParameters::get(opCtx),
opCtx->getWriteConcern(),
repl::ReadConcernArgs::get(opCtx),
diff --git a/src/mongo/db/commands/refresh_sessions_command.cpp b/src/mongo/db/commands/refresh_sessions_command.cpp
index a15eb760d08..209fef853c3 100644
--- a/src/mongo/db/commands/refresh_sessions_command.cpp
+++ b/src/mongo/db/commands/refresh_sessions_command.cpp
@@ -72,9 +72,7 @@ public:
void doCheckAuthorization(OperationContext* opCtx) const final {
// It is always ok to run this command, as long as you are authenticated
// as some user, if auth is enabled.
- uassert(ErrorCodes::Unauthorized,
- "Not authorized to run refreshSessions command",
- AuthorizationSession::get(opCtx->getClient())->getSingleUser());
+ // requiresAuth() => true covers this for us.
}
Reply typedRun(OperationContext* opCtx) final {
diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp
index 6330ebdfdf1..576ee9c3d39 100644
--- a/src/mongo/db/commands/run_aggregate.cpp
+++ b/src/mongo/db/commands/run_aggregate.cpp
@@ -989,7 +989,7 @@ Status runAggregate(OperationContext* opCtx,
ClientCursorParams cursorParams(
std::move(exec),
origNss,
- AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserName(),
APIParameters::get(opCtx),
opCtx->getWriteConcern(),
repl::ReadConcernArgs::get(opCtx),
diff --git a/src/mongo/db/commands/sessions_commands.idl b/src/mongo/db/commands/sessions_commands.idl
index c5d315b31f3..d9528ad6908 100644
--- a/src/mongo/db/commands/sessions_commands.idl
+++ b/src/mongo/db/commands/sessions_commands.idl
@@ -46,7 +46,7 @@ commands:
reply_type: OkReply
access_check:
complex:
- - check: get_single_user
+ - check: get_authenticated_user
- check: lookup_user
refreshSessionsFromClient:
@@ -60,5 +60,5 @@ commands:
reply_type: OkReply
access_check:
complex:
- - check: get_single_user
+ - check: get_authenticated_user
- check: lookup_user
diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp
index 17953399f68..08158554ad9 100644
--- a/src/mongo/db/curop.cpp
+++ b/src/mongo/db/curop.cpp
@@ -204,10 +204,7 @@ void CurOp::reportCurrentOpForClient(OperationContext* opCtx,
const auto serializeAuthenticatedUsers = [&](StringData name) {
if (authSession->isAuthenticated()) {
BSONArrayBuilder users(infoBuilder->subarrayStart(name));
- for (auto userIt = authSession->getAuthenticatedUserNames(); userIt.more();
- userIt.next()) {
- userIt->serializeToBSON(&users);
- }
+ authSession->getAuthenticatedUserName()->serializeToBSON(&users);
}
};
@@ -1109,28 +1106,16 @@ void OpDebug::append(OperationContext* opCtx,
void OpDebug::appendUserInfo(const CurOp& c,
BSONObjBuilder& builder,
AuthorizationSession* authSession) {
- UserNameIterator nameIter = authSession->getAuthenticatedUserNames();
-
- UserName bestUser;
- if (nameIter.more())
- bestUser = *nameIter;
-
std::string opdb(nsToDatabase(c.getNS()));
BSONArrayBuilder allUsers(builder.subarrayStart("allUsers"));
- for (; nameIter.more(); nameIter.next()) {
- BSONObjBuilder nextUser(allUsers.subobjStart());
- nextUser.append(AuthorizationManager::USER_NAME_FIELD_NAME, nameIter->getUser());
- nextUser.append(AuthorizationManager::USER_DB_FIELD_NAME, nameIter->getDB());
- nextUser.doneFast();
-
- if (nameIter->getDB() == opdb) {
- bestUser = *nameIter;
- }
+ auto name = authSession->getAuthenticatedUserName();
+ if (name) {
+ name->serializeToBSON(&allUsers);
}
allUsers.doneFast();
- builder.append("user", bestUser.getUser().empty() ? "" : bestUser.getDisplayName());
+ builder.append("user", name ? name->getDisplayName() : "");
}
std::function<BSONObj(ProfileFilter::Args)> OpDebug::appendStaged(StringSet requestedFields,
diff --git a/src/mongo/db/cursor_manager.cpp b/src/mongo/db/cursor_manager.cpp
index ea2ce3f969d..8d09c6811fb 100644
--- a/src/mongo/db/cursor_manager.cpp
+++ b/src/mongo/db/cursor_manager.cpp
@@ -324,7 +324,7 @@ std::vector<GenericCursor> CursorManager::getIdleCursors(
// Exclude cursors that this user does not own if auth is enabled.
if (ctxAuth->getAuthorizationManager().isAuthEnabled() &&
userMode == MongoProcessInterface::CurrentOpUserMode::kExcludeOthers &&
- !ctxAuth->isCoauthorizedWith(cursor->getAuthenticatedUsers())) {
+ !ctxAuth->isCoauthorizedWith(cursor->getAuthenticatedUser())) {
continue;
}
// Exclude pinned cursors.
@@ -479,7 +479,7 @@ Status CursorManager::checkAuthForKillCursors(OperationContext* opCtx, CursorId
// after the cursor's creation. We're guaranteed that the cursor won't get destroyed while we're
// reading from it because we hold the partition's lock.
AuthorizationSession* as = AuthorizationSession::get(opCtx->getClient());
- return auth::checkAuthForKillCursors(as, cursor->nss(), cursor->getAuthenticatedUsers());
+ return auth::checkAuthForKillCursors(as, cursor->nss(), cursor->getAuthenticatedUser());
}
} // namespace mongo
diff --git a/src/mongo/db/dollar_tenant_decoration_test.cpp b/src/mongo/db/dollar_tenant_decoration_test.cpp
index c19a3415139..391250a1791 100644
--- a/src/mongo/db/dollar_tenant_decoration_test.cpp
+++ b/src/mongo/db/dollar_tenant_decoration_test.cpp
@@ -57,7 +57,11 @@ public:
{Privilege(ResourcePattern::forClusterResource(), ActionType::useTenant)});
auto* as =
dynamic_cast<AuthorizationSessionImpl*>(AuthorizationSession::get(opCtx->getClient()));
- as->_authenticatedUsers.add(std::move(user));
+ if (as->_authenticatedUser != boost::none) {
+ as->logoutAllDatabases(opCtx->getClient(), "AuthorizationSessionImplTestHelper"_sd);
+ }
+ as->_authenticatedUser = std::move(user);
+ as->_authenticationMode = AuthorizationSession::AuthenticationMode::kConnection;
as->_updateInternalAuthorizationState();
}
};
diff --git a/src/mongo/db/exec/js_function.cpp b/src/mongo/db/exec/js_function.cpp
index e618ad0d352..339a7192d25 100644
--- a/src/mongo/db/exec/js_function.cpp
+++ b/src/mongo/db/exec/js_function.cpp
@@ -44,12 +44,12 @@ std::string getAuthenticatedUserNamesToken(Client* client) {
StringBuilder sb;
auto as = AuthorizationSession::get(client);
- for (auto nameIter = as->getAuthenticatedUserNames(); nameIter.more(); nameIter.next()) {
+ if (auto name = as->getAuthenticatedUserName()) {
// Using a NUL byte which isn't valid in usernames to separate them.
- if (const auto& tenant = nameIter->getTenant()) {
+ if (const auto& tenant = name->getTenant()) {
sb << '\0' << tenant->toString();
}
- sb << '\0' << nameIter->getUnambiguousName();
+ sb << '\0' << name->getUnambiguousName();
}
return sb.str();
diff --git a/src/mongo/db/index_builds_coordinator_mongod.cpp b/src/mongo/db/index_builds_coordinator_mongod.cpp
index a99c5f05173..fb309720f22 100644
--- a/src/mongo/db/index_builds_coordinator_mongod.cpp
+++ b/src/mongo/db/index_builds_coordinator_mongod.cpp
@@ -370,7 +370,7 @@ IndexBuildsCoordinatorMongod::_startIndexBuild(OperationContext* opCtx,
// Load the external client's attributes into this thread's client for auditing.
auto authSession = AuthorizationSession::get(opCtx->getClient());
if (authSession) {
- authSession->setImpersonatedUserData(std::move(impersonatedClientAttrs.userNames),
+ authSession->setImpersonatedUserData(std::move(impersonatedClientAttrs.userName),
std::move(impersonatedClientAttrs.roleNames));
}
diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp
index 7d7da8040ae..ac00155ad77 100644
--- a/src/mongo/db/introspect.cpp
+++ b/src/mongo/db/introspect.cpp
@@ -35,7 +35,6 @@
#include "mongo/bson/util/builder.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_session.h"
-#include "mongo/db/auth/user_set.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/db/client.h"
#include "mongo/db/concurrency/exception_util.h"
diff --git a/src/mongo/db/kill_sessions.cpp b/src/mongo/db/kill_sessions.cpp
index b167e14c156..0d830500154 100644
--- a/src/mongo/db/kill_sessions.cpp
+++ b/src/mongo/db/kill_sessions.cpp
@@ -42,14 +42,14 @@ namespace mongo {
namespace {
std::vector<KillAllSessionsUser> getKillAllSessionsImpersonateUsers(OperationContext* opCtx) {
- AuthorizationSession* authSession = AuthorizationSession::get(opCtx->getClient());
+ auto* as = AuthorizationSession::get(opCtx->getClient());
std::vector<KillAllSessionsUser> out;
- for (auto iter = authSession->getAuthenticatedUserNames(); iter.more(); iter.next()) {
+ if (auto name = as->getAuthenticatedUserName()) {
out.emplace_back();
- out.back().setUser(iter->getUser());
- out.back().setDb(iter->getDB());
+ out.back().setUser(name->getUser());
+ out.back().setDb(name->getDB());
}
return out;
@@ -71,19 +71,19 @@ std::vector<KillAllSessionsRole> getKillAllSessionsImpersonateRoles(OperationCon
} // namespace
-std::tuple<std::vector<UserName>, std::vector<RoleName>> getKillAllSessionsByPatternImpersonateData(
- const KillAllSessionsByPattern& pattern) {
- std::tuple<std::vector<UserName>, std::vector<RoleName>> out;
+std::tuple<boost::optional<UserName>, std::vector<RoleName>>
+getKillAllSessionsByPatternImpersonateData(const KillAllSessionsByPattern& pattern) {
+ std::tuple<boost::optional<UserName>, std::vector<RoleName>> out;
- auto& users = std::get<0>(out);
+ auto& user = std::get<0>(out);
auto& roles = std::get<1>(out);
- if (pattern.getUsers()) {
- users.reserve(pattern.getUsers()->size());
-
- for (auto&& user : pattern.getUsers().get()) {
- users.emplace_back(user.getUser(), user.getDb());
- }
+ if (pattern.getUsers() && (pattern.getUsers()->size() > 0)) {
+ uassert(ErrorCodes::BadValue,
+ "Too many users in impersonation data",
+ pattern.getUsers()->size() <= 1);
+ const auto& impUser = pattern.getUsers().get()[0];
+ user = UserName(impUser.getUser(), impUser.getDb());
}
if (pattern.getRoles()) {
@@ -119,16 +119,14 @@ KillAllSessionsByPatternItem makeKillAllSessionsByPattern(OperationContext* opCt
}
KillAllSessionsByPatternSet makeSessionFilterForAuthenticatedUsers(OperationContext* opCtx) {
- AuthorizationSession* authSession = AuthorizationSession::get(opCtx->getClient());
+ auto* as = AuthorizationSession::get(opCtx->getClient());
KillAllSessionsByPatternSet patterns;
- for (auto it = authSession->getAuthenticatedUserNames(); it.more(); it.next()) {
- if (auto user = authSession->lookupUser(*it)) {
- KillAllSessionsByPattern pattern;
- pattern.setUid(user->getDigest());
- KillAllSessionsByPatternItem item{std::move(pattern), APIParameters::get(opCtx)};
- patterns.emplace(std::move(item));
- }
+ if (auto user = as->getAuthenticatedUser()) {
+ KillAllSessionsByPattern pattern;
+ pattern.setUid(user.get()->getDigest());
+ KillAllSessionsByPatternItem item{std::move(pattern), APIParameters::get(opCtx)};
+ patterns.emplace(std::move(item));
}
return patterns;
}
diff --git a/src/mongo/db/kill_sessions.h b/src/mongo/db/kill_sessions.h
index 31ceeed9375..c666388208b 100644
--- a/src/mongo/db/kill_sessions.h
+++ b/src/mongo/db/kill_sessions.h
@@ -84,8 +84,8 @@ inline bool operator!=(const KillAllSessionsByPatternItem& lhs,
using KillAllSessionsByPatternSet =
stdx::unordered_set<KillAllSessionsByPatternItem, KillAllSessionsByPatternItemHash>;
-std::tuple<std::vector<UserName>, std::vector<RoleName>> getKillAllSessionsByPatternImpersonateData(
- const KillAllSessionsByPattern& pattern);
+std::tuple<boost::optional<UserName>, std::vector<RoleName>>
+getKillAllSessionsByPatternImpersonateData(const KillAllSessionsByPattern& pattern);
/**
* Note: All three of the below makeKillAllSessionsByPattern helpers take opCtx to inline the
diff --git a/src/mongo/db/kill_sessions_common.cpp b/src/mongo/db/kill_sessions_common.cpp
index a26c3c9fd5e..90a92c5d9b6 100644
--- a/src/mongo/db/kill_sessions_common.cpp
+++ b/src/mongo/db/kill_sessions_common.cpp
@@ -102,8 +102,11 @@ void killSessionsReport(OperationContext* opCtx, const BSONObj& cmdObj) {
auto client = opCtx->getClient();
if (client) {
if (AuthorizationManager::get(client->getServiceContext())->isAuthEnabled()) {
- auto user = AuthorizationSession::get(client)->getAuthenticatedUserNames();
- attr.add("user", user->toBSON());
+ if (auto user = AuthorizationSession::get(client)->getAuthenticatedUserName()) {
+ attr.add("user", BSON_ARRAY(user->toBSON()));
+ } else {
+ attr.add("user", BSONArray());
+ }
}
if (client->session()) {
diff --git a/src/mongo/db/kill_sessions_common.h b/src/mongo/db/kill_sessions_common.h
index 44fb96857e9..d74dda981a1 100644
--- a/src/mongo/db/kill_sessions_common.h
+++ b/src/mongo/db/kill_sessions_common.h
@@ -68,13 +68,13 @@ public:
AuthorizationSession* authSession = AuthorizationSession::get(opCtx->getClient());
if (pattern.getUsers() && pattern.getRoles()) {
- std::tie(_names, _roles) = getKillAllSessionsByPatternImpersonateData(pattern);
- _raii.emplace(authSession, &_names, &_roles);
+ std::tie(_name, _roles) = getKillAllSessionsByPatternImpersonateData(pattern);
+ _raii.emplace(authSession, &_name, &_roles);
}
}
private:
- std::vector<UserName> _names;
+ boost::optional<UserName> _name;
std::vector<RoleName> _roles;
boost::optional<AuthorizationSession::ScopedImpersonate> _raii;
};
diff --git a/src/mongo/db/logical_session_id_helpers.cpp b/src/mongo/db/logical_session_id_helpers.cpp
index 0f312f0d30f..035b54b061d 100644
--- a/src/mongo/db/logical_session_id_helpers.cpp
+++ b/src/mongo/db/logical_session_id_helpers.cpp
@@ -39,6 +39,23 @@
#include "mongo/db/operation_context.h"
namespace mongo {
+namespace {
+/**
+ * If auth is not enabled, will return boost::none.
+ * Otherwise, a user must be actively authenticated on the client,
+ * and a handle to this user will be returned.
+ */
+boost::optional<UserHandle> getAuthenticatedUser(Client* client) {
+ if (!AuthorizationManager::get(client->getServiceContext())->isAuthEnabled()) {
+ return boost::none;
+ }
+
+ auto optUser = AuthorizationSession::get(client)->getAuthenticatedUser();
+ uassert(ErrorCodes::Unauthorized, "Logical sessions require authentication", optUser);
+
+ return optUser.get();
+}
+} // namespace
/**
* This is a safe hash that will not collide with a username because all full usernames include an
@@ -47,20 +64,12 @@ namespace mongo {
const auto kNoAuthDigest = SHA256Block::computeHash(reinterpret_cast<const uint8_t*>(""), 0);
SHA256Block getLogicalSessionUserDigestForLoggedInUser(const OperationContext* opCtx) {
- auto client = opCtx->getClient();
- ServiceContext* serviceContext = client->getServiceContext();
-
- if (AuthorizationManager::get(serviceContext)->isAuthEnabled()) {
- UserName userName;
-
- const auto user = AuthorizationSession::get(client)->getSingleUser();
- invariant(user);
-
+ if (auto user = getAuthenticatedUser(opCtx->getClient())) {
uassert(ErrorCodes::BadValue,
"Username too long to use with logical sessions",
- user->getName().getDisplayNameLength() < kMaximumUserNameLengthForLogicalSessions);
-
- return user->getDigest();
+ user.get()->getName().getDisplayNameLength() <
+ kMaximumUserNameLengthForLogicalSessions);
+ return user.get()->getDigest();
} else {
return kNoAuthDigest;
}
@@ -172,14 +181,9 @@ LogicalSessionRecord makeLogicalSessionRecord(OperationContext* opCtx, Date_t la
LogicalSessionId id{};
LogicalSessionRecord lsr{};
- auto client = opCtx->getClient();
- ServiceContext* serviceContext = client->getServiceContext();
- if (AuthorizationManager::get(serviceContext)->isAuthEnabled()) {
- auto user = AuthorizationSession::get(client)->getSingleUser();
- invariant(user);
-
- id.setUid(user->getDigest());
- lsr.setUser(StringData(user->getName().getDisplayName()));
+ if (auto user = getAuthenticatedUser(opCtx->getClient())) {
+ id.setUid(user.get()->getDigest());
+ lsr.setUser(StringData(user.get()->getName().getDisplayName()));
} else {
id.setUid(kNoAuthDigest);
}
@@ -210,14 +214,9 @@ LogicalSessionRecord makeLogicalSessionRecord(OperationContext* opCtx,
Date_t lastUse) {
auto lsr = makeLogicalSessionRecord(lsid, lastUse);
- auto client = opCtx->getClient();
- ServiceContext* serviceContext = client->getServiceContext();
- if (AuthorizationManager::get(serviceContext)->isAuthEnabled()) {
- auto user = AuthorizationSession::get(client)->getSingleUser();
- invariant(user);
-
- if (user->getDigest() == lsid.getUid()) {
- lsr.setUser(StringData(user->getName().getDisplayName()));
+ if (auto user = getAuthenticatedUser(opCtx->getClient())) {
+ if (user.get()->getDigest() == lsid.getUid()) {
+ lsr.setUser(StringData(user.get()->getName().getDisplayName()));
}
}
diff --git a/src/mongo/db/pipeline/aggregate_command.idl b/src/mongo/db/pipeline/aggregate_command.idl
index 03637da1041..cff03899e4f 100644
--- a/src/mongo/db/pipeline/aggregate_command.idl
+++ b/src/mongo/db/pipeline/aggregate_command.idl
@@ -86,7 +86,7 @@ commands:
- check: is_coauthorized_with_client
- check: is_coauthorized_with
- check: should_ignore_auth_checks
- - check: get_single_user
+ - check: get_authenticated_user
- check: lookup_user
- privilege: # many commands
resource_pattern: exact_namespace
diff --git a/src/mongo/db/pipeline/document_source_list_local_sessions.cpp b/src/mongo/db/pipeline/document_source_list_local_sessions.cpp
index 6be5ca875a9..426a8d3bacb 100644
--- a/src/mongo/db/pipeline/document_source_list_local_sessions.cpp
+++ b/src/mongo/db/pipeline/document_source_list_local_sessions.cpp
@@ -88,9 +88,10 @@ ListSessionsUser getUserNameForLoggedInUser(const OperationContext* opCtx) {
ListSessionsUser user;
if (AuthorizationManager::get(client->getServiceContext())->isAuthEnabled()) {
- const auto& userName = AuthorizationSession::get(client)->getSingleUser()->getName();
- user.setUser(userName.getUser());
- user.setDb(userName.getDB());
+ const auto& userName = AuthorizationSession::get(client)->getAuthenticatedUserName();
+ uassert(ErrorCodes::Unauthorized, "There is no user authenticated", userName);
+ user.setUser(userName->getUser());
+ user.setDb(userName->getDB());
} else {
user.setUser("");
user.setDb("");
diff --git a/src/mongo/db/s/forwardable_operation_metadata.cpp b/src/mongo/db/s/forwardable_operation_metadata.cpp
index d3ca368cfb8..1a83a2eb1f1 100644
--- a/src/mongo/db/s/forwardable_operation_metadata.cpp
+++ b/src/mongo/db/s/forwardable_operation_metadata.cpp
@@ -62,8 +62,10 @@ void ForwardableOperationMetadata::setOn(OperationContext* opCtx) const {
if (const auto& optAuthMetadata = getImpersonatedUserMetadata()) {
const auto& authMetadata = optAuthMetadata.get();
- if (!authMetadata.getUsers().empty() || !authMetadata.getRoles().empty()) {
- AuthorizationSession::get(client)->setImpersonatedUserData(authMetadata.getUsers(),
+ const auto& users = authMetadata.getUsers();
+ if (!users.empty() || !authMetadata.getRoles().empty()) {
+ fassert(ErrorCodes::InternalError, users.size() == 1);
+ AuthorizationSession::get(client)->setImpersonatedUserData(users[0],
authMetadata.getRoles());
}
}
diff --git a/src/mongo/embedded/embedded_auth_session.cpp b/src/mongo/embedded/embedded_auth_session.cpp
index 9c9e2899c24..d086a0a3309 100644
--- a/src/mongo/embedded/embedded_auth_session.cpp
+++ b/src/mongo/embedded/embedded_auth_session.cpp
@@ -78,7 +78,7 @@ public:
UASSERT_NOT_IMPLEMENTED;
}
- User* getSingleUser() override {
+ boost::optional<UserHandle> getAuthenticatedUser() override {
UASSERT_NOT_IMPLEMENTED;
}
@@ -92,8 +92,8 @@ public:
return false;
}
- UserNameIterator getAuthenticatedUserNames() override {
- return UserNameIterator(std::make_unique<Impl>());
+ boost::optional<UserName> getAuthenticatedUserName() override {
+ return boost::none;
}
RoleNameIterator getAuthenticatedRoleNames() override {
@@ -169,12 +169,11 @@ public:
return true;
}
- void setImpersonatedUserData(const std::vector<UserName>&,
- const std::vector<RoleName>&) override {
+ void setImpersonatedUserData(const UserName&, const std::vector<RoleName>&) override {
UASSERT_NOT_IMPLEMENTED;
}
- UserNameIterator getImpersonatedUserNames() override {
+ boost::optional<UserName> getImpersonatedUserName() override {
UASSERT_NOT_IMPLEMENTED;
}
@@ -190,7 +189,7 @@ public:
return true;
}
- bool isCoauthorizedWith(UserNameIterator) override {
+ bool isCoauthorizedWith(const boost::optional<UserName>&) override {
return true;
}
@@ -228,7 +227,7 @@ public:
}
protected:
- std::tuple<std::vector<UserName>*, std::vector<RoleName>*> _getImpersonations() override {
+ std::tuple<boost::optional<UserName>*, std::vector<RoleName>*> _getImpersonations() override {
UASSERT_NOT_IMPLEMENTED;
}
diff --git a/src/mongo/rpc/metadata/impersonated_user_metadata.cpp b/src/mongo/rpc/metadata/impersonated_user_metadata.cpp
index 64b78931f39..63d0d4f7837 100644
--- a/src/mongo/rpc/metadata/impersonated_user_metadata.cpp
+++ b/src/mongo/rpc/metadata/impersonated_user_metadata.cpp
@@ -58,6 +58,10 @@ void readImpersonatedUserMetadata(const BSONElement& elem, OperationContext* opC
IDLParserErrorContext errCtx(kImpersonationMetadataSectionName);
auto data = ImpersonatedUserMetadata::parse(errCtx, elem.embeddedObject());
+ uassert(ErrorCodes::BadValue,
+ "Impersonating multiple users is not supported",
+ data.getUsers().size() <= 1);
+
// Set the impersonation data only if there are actually impersonated
// users/roles.
if ((!data.getUsers().empty()) || (!data.getRoles().empty())) {
@@ -75,20 +79,24 @@ void writeAuthDataToImpersonatedUserMetadata(OperationContext* opCtx, BSONObjBui
// Otherwise construct a metadata section from the list of authenticated users/roles
auto authSession = AuthorizationSession::get(opCtx->getClient());
- auto userNames = authSession->getImpersonatedUserNames();
+ auto userName = authSession->getImpersonatedUserName();
auto roleNames = authSession->getImpersonatedRoleNames();
- if (!userNames.more() && !roleNames.more()) {
- userNames = authSession->getAuthenticatedUserNames();
+ if (!userName && !roleNames.more()) {
+ userName = authSession->getAuthenticatedUserName();
roleNames = authSession->getAuthenticatedRoleNames();
}
// If there are no users/roles being impersonated just exit
- if (!userNames.more() && !roleNames.more()) {
+ if (!userName && !roleNames.more()) {
return;
}
ImpersonatedUserMetadata metadata;
- metadata.setUsers(userNameIteratorToContainer<std::vector<UserName>>(userNames));
+ if (userName) {
+ metadata.setUsers({userName.get()});
+ } else {
+ metadata.setUsers({});
+ }
metadata.setRoles(roleNameIteratorToContainer<std::vector<RoleName>>(roleNames));
BSONObjBuilder section(out->subobjStart(kImpersonationMetadataSectionName));
diff --git a/src/mongo/s/commands/cluster_killcursors_cmd.cpp b/src/mongo/s/commands/cluster_killcursors_cmd.cpp
index 716107f43d1..31faadc80f2 100644
--- a/src/mongo/s/commands/cluster_killcursors_cmd.cpp
+++ b/src/mongo/s/commands/cluster_killcursors_cmd.cpp
@@ -45,8 +45,9 @@ struct ClusterKillCursorsCmd {
const NamespaceString& nss,
CursorId cursorId) {
auto const authzSession = AuthorizationSession::get(opCtx->getClient());
- auto authChecker = [&authzSession, &nss](UserNameIterator userNames) -> Status {
- return auth::checkAuthForKillCursors(authzSession, nss, userNames);
+ auto authChecker = [&authzSession,
+ &nss](const boost::optional<UserName>& userName) -> Status {
+ return auth::checkAuthForKillCursors(authzSession, nss, userName);
};
return Grid::get(opCtx)->getCursorManager()->checkAuthForKillCursors(
diff --git a/src/mongo/s/commands/cluster_list_collections_cmd.cpp b/src/mongo/s/commands/cluster_list_collections_cmd.cpp
index 511a086a4a8..8b55ddca0a8 100644
--- a/src/mongo/s/commands/cluster_list_collections_cmd.cpp
+++ b/src/mongo/s/commands/cluster_list_collections_cmd.cpp
@@ -127,10 +127,8 @@ BSONObj rewriteCommandForListingOwnCollections(OperationContext* opCtx,
// Compute the set of collection names which would be permissible to return.
std::set<std::string> collectionNames;
- for (UserNameIterator nameIter = authzSession->getAuthenticatedUserNames(); nameIter.more();
- nameIter.next()) {
- User* authUser = authzSession->lookupUser(*nameIter);
- for (const auto& [resource, privilege] : authUser->getPrivileges()) {
+ if (auto authUser = authzSession->getAuthenticatedUser()) {
+ for (const auto& [resource, privilege] : authUser.get()->getPrivileges()) {
if (resource.isCollectionPattern() ||
(resource.isExactNamespacePattern() && resource.databaseToMatch() == dbName)) {
collectionNames.emplace(resource.collectionToMatch().toString());
diff --git a/src/mongo/s/query/cluster_aggregation_planner.cpp b/src/mongo/s/query/cluster_aggregation_planner.cpp
index dc044f72309..0c80b838544 100644
--- a/src/mongo/s/query/cluster_aggregation_planner.cpp
+++ b/src/mongo/s/query/cluster_aggregation_planner.cpp
@@ -344,14 +344,14 @@ BSONObj establishMergingMongosCursor(OperationContext* opCtx,
CursorId clusterCursorId = 0;
if (cursorState == ClusterCursorManager::CursorState::NotExhausted) {
- auto authUsers = AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames();
+ auto authUser = AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserName();
clusterCursorId = uassertStatusOK(Grid::get(opCtx)->getCursorManager()->registerCursor(
opCtx,
ccc.releaseCursor(),
requestedNss,
ClusterCursorManager::CursorType::MultiTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- authUsers));
+ authUser));
}
// Fill out the aggregation metrics in CurOp.
diff --git a/src/mongo/s/query/cluster_cursor_manager.cpp b/src/mongo/s/query/cluster_cursor_manager.cpp
index 5eaa7e05306..3361c1dace5 100644
--- a/src/mongo/s/query/cluster_cursor_manager.cpp
+++ b/src/mongo/s/query/cluster_cursor_manager.cpp
@@ -162,7 +162,7 @@ StatusWith<CursorId> ClusterCursorManager::registerCursor(
const NamespaceString& nss,
CursorType cursorType,
CursorLifetime cursorLifetime,
- UserNameIterator authenticatedUsers) {
+ const boost::optional<UserName>& authenticatedUser) {
// Read the clock out of the lock.
const auto now = _clockSource->now();
@@ -188,7 +188,7 @@ StatusWith<CursorId> ClusterCursorManager::registerCursor(
cursorType,
cursorLifetime,
now,
- authenticatedUsers,
+ authenticatedUser,
opCtx->getClient()->getUUID(),
opCtx->getOperationKey(),
nss));
@@ -216,7 +216,7 @@ StatusWith<ClusterCursorManager::PinnedCursor> ClusterCursorManager::checkOutCur
}
// Check if the user is coauthorized to access this cursor.
- auto authCheckStatus = authChecker(entry->getAuthenticatedUsers());
+ auto authCheckStatus = authChecker(entry->getAuthenticatedUser());
if (!authCheckStatus.isOK()) {
return authCheckStatus.withContext(str::stream()
<< "cursor id " << cursorId
@@ -296,9 +296,9 @@ Status ClusterCursorManager::checkAuthForKillCursors(OperationContext* opCtx,
return cursorNotFoundStatus(cursorId);
}
- // Note that getAuthenticatedUsers() is thread-safe, so it's okay to call even if there's
+ // Note that getAuthenticatedUser() is thread-safe, so it's okay to call even if there's
// an operation using the cursor.
- return authChecker(entry->getAuthenticatedUsers());
+ return authChecker(entry->getAuthenticatedUser());
}
void ClusterCursorManager::killOperationUsingCursor(WithLock, CursorEntry* entry) {
@@ -497,7 +497,7 @@ std::vector<GenericCursor> ClusterCursorManager::getIdleCursors(
// permission to see this cursor.
if (ctxAuth->getAuthorizationManager().isAuthEnabled() &&
userMode == MongoProcessInterface::CurrentOpUserMode::kExcludeOthers &&
- !ctxAuth->isCoauthorizedWith(entry.getAuthenticatedUsers())) {
+ !ctxAuth->isCoauthorizedWith(entry.getAuthenticatedUser())) {
continue;
}
if (entry.isKillPending() || entry.getOperationUsingCursor()) {
diff --git a/src/mongo/s/query/cluster_cursor_manager.h b/src/mongo/s/query/cluster_cursor_manager.h
index be10b0d60bd..730ccc40624 100644
--- a/src/mongo/s/query/cluster_cursor_manager.h
+++ b/src/mongo/s/query/cluster_cursor_manager.h
@@ -117,7 +117,7 @@ public:
// Represents a function that may be passed into a ClusterCursorManager method which checks
// whether the current client is authorized to perform the operation in question. The function
// will be passed the list of users authorized to use the cursor.
- using AuthzCheckFn = std::function<Status(UserNameIterator)>;
+ using AuthzCheckFn = std::function<Status(const boost::optional<UserName>&)>;
/**
* PinnedCursor is a moveable, non-copyable class representing ownership of a cursor that has
@@ -226,7 +226,7 @@ public:
CursorType cursorType,
CursorLifetime cursorLifetime,
Date_t lastActive,
- UserNameIterator authenticatedUsersIter,
+ boost::optional<UserName> authenticatedUser,
UUID clientUUID,
boost::optional<OperationKey> opKey,
NamespaceString nss)
@@ -238,8 +238,7 @@ public:
_opKey(std::move(opKey)),
_nss(std::move(nss)),
_originatingClient(std::move(clientUUID)),
- _authenticatedUsers(
- userNameIteratorToContainer<std::vector<UserName>>(authenticatedUsersIter)) {
+ _authenticatedUser(std::move(authenticatedUser)) {
invariant(_cursor);
}
@@ -330,8 +329,8 @@ public:
_lastActive = lastActive;
}
- UserNameIterator getAuthenticatedUsers() const {
- return makeUserNameIterator(_authenticatedUsers.begin(), _authenticatedUsers.end());
+ const boost::optional<UserName>& getAuthenticatedUser() const {
+ return _authenticatedUser;
}
const UUID& originatingClientUuid() const {
@@ -365,7 +364,7 @@ public:
/**
* The set of users authorized to use this cursor.
*/
- std::vector<UserName> _authenticatedUsers;
+ boost::optional<UserName> _authenticatedUser;
};
/**
@@ -408,7 +407,7 @@ public:
const NamespaceString& nss,
CursorType cursorType,
CursorLifetime cursorLifetime,
- UserNameIterator authenticatedUsers);
+ const boost::optional<UserName>& authenticatedUser);
/**
* Moves the given cursor to the 'pinned' state, and transfers ownership of the cursor to the
diff --git a/src/mongo/s/query/cluster_cursor_manager_test.cpp b/src/mongo/s/query/cluster_cursor_manager_test.cpp
index 0176fe23947..58cd6bcdb02 100644
--- a/src/mongo/s/query/cluster_cursor_manager_test.cpp
+++ b/src/mongo/s/query/cluster_cursor_manager_test.cpp
@@ -60,11 +60,11 @@ protected:
_manager.shutdown(_opCtx.get());
}
- static Status successAuthChecker(UserNameIterator userNames) {
+ static Status successAuthChecker(const boost::optional<UserName>&) {
return Status::OK();
};
- static Status failAuthChecker(UserNameIterator userNames) {
+ static Status failAuthChecker(const boost::optional<UserName>&) {
return {ErrorCodes::Unauthorized, "Unauthorized"};
};
@@ -147,7 +147,7 @@ TEST_F(ClusterCursorManagerTest, RegisterCursor) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(pinnedCursor.getStatus());
@@ -168,7 +168,7 @@ TEST_F(ClusterCursorManagerTest, RegisterCursorReturnsNonZeroId) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_NE(0, cursorId);
}
@@ -182,7 +182,7 @@ TEST_F(ClusterCursorManagerTest, CheckOutCursorBasic) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto checkedOutCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(checkedOutCursor.getStatus());
@@ -210,7 +210,7 @@ TEST_F(ClusterCursorManagerTest, CheckOutCursorMultipleCursors) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
}
for (int i = 0; i < numCursors; ++i) {
auto pinnedCursor =
@@ -234,7 +234,7 @@ TEST_F(ClusterCursorManagerTest, CheckOutCursorPinned) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(pinnedCursor.getStatus());
@@ -252,7 +252,7 @@ TEST_F(ClusterCursorManagerTest, CheckOutCursorKilled) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
killCursorFromDifferentOpCtx(cursorId);
ASSERT_EQ(ErrorCodes::CursorNotFound,
getManager()
@@ -275,7 +275,7 @@ TEST_F(ClusterCursorManagerTest, CheckOutCursorWrongCursorId) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_EQ(ErrorCodes::CursorNotFound,
getManager()
->checkOutCursor(cursorId + 1, getOperationContext(), successAuthChecker)
@@ -291,7 +291,7 @@ TEST_F(ClusterCursorManagerTest, CheckOutCursorUpdateActiveTime) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
Date_t cursorRegistrationTime = getClockSource()->now();
getClockSource()->advance(Milliseconds(1));
auto checkedOutCursor =
@@ -309,7 +309,7 @@ TEST_F(ClusterCursorManagerTest, CheckOutCursorAuthFails) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto checkedOutCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), failAuthChecker);
ASSERT_EQ(checkedOutCursor.getStatus(), ErrorCodes::Unauthorized);
@@ -325,7 +325,7 @@ TEST_F(ClusterCursorManagerTest, ReturnCursorUpdateActiveTime) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
Date_t cursorCheckOutTime = getClockSource()->now();
auto checkedOutCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
@@ -344,7 +344,7 @@ TEST_F(ClusterCursorManagerTest, KillUnpinnedCursorBasic) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
killCursorFromDifferentOpCtx(cursorId);
ASSERT(isMockCursorKilled(0));
}
@@ -357,7 +357,7 @@ TEST_F(ClusterCursorManagerTest, KillPinnedCursorBasic) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(pinnedCursor.getStatus());
@@ -384,7 +384,7 @@ TEST_F(ClusterCursorManagerTest, KillCursorMultipleCursors) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
}
// Kill each cursor and verify that it was successfully killed.
for (size_t i = 0; i < numCursors; ++i) {
@@ -408,7 +408,7 @@ TEST_F(ClusterCursorManagerTest, KillCursorWrongCursorId) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
Status killResult = getManager()->killCursor(getOperationContext(), cursorId + 1);
ASSERT_EQ(ErrorCodes::CursorNotFound, killResult);
}
@@ -420,7 +420,7 @@ TEST_F(ClusterCursorManagerTest, KillMortalCursorsInactiveSinceBasic) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
getManager()->killMortalCursorsInactiveSince(getOperationContext(), getClockSource()->now());
ASSERT(isMockCursorKilled(0));
}
@@ -434,7 +434,7 @@ TEST_F(ClusterCursorManagerTest, KillMortalCursorsInactiveSinceSkipUnexpired) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
getManager()->killMortalCursorsInactiveSince(getOperationContext(), timeBeforeCursorCreation);
ASSERT(!isMockCursorKilled(0));
}
@@ -446,7 +446,7 @@ TEST_F(ClusterCursorManagerTest, KillMortalCursorsInactiveSinceSkipImmortal) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Immortal,
- UserNameIterator()));
+ boost::none));
getManager()->killMortalCursorsInactiveSince(getOperationContext(), getClockSource()->now());
ASSERT(!isMockCursorKilled(0));
}
@@ -460,7 +460,7 @@ TEST_F(ClusterCursorManagerTest, ShouldNotKillPinnedCursors) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pin = assertGet(
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker));
getManager()->killMortalCursorsInactiveSince(getOperationContext(), getClockSource()->now());
@@ -485,7 +485,7 @@ TEST_F(ClusterCursorManagerTest, KillMortalCursorsInactiveSinceMultipleCursors)
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
getClockSource()->advance(Milliseconds(1));
}
getManager()->killMortalCursorsInactiveSince(getOperationContext(), cutoff);
@@ -507,7 +507,7 @@ TEST_F(ClusterCursorManagerTest, KillAllCursors) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
}
getManager()->killAllCursors(getOperationContext());
for (size_t i = 0; i < numCursors; ++i) {
@@ -523,7 +523,7 @@ TEST_F(ClusterCursorManagerTest, KillCursorsSatisfyingAlwaysTrueKillsAllCursors)
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
}
auto pred = [](CursorId, const ClusterCursorManager::CursorEntry&) { return true; };
auto nKilled = getManager()->killCursorsSatisfying(getOperationContext(), std::move(pred));
@@ -541,7 +541,7 @@ TEST_F(ClusterCursorManagerTest, KillCursorsSatisfyingAlwaysFalseKillsNoCursors)
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
}
auto pred = [](CursorId, const ClusterCursorManager::CursorEntry&) { return false; };
auto nKilled = getManager()->killCursorsSatisfying(getOperationContext(), std::move(pred));
@@ -562,7 +562,7 @@ TEST_F(ClusterCursorManagerTest, KillCursorsSatisfyingOnlyKillsMatchingSubset) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator());
+ boost::none);
ASSERT_OK(swCursorId);
if (shouldKillCursor(i))
idsToKill.insert(swCursorId.getValue());
@@ -589,7 +589,7 @@ TEST_F(ClusterCursorManagerTest, KillCursorsSatisfyingBasedOnOpKey) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
}
auto pred = [&](CursorId id, const ClusterCursorManager::CursorEntry& entry) {
return entry.getOperationKey() == getOperationContext()->getOperationKey();
@@ -608,7 +608,7 @@ TEST_F(ClusterCursorManagerTest, CorrectlyRecordsOriginatingClient) {
nss,
ClusterCursorManager::CursorType::MultiTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
// Now insert some cursors under a different client.
const size_t numAltClientCursors = 10;
{
@@ -621,7 +621,7 @@ TEST_F(ClusterCursorManagerTest, CorrectlyRecordsOriginatingClient) {
nss,
ClusterCursorManager::CursorType::MultiTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
}
}
@@ -652,7 +652,7 @@ TEST_F(ClusterCursorManagerTest, StatsRegisterShardedCursor) {
nss,
ClusterCursorManager::CursorType::MultiTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_EQ(1U, getManager()->stats().cursorsMultiTarget);
}
@@ -663,7 +663,7 @@ TEST_F(ClusterCursorManagerTest, StatsRegisterNotShardedCursor) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_EQ(1U, getManager()->stats().cursorsSingleTarget);
}
@@ -675,7 +675,7 @@ TEST_F(ClusterCursorManagerTest, StatsPinCursor) {
nss,
ClusterCursorManager::CursorType::MultiTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_EQ(1U, getManager()->stats().cursorsPinned);
@@ -691,7 +691,7 @@ TEST_F(ClusterCursorManagerTest, StatsRegisterMultipleCursors) {
nss,
ClusterCursorManager::CursorType::MultiTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_EQ(i + 1, getManager()->stats().cursorsMultiTarget);
ASSERT_EQ(0U, getManager()->stats().cursorsSingleTarget);
}
@@ -702,7 +702,7 @@ TEST_F(ClusterCursorManagerTest, StatsRegisterMultipleCursors) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_EQ(numShardedCursors, getManager()->stats().cursorsMultiTarget);
ASSERT_EQ(i + 1, getManager()->stats().cursorsSingleTarget);
}
@@ -716,7 +716,7 @@ TEST_F(ClusterCursorManagerTest, StatsKillShardedCursor) {
nss,
ClusterCursorManager::CursorType::MultiTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_EQ(1U, getManager()->stats().cursorsMultiTarget);
ASSERT_OK(getManager()->killCursor(getOperationContext(), cursorId));
ASSERT_EQ(0U, getManager()->stats().cursorsMultiTarget);
@@ -730,7 +730,7 @@ TEST_F(ClusterCursorManagerTest, StatsKillNotShardedCursor) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_EQ(1U, getManager()->stats().cursorsSingleTarget);
ASSERT_OK(getManager()->killCursor(getOperationContext(), cursorId));
ASSERT_EQ(0U, getManager()->stats().cursorsSingleTarget);
@@ -744,7 +744,7 @@ TEST_F(ClusterCursorManagerTest, StatsKillPinnedCursor) {
nss,
ClusterCursorManager::CursorType::MultiTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_EQ(1U, getManager()->stats().cursorsPinned);
@@ -763,7 +763,7 @@ TEST_F(ClusterCursorManagerTest, StatsExhaustShardedCursor) {
nss,
ClusterCursorManager::CursorType::MultiTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(pinnedCursor.getStatus());
@@ -781,7 +781,7 @@ TEST_F(ClusterCursorManagerTest, StatsExhaustNotShardedCursor) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(pinnedCursor.getStatus());
@@ -800,7 +800,7 @@ TEST_F(ClusterCursorManagerTest, StatsExhaustPinnedCursor) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(pinnedCursor.getStatus());
@@ -819,7 +819,7 @@ TEST_F(ClusterCursorManagerTest, StatsCheckInWithoutExhaustingPinnedCursor) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(pinnedCursor.getStatus());
@@ -844,7 +844,7 @@ TEST_F(ClusterCursorManagerTest, PinnedCursorReturnCursorNotExhausted) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto registeredCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(registeredCursor.getStatus());
@@ -866,7 +866,7 @@ TEST_F(ClusterCursorManagerTest, PinnedCursorReturnCursorExhausted) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto registeredCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(registeredCursor.getStatus());
@@ -894,7 +894,7 @@ TEST_F(ClusterCursorManagerTest, PinnedCursorReturnCursorExhaustedWithNonExhaust
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto registeredCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(registeredCursor.getStatus());
@@ -920,7 +920,7 @@ TEST_F(ClusterCursorManagerTest, PinnedCursorMoveAssignmentKill) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
pinnedCursor = ClusterCursorManager::PinnedCursor();
@@ -936,7 +936,7 @@ TEST_F(ClusterCursorManagerTest, PinnedCursorDestructorKill) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
}
@@ -954,7 +954,7 @@ TEST_F(ClusterCursorManagerTest, RemotesExhausted) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(pinnedCursor.getStatus());
@@ -970,7 +970,7 @@ TEST_F(ClusterCursorManagerTest, DoNotDestroyKilledPinnedCursors) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
ASSERT_OK(pinnedCursor.getStatus());
@@ -1008,7 +1008,7 @@ TEST_F(ClusterCursorManagerTest, CursorStoresAPIParameters) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor = assertGet(
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker));
@@ -1024,7 +1024,7 @@ TEST_F(ClusterCursorManagerTest, CannotRegisterCursorDuringShutdown) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT(!isMockCursorKilled(0));
getManager()->shutdown(getOperationContext());
@@ -1037,7 +1037,7 @@ TEST_F(ClusterCursorManagerTest, CannotRegisterCursorDuringShutdown) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
}
TEST_F(ClusterCursorManagerTest, PinnedCursorNotKilledOnShutdown) {
@@ -1047,7 +1047,7 @@ TEST_F(ClusterCursorManagerTest, PinnedCursorNotKilledOnShutdown) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
@@ -1069,7 +1069,7 @@ TEST_F(ClusterCursorManagerTest, CannotCheckoutCursorDuringShutdown) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT(!isMockCursorKilled(0));
getManager()->shutdown(getOperationContext());
@@ -1092,7 +1092,7 @@ TEST_F(ClusterCursorManagerTest, CursorsWithoutSessions) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
// Manager should have no active sessions.
LogicalSessionIdSet lsids;
@@ -1112,7 +1112,7 @@ TEST_F(ClusterCursorManagerTest, OneCursorWithASession) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
// Retrieve all sessions active in manager - set should contain just lsid.
LogicalSessionIdSet lsids;
@@ -1147,7 +1147,7 @@ TEST_F(ClusterCursorManagerTest, GetSessionIdsWhileCheckedOut) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
// Check the cursor out, then try to append cursors, see that we get one.
auto res = getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
@@ -1169,14 +1169,14 @@ TEST_F(ClusterCursorManagerTest, MultipleCursorsWithSameSession) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto cursorId2 =
assertGet(getManager()->registerCursor(getOperationContext(),
allocateMockCursor(lsid),
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
// Retrieve all sessions - set should contain just lsid.
stdx::unordered_set<LogicalSessionId, LogicalSessionIdHash> lsids;
@@ -1219,7 +1219,7 @@ TEST_F(ClusterCursorManagerTest, MultipleCursorsMultipleSessions) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
CursorId cursor2 =
assertGet(getManager()->registerCursor(getOperationContext(),
@@ -1227,14 +1227,14 @@ TEST_F(ClusterCursorManagerTest, MultipleCursorsMultipleSessions) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_OK(getManager()->registerCursor(getOperationContext(),
allocateMockCursor(),
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
// Retrieve all sessions - should be both lsids.
LogicalSessionIdSet lsids;
@@ -1265,7 +1265,7 @@ TEST_F(ClusterCursorManagerTest, ManyCursorsManySessions) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
}
// Retrieve all sessions.
@@ -1281,7 +1281,7 @@ TEST_F(ClusterCursorManagerTest, CheckAuthForKillCursors) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
ASSERT_EQ(ErrorCodes::CursorNotFound,
getManager()->checkAuthForKillCursors(
@@ -1301,7 +1301,7 @@ TEST_F(ClusterCursorManagerTest, PinnedCursorReturnsUnderlyingCursorTxnNumber) {
nss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- UserNameIterator()));
+ boost::none));
auto pinnedCursor =
getManager()->checkOutCursor(cursorId, getOperationContext(), successAuthChecker);
diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp
index 42b0b8154e5..7d6f93623f9 100644
--- a/src/mongo/s/query/cluster_find.cpp
+++ b/src/mongo/s/query/cluster_find.cpp
@@ -409,11 +409,11 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
const auto cursorLifetime = findCommand.getNoCursorTimeout()
? ClusterCursorManager::CursorLifetime::Immortal
: ClusterCursorManager::CursorLifetime::Mortal;
- auto authUsers = AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames();
+ auto authUser = AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserName();
ccc->incNBatches();
auto cursorId = uassertStatusOK(cursorManager->registerCursor(
- opCtx, ccc.releaseCursor(), query.nss(), cursorType, cursorLifetime, authUsers));
+ opCtx, ccc.releaseCursor(), query.nss(), cursorType, cursorLifetime, authUser));
// Record the cursorID in CurOp.
CurOp::get(opCtx)->debug().cursorid = cursorId;
@@ -699,8 +699,8 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx,
auto cursorManager = Grid::get(opCtx)->getCursorManager();
auto authzSession = AuthorizationSession::get(opCtx->getClient());
- auto authChecker = [&authzSession](UserNameIterator userNames) -> Status {
- return authzSession->isCoauthorizedWith(userNames)
+ auto authChecker = [&authzSession](const boost::optional<UserName>& userName) -> Status {
+ return authzSession->isCoauthorizedWith(userName)
? Status::OK()
: Status(ErrorCodes::Unauthorized, "User not authorized to access cursor");
};
diff --git a/src/mongo/s/query/store_possible_cursor.cpp b/src/mongo/s/query/store_possible_cursor.cpp
index c778daa9d84..329d47e34db 100644
--- a/src/mongo/s/query/store_possible_cursor.cpp
+++ b/src/mongo/s/query/store_possible_cursor.cpp
@@ -132,14 +132,14 @@ StatusWith<BSONObj> storePossibleCursor(OperationContext* opCtx,
// We don't expect to use this cursor until a subsequent getMore, so detach from the current
// OperationContext until then.
ccc->detachFromOperationContext();
- auto authUsers = AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames();
+ auto authUser = AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserName();
auto clusterCursorId =
cursorManager->registerCursor(opCtx,
ccc.releaseCursor(),
requestedNss,
ClusterCursorManager::CursorType::SingleTarget,
ClusterCursorManager::CursorLifetime::Mortal,
- authUsers);
+ authUser);
if (!clusterCursorId.isOK()) {
return clusterCursorId.getStatus();
}