diff options
-rw-r--r-- | jstests/auth/impersonation-deny.js | 12 | ||||
-rw-r--r-- | jstests/noPassthrough/out_merge_on_secondary_metadata.js | 2 | ||||
-rw-r--r-- | src/mongo/db/auth/impersonation_session.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/curop.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/s/forwardable_operation_metadata.cpp | 30 | ||||
-rw-r--r-- | src/mongo/db/s/forwardable_operation_metadata.idl | 4 | ||||
-rw-r--r-- | src/mongo/rpc/metadata/impersonated_user_metadata.cpp | 21 | ||||
-rw-r--r-- | src/mongo/rpc/metadata/impersonated_user_metadata.idl | 5 |
8 files changed, 80 insertions, 19 deletions
diff --git a/jstests/auth/impersonation-deny.js b/jstests/auth/impersonation-deny.js index 3f1f16eabfe..e3a962942ca 100644 --- a/jstests/auth/impersonation-deny.js +++ b/jstests/auth/impersonation-deny.js @@ -29,12 +29,22 @@ function testMongod(mongod, systemuserpwd = undefined) { const kImpersonatedHello = { hello: 1, "$audit": { - "$impersonatedUsers": [{user: 'admin', db: 'admin'}], + "$impersonatedUser": {user: 'admin', db: 'admin'}, "$impersonatedRoles": [{role: 'root', db: 'admin'}], } }; assertUnauthorized(kImpersonatedHello, 'Unauthorized use of impersonation metadata'); + // TODO SERVER-72448: Remove + const kImpersonatedHelloLegacy = { + hello: 1, + "$audit": { + "$impersonatedUsers": [{user: 'admin', db: 'admin'}], + "$impersonatedRoles": [{role: 'root', db: 'admin'}], + } + }; + assertUnauthorized(kImpersonatedHelloLegacy, 'Unauthorized use of impersonation metadata'); + // Try as admin (root role), should still fail. admin.auth('admin', 'admin'); assertUnauthorized(kImpersonatedHello, 'Unauthorized use of impersonation metadata'); diff --git a/jstests/noPassthrough/out_merge_on_secondary_metadata.js b/jstests/noPassthrough/out_merge_on_secondary_metadata.js index 250536bfcbd..3d9727bef7b 100644 --- a/jstests/noPassthrough/out_merge_on_secondary_metadata.js +++ b/jstests/noPassthrough/out_merge_on_secondary_metadata.js @@ -35,7 +35,7 @@ assert.commandWorked( primaryDB.runCommand({createUser: "testUser", pwd: "pwd", roles: [], writeConcern: {w: 2}})); primaryDB.grantRolesToUser("testUser", [{role: "readWrite", db: "test"}], {w: 2}); const expectedUserAndRoleMetadata = { - $impersonatedUsers: [{"user": "testUser", "db": "test"}], + $impersonatedUser: {"user": "testUser", "db": "test"}, $impersonatedRoles: [{"role": "readWrite", "db": "test"}] }; diff --git a/src/mongo/db/auth/impersonation_session.cpp b/src/mongo/db/auth/impersonation_session.cpp index 88742e20357..1cf9d790e06 100644 --- a/src/mongo/db/auth/impersonation_session.cpp +++ b/src/mongo/db/auth/impersonation_session.cpp @@ -55,9 +55,19 @@ ImpersonationSessionGuard::ImpersonationSessionGuard(OperationContext* opCtx) : authSession->isAuthorizedForPrivilege( Privilege(ResourcePattern::forClusterResource(), ActionType::impersonate))); fassert(ErrorCodes::InternalError, !authSession->isImpersonating()); - fassert(ErrorCodes::InternalError, impersonatedUsersAndRoles->getUsers().size() == 1); - authSession->setImpersonatedUserData(impersonatedUsersAndRoles->getUsers()[0], - impersonatedUsersAndRoles->getRoles()); + if (impersonatedUsersAndRoles->getUser()) { + fassert(ErrorCodes::InternalError, + impersonatedUsersAndRoles->getUsers() == boost::none); + + authSession->setImpersonatedUserData(impersonatedUsersAndRoles->getUser().get(), + impersonatedUsersAndRoles->getRoles()); + + } else if (impersonatedUsersAndRoles->getUsers()) { + // TODO SERVER-72448: Remove + fassert(ErrorCodes::InternalError, impersonatedUsersAndRoles->getUsers()->size() == 1); + authSession->setImpersonatedUserData(impersonatedUsersAndRoles->getUsers().get()[0], + impersonatedUsersAndRoles->getRoles()); + } _active = true; return; } diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp index 6e4b0798f18..825edbad7f1 100644 --- a/src/mongo/db/curop.cpp +++ b/src/mongo/db/curop.cpp @@ -217,8 +217,13 @@ void CurOp::reportCurrentOpForClient(OperationContext* opCtx, auto maybeImpersonationData = rpc::getImpersonatedUserMetadata(clientOpCtx); if (maybeImpersonationData) { BSONArrayBuilder users(infoBuilder->subarrayStart("effectiveUsers")); - for (const auto& user : maybeImpersonationData->getUsers()) { - user.serializeToBSON(&users); + + if (maybeImpersonationData->getUser()) { + maybeImpersonationData->getUser()->serializeToBSON(&users); + } else if (maybeImpersonationData->getUsers()) { + for (const auto& user : maybeImpersonationData->getUsers().get()) { + user.serializeToBSON(&users); + } } users.doneFast(); diff --git a/src/mongo/db/s/forwardable_operation_metadata.cpp b/src/mongo/db/s/forwardable_operation_metadata.cpp index 3b5ca272ca8..1ceba18777e 100644 --- a/src/mongo/db/s/forwardable_operation_metadata.cpp +++ b/src/mongo/db/s/forwardable_operation_metadata.cpp @@ -45,7 +45,17 @@ ForwardableOperationMetadata::ForwardableOperationMetadata(OperationContext* opC setComment(optComment->wrap()); } if (const auto authMetadata = rpc::getImpersonatedUserMetadata(opCtx)) { - setImpersonatedUserMetadata({{authMetadata->getUsers(), authMetadata->getRoles()}}); + if (authMetadata->getUser()) { + AuthenticationMetadata metadata; + metadata.setUser(authMetadata->getUser().get()); + metadata.setRoles(authMetadata->getRoles()); + setImpersonatedUserMetadata(metadata); + } else if (authMetadata->getUsers()) { + AuthenticationMetadata metadata; + metadata.setUsers(authMetadata->getUsers().get()); + metadata.setRoles(authMetadata->getRoles()); + setImpersonatedUserMetadata(metadata); + } } setMayBypassWriteBlocking(WriteBlockBypass::get(opCtx).isWriteBlockBypassEnabled()); @@ -60,10 +70,20 @@ void ForwardableOperationMetadata::setOn(OperationContext* opCtx) const { if (const auto& optAuthMetadata = getImpersonatedUserMetadata()) { const auto& authMetadata = optAuthMetadata.value(); - const auto& users = authMetadata.getUsers(); - if (!users.empty() || !authMetadata.getRoles().empty()) { - fassert(ErrorCodes::InternalError, users.size() == 1); - AuthorizationSession::get(client)->setImpersonatedUserData(users[0], + UserName username; + + if (authMetadata.getUser()) { + fassert(ErrorCodes::InternalError, authMetadata.getUsers() == boost::none); + + username = authMetadata.getUser().get(); + } else if (authMetadata.getUsers()) { + // TODO SERVER-72448: Remove + fassert(ErrorCodes::InternalError, authMetadata.getUsers()->size() == 1); + username = authMetadata.getUsers().get()[0]; + } + + if (!authMetadata.getRoles().empty()) { + AuthorizationSession::get(client)->setImpersonatedUserData(username, authMetadata.getRoles()); } } diff --git a/src/mongo/db/s/forwardable_operation_metadata.idl b/src/mongo/db/s/forwardable_operation_metadata.idl index e914f051ee9..0ebcfad9c1b 100644 --- a/src/mongo/db/s/forwardable_operation_metadata.idl +++ b/src/mongo/db/s/forwardable_operation_metadata.idl @@ -44,6 +44,10 @@ structs: fields: users: type: array<UserName> + optional: true + user: + type: UserName + optional: true roles: type: array<RoleName> diff --git a/src/mongo/rpc/metadata/impersonated_user_metadata.cpp b/src/mongo/rpc/metadata/impersonated_user_metadata.cpp index 7fecbe88eb3..9ff13f97c95 100644 --- a/src/mongo/rpc/metadata/impersonated_user_metadata.cpp +++ b/src/mongo/rpc/metadata/impersonated_user_metadata.cpp @@ -58,13 +58,12 @@ void readImpersonatedUserMetadata(const BSONElement& elem, OperationContext* opC IDLParserContext errCtx(kImpersonationMetadataSectionName); auto data = ImpersonatedUserMetadata::parse(errCtx, elem.embeddedObject()); - uassert(ErrorCodes::BadValue, - "Impersonating multiple users is not supported", - data.getUsers().size() <= 1); + // TODO SERVER-72448: Remove the getUsers() pathway + const bool userExists = data.getUser() || (data.getUsers() && !data.getUsers()->empty()); // Set the impersonation data only if there are actually impersonated // users/roles. - if ((!data.getUsers().empty()) || (!data.getRoles().empty())) { + if (userExists || !data.getRoles().empty()) { newData = std::move(data); } } @@ -92,11 +91,19 @@ void writeAuthDataToImpersonatedUserMetadata(OperationContext* opCtx, BSONObjBui } ImpersonatedUserMetadata metadata; - if (userName) { - metadata.setUsers({userName.value()}); + if (serverGlobalParams.featureCompatibility.isLessThanOrEqualTo( + multiversion::FeatureCompatibilityVersion::kVersion_6_2)) { + if (userName) { + metadata.setUsers({{userName.value()}}); + } else { + metadata.setUsers({}); + } } else { - metadata.setUsers({}); + if (userName) { + metadata.setUser(userName.value()); + } } + metadata.setRoles(roleNameIteratorToContainer<std::vector<RoleName>>(roleNames)); BSONObjBuilder section(out->subobjStart(kImpersonationMetadataSectionName)); diff --git a/src/mongo/rpc/metadata/impersonated_user_metadata.idl b/src/mongo/rpc/metadata/impersonated_user_metadata.idl index bbd969eeb3e..066024fb437 100644 --- a/src/mongo/rpc/metadata/impersonated_user_metadata.idl +++ b/src/mongo/rpc/metadata/impersonated_user_metadata.idl @@ -42,6 +42,11 @@ structs: "$impersonatedUsers": type: array<UserName> cpp_name: "users" + optional: true + "$impersonatedUser": + type: UserName + cpp_name: "user" + optional: true "$impersonatedRoles": type: array<RoleName> cpp_name: "roles" |