summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShreyas Kalyan <shreyas.kalyan@mongodb.com>2022-12-07 14:56:40 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-01-06 18:44:41 +0000
commit0e907cfd675d2ecfd36b12f910aeea5ca30f042d (patch)
treea3f58b2bec75fd955dbf7b55f592db03a3275ee9
parent71450a64f946eff52daf0f76d743dbcd3254228f (diff)
downloadmongo-0e907cfd675d2ecfd36b12f910aeea5ca30f042d.tar.gz
SERVER-64029 Prohibit impersonating multiple users
-rw-r--r--jstests/auth/impersonation-deny.js12
-rw-r--r--jstests/noPassthrough/out_merge_on_secondary_metadata.js2
-rw-r--r--src/mongo/db/auth/impersonation_session.cpp16
-rw-r--r--src/mongo/db/curop.cpp9
-rw-r--r--src/mongo/db/s/forwardable_operation_metadata.cpp30
-rw-r--r--src/mongo/db/s/forwardable_operation_metadata.idl4
-rw-r--r--src/mongo/rpc/metadata/impersonated_user_metadata.cpp21
-rw-r--r--src/mongo/rpc/metadata/impersonated_user_metadata.idl5
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"