diff options
-rw-r--r-- | src/mongo/db/auth/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_local.cpp | 22 | ||||
-rw-r--r-- | src/mongo/db/auth/authz_manager_external_state_local.h | 15 | ||||
-rw-r--r-- | src/mongo/db/commands/user_management_commands.cpp | 46 |
4 files changed, 49 insertions, 35 deletions
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index fc535d9033f..f8935e8d588 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -38,7 +38,6 @@ env.Library('authcore', ['action_set.cpp', '$BUILD_DIR/mongo/db/common', '$BUILD_DIR/mongo/db/ops/update_driver', '$BUILD_DIR/mongo/db/namespace_string', - '$BUILD_DIR/mongo/rpc/protocol', '$BUILD_DIR/mongo/util/md5']) env.Library('authcommon', diff --git a/src/mongo/db/auth/authz_manager_external_state_local.cpp b/src/mongo/db/auth/authz_manager_external_state_local.cpp index 10576b5380f..674a06cfb6b 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp @@ -37,7 +37,6 @@ #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/user_document_parser.h" #include "mongo/db/operation_context.h" -#include "mongo/rpc/protocol.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" @@ -157,14 +156,13 @@ Status AuthzManagerExternalStateLocal::getUserDescription(OperationContext* txn, return status; mutablebson::Document resultDoc(*result, mutablebson::Document::kInPlaceDisabled); - _resolveUserRoles(txn, &resultDoc, directRoles); + _resolveUserRoles(&resultDoc, directRoles); *result = resultDoc.getObject(); return Status::OK(); } -void AuthzManagerExternalStateLocal::_resolveUserRoles(OperationContext* txn, - mutablebson::Document* userDoc, +void AuthzManagerExternalStateLocal::_resolveUserRoles(mutablebson::Document* userDoc, const std::vector<RoleName>& directRoles) { unordered_set<RoleName> indirectRoles; PrivilegeVector allPrivileges; @@ -194,8 +192,6 @@ void AuthzManagerExternalStateLocal::_resolveUserRoles(OperationContext* txn, } } - _redactPrivilegesForBackwardsCompatibilityIfNeeded(txn, &allPrivileges); - mutablebson::Element inheritedRolesElement = userDoc->makeElementArray("inheritedRoles"); mutablebson::Element privilegesElement = userDoc->makeElementArray("inheritedPrivileges"); mutablebson::Element warningsElement = userDoc->makeElementArray("warnings"); @@ -214,20 +210,6 @@ void AuthzManagerExternalStateLocal::_resolveUserRoles(OperationContext* txn, } } -void AuthzManagerExternalStateLocal::_redactPrivilegesForBackwardsCompatibilityIfNeeded( - OperationContext* txn, PrivilegeVector* privileges) { - auto protocol = rpc::getOperationProtocol(txn); - if (protocol == rpc::Protocol::kOpCommandV1) { - return; - } - - for (auto& privilege : *privileges) { - ActionSet toRedact; - toRedact.addAction(ActionType::bypassDocumentValidation); - privilege.removeActions(toRedact); - } -} - Status AuthzManagerExternalStateLocal::_getUserDocument(OperationContext* txn, const UserName& userName, BSONObj* userDoc) { diff --git a/src/mongo/db/auth/authz_manager_external_state_local.h b/src/mongo/db/auth/authz_manager_external_state_local.h index 2a43cacd630..954374cf961 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.h +++ b/src/mongo/db/auth/authz_manager_external_state_local.h @@ -131,23 +131,10 @@ private: * resolve roles and add the 'inheritedRoles', 'inheritedPrivileges', * and 'warnings' fields. */ - void _resolveUserRoles(OperationContext* txn, - mutablebson::Document* userDoc, + void _resolveUserRoles(mutablebson::Document* userDoc, const std::vector<RoleName>& directRoles); /** - * Gets the Protocol from 'txn' of the operation being run to determine if it was from - * OP_COMMAND or OP_QUERY. If OP_COMMAND, does nothing. If OP_QUERY, assumes that means it is - * a 3.0 mongos talking to us, and modifies the input PrivilegeVector to remove all references - * to any ActionTypes that didn't exist 3.0. This is because when a 3.0 mongos parses the - * privileges from a user document at authentication time, it skips any privileges containing - * any actions it doesn't know about. See SERVER-2146 for more details. - * TODO(SERVER-21561): Remove this after 3.2 - */ - void _redactPrivilegesForBackwardsCompatibilityIfNeeded(OperationContext* txn, - PrivilegeVector* privileges); - - /** * Eventually consistent, in-memory representation of all roles in the system (both * user-defined and built-in). Synchronized via _roleGraphMutex. */ diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp index 30387107ff4..9a48de6d74e 100644 --- a/src/mongo/db/commands/user_management_commands.cpp +++ b/src/mongo/db/commands/user_management_commands.cpp @@ -62,6 +62,7 @@ #include "mongo/db/operation_context.h" #include "mongo/db/service_context.h" #include "mongo/platform/unordered_set.h" +#include "mongo/rpc/protocol.h" #include "mongo/stdx/functional.h" #include "mongo/stdx/mutex.h" #include "mongo/util/log.h" @@ -1209,6 +1210,9 @@ public: if (!status.isOK()) { return appendCommandStatus(result, status); } + + userDetails = _redactPrivilegesForBackwardsCompabilityIfNeeded(txn, userDetails); + if (!args.showCredentials) { // getUserDescription always includes credentials, need to strip it out BSONObjBuilder userWithoutCredentials(usersArrayBuilder.subobjStart()); @@ -1254,6 +1258,48 @@ public: return true; } +private: + /** + * Gets the Protocol from 'txn' of the operation being run to determine if it was from + * OP_COMMAND or OP_QUERY. If OP_COMMAND, returns the input user document unmodified. + * If OP_QUERY, assumes that means it is a 3.0 mongos talking to us, and returns a modified + * version of the input user doc, with all privileges containing the 'bypassDocumentValidation' + * modified to remove that action. This is because when a 3.0 mongos parses the privileges from + * a user document at authentication time, it skips any privileges containing any actions it + * doesn't know about, and 'bypassDocumentValidation' was added for 3.2 so a 3.0 mongos will not + * recognize it. + * NOTE: This means that if a user connects directly to mongod with a driver that doesn't use + * OP_COMMAND and runs usersInfo with 'showPrivileges':true, they won't see any privileges + * containing 'bypassDocumentValidation', even if the user in question actually does possess + * that action. + * See SERVER-21486 and SERVER-21659 for more details. + * TODO(SERVER-21561): Remove this after 3.2 + */ + BSONObj _redactPrivilegesForBackwardsCompabilityIfNeeded(OperationContext* txn, + BSONObj userDoc) { + if (rpc::getOperationProtocol(txn) != rpc::Protocol::kOpQuery) { + return userDoc; + } + + namespace mmb = mutablebson; + bool changed = false; + mmb::Document redacted(userDoc, mmb::Document::kInPlaceDisabled); + mmb::Element privilegesArray = + mmb::findFirstChildNamed(redacted.root(), "inheritedPrivileges"); + for (auto privilegeElement = privilegesArray.leftChild(); privilegeElement.ok(); + privilegeElement = privilegeElement.rightSibling()) { + auto actionsArray = mmb::findFirstChildNamed(privilegeElement, "actions"); + for (auto actionElement = actionsArray.leftChild(); actionElement.ok();) { + auto nextActionElement = actionElement.rightSibling(); + if (actionElement.getValueString() == "bypassDocumentValidation") { + invariantOK(actionElement.remove()); + changed = true; + } + actionElement = nextActionElement; + } + } + return changed ? redacted.getObject().getOwned() : userDoc; + } } cmdUsersInfo; class CmdCreateRole : public Command { |