summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer T Brody <spencer@mongodb.com>2015-11-18 17:07:50 -0500
committerSpencer T Brody <spencer@mongodb.com>2015-11-19 23:32:47 -0500
commit874fc812768718f015e81d6ce7bd2dab9ce14128 (patch)
tree073e256b8e5f6757155029e74358391d87274318
parent5b3257d526f8217e303609418da1769275f81d03 (diff)
downloadmongo-874fc812768718f015e81d6ce7bd2dab9ce14128.tar.gz
SERVER-21486 Redact bypassDocumentValidation from user privilege set when being talked to by a 3.0 mongos
-rw-r--r--src/mongo/db/auth/SConscript1
-rw-r--r--src/mongo/db/auth/action_types.txt2
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.cpp24
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.h29
-rw-r--r--src/mongo/db/dbcommands.cpp4
-rw-r--r--src/mongo/rpc/protocol.cpp13
-rw-r--r--src/mongo/rpc/protocol.h11
7 files changed, 73 insertions, 11 deletions
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<RoleName>& directRoles) {
+void AuthzManagerExternalStateLocal::_resolveUserRoles(OperationContext* txn,
+ mutablebson::Document* userDoc,
+ const std::vector<RoleName>& directRoles) {
unordered_set<RoleName> 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<RoleName>& 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<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/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<Client> 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<Protocol> operationProtocolDecoration =
+ OperationContext::declareDecoration<Protocol>();
+
} // namespace
+Protocol getOperationProtocol(OperationContext* txn) {
+ return operationProtocolDecoration(txn);
+}
+
+void setOperationProtocol(OperationContext* txn, Protocol protocol) {
+ operationProtocolDecoration(txn) = protocol;
+}
+
StatusWith<Protocol> 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 {
/**
@@ -77,6 +78,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.
*/
StatusWith<Protocol> negotiate(ProtocolSet fst, ProtocolSet snd);