|
62 | 62 | #include "mongo/db/operation_context.h" |
63 | 63 | #include "mongo/db/service_context.h" |
64 | 64 | #include "mongo/platform/unordered_set.h" |
| 65 | +#include "mongo/rpc/protocol.h" |
65 | 66 | #include "mongo/stdx/functional.h" |
66 | 67 | #include "mongo/stdx/mutex.h" |
67 | 68 | #include "mongo/util/log.h" |
@@ -1209,6 +1210,9 @@ class CmdUsersInfo : public Command { |
1209 | 1210 | if (!status.isOK()) { |
1210 | 1211 | return appendCommandStatus(result, status); |
1211 | 1212 | } |
| 1213 | + |
| 1214 | + userDetails = _redactPrivilegesForBackwardsCompabilityIfNeeded(txn, userDetails); |
| 1215 | + |
1212 | 1216 | if (!args.showCredentials) { |
1213 | 1217 | // getUserDescription always includes credentials, need to strip it out |
1214 | 1218 | BSONObjBuilder userWithoutCredentials(usersArrayBuilder.subobjStart()); |
@@ -1254,6 +1258,48 @@ class CmdUsersInfo : public Command { |
1254 | 1258 | return true; |
1255 | 1259 | } |
1256 | 1260 |
|
| 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 | + } |
1257 | 1303 | } cmdUsersInfo; |
1258 | 1304 |
|
1259 | 1305 | class CmdCreateRole : public Command { |
|
0 commit comments