Skip to content

Commit 16b5070

Browse files
committed
SERVER-21659 Move logic for redacting 'bypassDocumentValidation' privilege for backwards compatibility up to the usersInfo command
1 parent 909b13f commit 16b5070

File tree

4 files changed

+49
-35
lines changed

4 files changed

+49
-35
lines changed

src/mongo/db/auth/SConscript

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ env.Library('authcore', ['action_set.cpp',
3838
'$BUILD_DIR/mongo/db/common',
3939
'$BUILD_DIR/mongo/db/ops/update_driver',
4040
'$BUILD_DIR/mongo/db/namespace_string',
41-
'$BUILD_DIR/mongo/rpc/protocol',
4241
'$BUILD_DIR/mongo/util/md5'])
4342

4443
env.Library('authcommon',

src/mongo/db/auth/authz_manager_external_state_local.cpp

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
#include "mongo/db/auth/authorization_manager.h"
3838
#include "mongo/db/auth/user_document_parser.h"
3939
#include "mongo/db/operation_context.h"
40-
#include "mongo/rpc/protocol.h"
4140
#include "mongo/util/log.h"
4241
#include "mongo/util/mongoutils/str.h"
4342

@@ -157,14 +156,13 @@ Status AuthzManagerExternalStateLocal::getUserDescription(OperationContext* txn,
157156
return status;
158157

159158
mutablebson::Document resultDoc(*result, mutablebson::Document::kInPlaceDisabled);
160-
_resolveUserRoles(txn, &resultDoc, directRoles);
159+
_resolveUserRoles(&resultDoc, directRoles);
161160
*result = resultDoc.getObject();
162161

163162
return Status::OK();
164163
}
165164

166-
void AuthzManagerExternalStateLocal::_resolveUserRoles(OperationContext* txn,
167-
mutablebson::Document* userDoc,
165+
void AuthzManagerExternalStateLocal::_resolveUserRoles(mutablebson::Document* userDoc,
168166
const std::vector<RoleName>& directRoles) {
169167
unordered_set<RoleName> indirectRoles;
170168
PrivilegeVector allPrivileges;
@@ -194,8 +192,6 @@ void AuthzManagerExternalStateLocal::_resolveUserRoles(OperationContext* txn,
194192
}
195193
}
196194

197-
_redactPrivilegesForBackwardsCompatibilityIfNeeded(txn, &allPrivileges);
198-
199195
mutablebson::Element inheritedRolesElement = userDoc->makeElementArray("inheritedRoles");
200196
mutablebson::Element privilegesElement = userDoc->makeElementArray("inheritedPrivileges");
201197
mutablebson::Element warningsElement = userDoc->makeElementArray("warnings");
@@ -214,20 +210,6 @@ void AuthzManagerExternalStateLocal::_resolveUserRoles(OperationContext* txn,
214210
}
215211
}
216212

217-
void AuthzManagerExternalStateLocal::_redactPrivilegesForBackwardsCompatibilityIfNeeded(
218-
OperationContext* txn, PrivilegeVector* privileges) {
219-
auto protocol = rpc::getOperationProtocol(txn);
220-
if (protocol == rpc::Protocol::kOpCommandV1) {
221-
return;
222-
}
223-
224-
for (auto& privilege : *privileges) {
225-
ActionSet toRedact;
226-
toRedact.addAction(ActionType::bypassDocumentValidation);
227-
privilege.removeActions(toRedact);
228-
}
229-
}
230-
231213
Status AuthzManagerExternalStateLocal::_getUserDocument(OperationContext* txn,
232214
const UserName& userName,
233215
BSONObj* userDoc) {

src/mongo/db/auth/authz_manager_external_state_local.h

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -131,22 +131,9 @@ class AuthzManagerExternalStateLocal : public AuthzManagerExternalState {
131131
* resolve roles and add the 'inheritedRoles', 'inheritedPrivileges',
132132
* and 'warnings' fields.
133133
*/
134-
void _resolveUserRoles(OperationContext* txn,
135-
mutablebson::Document* userDoc,
134+
void _resolveUserRoles(mutablebson::Document* userDoc,
136135
const std::vector<RoleName>& directRoles);
137136

138-
/**
139-
* Gets the Protocol from 'txn' of the operation being run to determine if it was from
140-
* OP_COMMAND or OP_QUERY. If OP_COMMAND, does nothing. If OP_QUERY, assumes that means it is
141-
* a 3.0 mongos talking to us, and modifies the input PrivilegeVector to remove all references
142-
* to any ActionTypes that didn't exist 3.0. This is because when a 3.0 mongos parses the
143-
* privileges from a user document at authentication time, it skips any privileges containing
144-
* any actions it doesn't know about. See SERVER-2146 for more details.
145-
* TODO(SERVER-21561): Remove this after 3.2
146-
*/
147-
void _redactPrivilegesForBackwardsCompatibilityIfNeeded(OperationContext* txn,
148-
PrivilegeVector* privileges);
149-
150137
/**
151138
* Eventually consistent, in-memory representation of all roles in the system (both
152139
* user-defined and built-in). Synchronized via _roleGraphMutex.

src/mongo/db/commands/user_management_commands.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include "mongo/db/operation_context.h"
6363
#include "mongo/db/service_context.h"
6464
#include "mongo/platform/unordered_set.h"
65+
#include "mongo/rpc/protocol.h"
6566
#include "mongo/stdx/functional.h"
6667
#include "mongo/stdx/mutex.h"
6768
#include "mongo/util/log.h"
@@ -1209,6 +1210,9 @@ class CmdUsersInfo : public Command {
12091210
if (!status.isOK()) {
12101211
return appendCommandStatus(result, status);
12111212
}
1213+
1214+
userDetails = _redactPrivilegesForBackwardsCompabilityIfNeeded(txn, userDetails);
1215+
12121216
if (!args.showCredentials) {
12131217
// getUserDescription always includes credentials, need to strip it out
12141218
BSONObjBuilder userWithoutCredentials(usersArrayBuilder.subobjStart());
@@ -1254,6 +1258,48 @@ class CmdUsersInfo : public Command {
12541258
return true;
12551259
}
12561260

1261+
private:
1262+
/**
1263+
* Gets the Protocol from 'txn' of the operation being run to determine if it was from
1264+
* OP_COMMAND or OP_QUERY. If OP_COMMAND, returns the input user document unmodified.
1265+
* If OP_QUERY, assumes that means it is a 3.0 mongos talking to us, and returns a modified
1266+
* version of the input user doc, with all privileges containing the 'bypassDocumentValidation'
1267+
* modified to remove that action. This is because when a 3.0 mongos parses the privileges from
1268+
* a user document at authentication time, it skips any privileges containing any actions it
1269+
* doesn't know about, and 'bypassDocumentValidation' was added for 3.2 so a 3.0 mongos will not
1270+
* recognize it.
1271+
* NOTE: This means that if a user connects directly to mongod with a driver that doesn't use
1272+
* OP_COMMAND and runs usersInfo with 'showPrivileges':true, they won't see any privileges
1273+
* containing 'bypassDocumentValidation', even if the user in question actually does possess
1274+
* that action.
1275+
* See SERVER-21486 and SERVER-21659 for more details.
1276+
* TODO(SERVER-21561): Remove this after 3.2
1277+
*/
1278+
BSONObj _redactPrivilegesForBackwardsCompabilityIfNeeded(OperationContext* txn,
1279+
BSONObj userDoc) {
1280+
if (rpc::getOperationProtocol(txn) != rpc::Protocol::kOpQuery) {
1281+
return userDoc;
1282+
}
1283+
1284+
namespace mmb = mutablebson;
1285+
bool changed = false;
1286+
mmb::Document redacted(userDoc, mmb::Document::kInPlaceDisabled);
1287+
mmb::Element privilegesArray =
1288+
mmb::findFirstChildNamed(redacted.root(), "inheritedPrivileges");
1289+
for (auto privilegeElement = privilegesArray.leftChild(); privilegeElement.ok();
1290+
privilegeElement = privilegeElement.rightSibling()) {
1291+
auto actionsArray = mmb::findFirstChildNamed(privilegeElement, "actions");
1292+
for (auto actionElement = actionsArray.leftChild(); actionElement.ok();) {
1293+
auto nextActionElement = actionElement.rightSibling();
1294+
if (actionElement.getValueString() == "bypassDocumentValidation") {
1295+
invariantOK(actionElement.remove());
1296+
changed = true;
1297+
}
1298+
actionElement = nextActionElement;
1299+
}
1300+
}
1301+
return changed ? redacted.getObject().getOwned() : userDoc;
1302+
}
12571303
} cmdUsersInfo;
12581304

12591305
class CmdCreateRole : public Command {

0 commit comments

Comments
 (0)