From 874fc812768718f015e81d6ce7bd2dab9ce14128 Mon Sep 17 00:00:00 2001 From: Spencer T Brody Date: Wed, 18 Nov 2015 17:07:50 -0500 Subject: SERVER-21486 Redact bypassDocumentValidation from user privilege set when being talked to by a 3.0 mongos --- src/mongo/db/auth/SConscript | 1 + src/mongo/db/auth/action_types.txt | 2 +- .../db/auth/authz_manager_external_state_local.cpp | 24 +++++++++++++++--- .../db/auth/authz_manager_external_state_local.h | 29 ++++++++++++++++------ src/mongo/db/dbcommands.cpp | 4 +++ src/mongo/rpc/protocol.cpp | 13 ++++++++++ src/mongo/rpc/protocol.h | 11 ++++++++ 7 files changed, 73 insertions(+), 11 deletions(-) (limited to 'src/mongo') diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index f8935e8d588..fc535d9033f 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -38,6 +38,7 @@ 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/action_types.txt b/src/mongo/db/auth/action_types.txt index 2d55b878687..3c560ccf9b8 100644 --- a/src/mongo/db/auth/action_types.txt +++ b/src/mongo/db/auth/action_types.txt @@ -12,7 +12,7 @@ "authCheck", # Not used for permissions checks, but to id the authorization-checking event in logs. "authenticate", # Not used for permission checks, but to id authentication events in logs. "authSchemaUpgrade", -"bypassDocumentValidation", # For bypassDocumentValidation command option. +"bypassDocumentValidation", "changeCustomData", "changePassword", "changeOwnPassword", 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 449c1e9dbfe..10576b5380f 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp @@ -37,6 +37,7 @@ #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" @@ -156,14 +157,15 @@ Status AuthzManagerExternalStateLocal::getUserDescription(OperationContext* txn, return status; mutablebson::Document resultDoc(*result, mutablebson::Document::kInPlaceDisabled); - resolveUserRoles(&resultDoc, directRoles); + _resolveUserRoles(txn, &resultDoc, directRoles); *result = resultDoc.getObject(); return Status::OK(); } -void AuthzManagerExternalStateLocal::resolveUserRoles(mutablebson::Document* userDoc, - const std::vector& directRoles) { +void AuthzManagerExternalStateLocal::_resolveUserRoles(OperationContext* txn, + mutablebson::Document* userDoc, + const std::vector& directRoles) { unordered_set indirectRoles; PrivilegeVector allPrivileges; bool isRoleGraphInconsistent; @@ -192,6 +194,8 @@ void AuthzManagerExternalStateLocal::resolveUserRoles(mutablebson::Document* use } } + _redactPrivilegesForBackwardsCompatibilityIfNeeded(txn, &allPrivileges); + mutablebson::Element inheritedRolesElement = userDoc->makeElementArray("inheritedRoles"); mutablebson::Element privilegesElement = userDoc->makeElementArray("inheritedPrivileges"); mutablebson::Element warningsElement = userDoc->makeElementArray("warnings"); @@ -210,6 +214,20 @@ void AuthzManagerExternalStateLocal::resolveUserRoles(mutablebson::Document* use } } +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 536404dcd51..2a43cacd630 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.h +++ b/src/mongo/db/auth/authz_manager_external_state_local.h @@ -54,13 +54,6 @@ class AuthzManagerExternalStateLocal : public AuthzManagerExternalState { public: virtual ~AuthzManagerExternalStateLocal() = default; - /** - * Takes a user document, and processes it with the RoleGraph, in order to recursively - * resolve roles and add the 'inheritedRoles', 'inheritedPrivileges', - * and 'warnings' fields. - */ - void resolveUserRoles(mutablebson::Document* userDoc, const std::vector& directRoles); - virtual Status initialize(OperationContext* txn); virtual Status getStoredAuthorizationVersion(OperationContext* txn, int* outVersion); @@ -132,6 +125,28 @@ private: Status _getRoleDescription_inlock(const RoleName& roleName, bool showPrivileges, BSONObj* result); + + /** + * Takes a user document, and processes it with the RoleGraph, in order to recursively + * resolve roles and add the 'inheritedRoles', 'inheritedPrivileges', + * and 'warnings' fields. + */ + void _resolveUserRoles(OperationContext* txn, + mutablebson::Document* userDoc, + const std::vector& 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/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index 59af14b6faf..a40f44dd210 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -94,6 +94,7 @@ #include "mongo/rpc/metadata/config_server_metadata.h" #include "mongo/rpc/metadata/server_selection_metadata.h" #include "mongo/rpc/metadata/sharding_metadata.h" +#include "mongo/rpc/protocol.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/grid.h" #include "mongo/s/stale_exception.h" // for SendStaleConfigException @@ -1196,6 +1197,9 @@ void Command::execCommand(OperationContext* txn, stdx::lock_guard lk(*txn->getClient()); CurOp::get(txn)->setCommand_inlock(command); } + + rpc::setOperationProtocol(txn, request.getProtocol()); // SERVER-21485. Remove after 3.2 + // TODO: move this back to runCommands when mongos supports OperationContext // see SERVER-18515 for details. uassertStatusOK(rpc::readRequestMetadata(txn, request.getMetadata())); diff --git a/src/mongo/rpc/protocol.cpp b/src/mongo/rpc/protocol.cpp index 3c3cafb6479..040cceb4dd5 100644 --- a/src/mongo/rpc/protocol.cpp +++ b/src/mongo/rpc/protocol.cpp @@ -36,7 +36,9 @@ #include "mongo/base/string_data.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/db/jsobj.h" +#include "mongo/db/operation_context.h" #include "mongo/db/wire_version.h" +#include "mongo/util/decorable.h" #include "mongo/util/mongoutils/str.h" namespace mongo { @@ -54,8 +56,19 @@ const char kOpQueryOnly[] = "opQueryOnly"; const char kOpCommandOnly[] = "opCommandOnly"; const char kAll[] = "all"; +const OperationContext::Decoration operationProtocolDecoration = + OperationContext::declareDecoration(); + } // namespace +Protocol getOperationProtocol(OperationContext* txn) { + return operationProtocolDecoration(txn); +} + +void setOperationProtocol(OperationContext* txn, Protocol protocol) { + operationProtocolDecoration(txn) = protocol; +} + StatusWith negotiate(ProtocolSet fst, ProtocolSet snd) { using std::begin; using std::end; diff --git a/src/mongo/rpc/protocol.h b/src/mongo/rpc/protocol.h index 643351106e0..45280849c29 100644 --- a/src/mongo/rpc/protocol.h +++ b/src/mongo/rpc/protocol.h @@ -36,6 +36,7 @@ namespace mongo { class BSONObj; +class OperationContext; namespace rpc { /** @@ -76,6 +77,16 @@ const ProtocolSet kAll = kOpQueryOnly | kOpCommandOnly; } // namespace supports +/** + * Returns the protocol used to initiate the current operation. + */ +Protocol getOperationProtocol(OperationContext* txn); + +/** + * Sets the protocol used to initiate the current operation. + */ +void setOperationProtocol(OperationContext* txn, Protocol protocol); + /** * Returns the newest protocol supported by two parties. */ -- cgit v1.2.1