summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSpencer Jackson <spencer.jackson@mongodb.com>2017-09-27 16:06:45 -0400
committerSpencer Jackson <spencer.jackson@mongodb.com>2017-09-29 11:54:59 -0400
commitfb4b207cddb61a9b1c5e010be693ba41156e7f58 (patch)
treea9a0fc28e23976c2184fe69c0b35252cd4f73410 /src
parent2fc2b3fbde6adbeb43a7b8df70e26000cedf01d5 (diff)
downloadmongo-fb4b207cddb61a9b1c5e010be693ba41156e7f58.tar.gz
SERVER-31248: Use of UUID in command requires privilege
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/auth/action_types.txt1
-rw-r--r--src/mongo/db/auth/authorization_session.cpp15
-rw-r--r--src/mongo/db/auth/authorization_session.h4
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp29
-rw-r--r--src/mongo/db/auth/role_graph_builtin_roles.cpp3
-rw-r--r--src/mongo/db/commands/count_cmd.cpp22
-rw-r--r--src/mongo/db/commands/find_cmd.cpp15
-rw-r--r--src/mongo/db/commands/list_indexes.cpp4
-rw-r--r--src/mongo/db/commands/parallel_collection_scan.cpp24
9 files changed, 96 insertions, 21 deletions
diff --git a/src/mongo/db/auth/action_types.txt b/src/mongo/db/auth/action_types.txt
index 1f57ba6084b..88d777a4950 100644
--- a/src/mongo/db/auth/action_types.txt
+++ b/src/mongo/db/auth/action_types.txt
@@ -106,6 +106,7 @@
"top",
"touch",
"unlock",
+"useUUID",
"update",
"updateRole", # Not used for permissions checks, but to id the event in logs.
"updateUser", # Not used for permissions checks, but to id the event in logs.
diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp
index 023d5fc02a7..15ee3480a88 100644
--- a/src/mongo/db/auth/authorization_session.cpp
+++ b/src/mongo/db/auth/authorization_session.cpp
@@ -601,6 +601,21 @@ Status AuthorizationSession::checkAuthorizedToRevokePrivilege(const Privilege& p
return Status::OK();
}
+bool AuthorizationSession::isAuthorizedToParseNamespaceElement(const BSONElement& element) {
+ const bool isUUID = element.type() == BinData && element.binDataType() == BinDataType::newUUID;
+
+ uassert(ErrorCodes::InvalidNamespace,
+ "Failed to parse namespace element",
+ element.type() == String || isUUID);
+
+ if (isUUID) {
+ return isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
+ ActionType::useUUID);
+ }
+
+ return true;
+}
+
bool AuthorizationSession::isAuthorizedToCreateRole(
const struct auth::CreateOrUpdateRoleArgs& args) {
// A user is allowed to create a role under either of two conditions.
diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h
index 1f41180df18..a1e159c80de 100644
--- a/src/mongo/db/auth/authorization_session.h
+++ b/src/mongo/db/auth/authorization_session.h
@@ -227,6 +227,10 @@ public:
// Checks if this connection is using the localhost bypass
bool isUsingLocalhostBypass();
+ // Checks if this connection has the privileges necessary to parse a namespace from a
+ // given BSONElement.
+ bool isAuthorizedToParseNamespaceElement(const BSONElement& elem);
+
// Checks if this connection has the privileges necessary to create a new role
bool isAuthorizedToCreateRole(const auth::CreateOrUpdateRoleArgs& args);
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp
index 308156c31ee..0ec66e94598 100644
--- a/src/mongo/db/auth/authorization_session_test.cpp
+++ b/src/mongo/db/auth/authorization_session_test.cpp
@@ -1278,5 +1278,34 @@ TEST_F(AuthorizationSessionTest, CanListCollectionsWithListCollectionsPrivilege)
ASSERT_TRUE(authzSession->isAuthorizedToListCollections(testQuxNss.db()));
}
+TEST_F(AuthorizationSessionTest, CanUseUUIDNamespacesWithPrivilege) {
+ BSONObj stringObj = BSON("a"
+ << "string");
+ BSONObj uuidObj = BSON("a" << UUID::gen());
+ BSONObj invalidObj = BSON("a" << 12);
+
+ // Strings require no privileges
+ ASSERT_TRUE(authzSession->isAuthorizedToParseNamespaceElement(stringObj.firstElement()));
+
+ // UUIDs cannot be parsed with default privileges
+ ASSERT_FALSE(authzSession->isAuthorizedToParseNamespaceElement(uuidObj.firstElement()));
+
+ // Element must be either a string, or a UUID
+ ASSERT_THROWS_CODE(authzSession->isAuthorizedToParseNamespaceElement(invalidObj.firstElement()),
+ AssertionException,
+ ErrorCodes::InvalidNamespace);
+
+ // The useUUID privilege allows UUIDs to be parsed
+ authzSession->assumePrivilegesForDB(
+ Privilege(ResourcePattern::forClusterResource(), {ActionType::useUUID}));
+
+ ASSERT_TRUE(authzSession->isAuthorizedToParseNamespaceElement(stringObj.firstElement()));
+ ASSERT_TRUE(authzSession->isAuthorizedToParseNamespaceElement(uuidObj.firstElement()));
+ ASSERT_THROWS_CODE(authzSession->isAuthorizedToParseNamespaceElement(invalidObj.firstElement()),
+ AssertionException,
+ ErrorCodes::InvalidNamespace);
+}
+
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/db/auth/role_graph_builtin_roles.cpp b/src/mongo/db/auth/role_graph_builtin_roles.cpp
index 31e8e1234ec..94b14014549 100644
--- a/src/mongo/db/auth/role_graph_builtin_roles.cpp
+++ b/src/mongo/db/auth/role_graph_builtin_roles.cpp
@@ -194,6 +194,7 @@ MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) {
<< ActionType::replSetGetStatus // clusterManager gets this also
<< ActionType::serverStatus
<< ActionType::top
+ << ActionType::useUUID
<< ActionType::inprog
<< ActionType::shardingState;
@@ -499,7 +500,7 @@ void addQueryableBackupPrivileges(PrivilegeVector* privileges) {
ActionSet clusterActions;
clusterActions << ActionType::getParameter // To check authSchemaVersion
- << ActionType::listDatabases;
+ << ActionType::listDatabases << ActionType::useUUID;
Privilege::addPrivilegeToPrivilegeVector(
privileges, Privilege(ResourcePattern::forClusterResource(), clusterActions));
diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp
index 9ce6c54675e..d70c9ce6c80 100644
--- a/src/mongo/db/commands/count_cmd.cpp
+++ b/src/mongo/db/commands/count_cmd.cpp
@@ -30,6 +30,7 @@
#include "mongo/platform/basic.h"
+#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
#include "mongo/db/commands/run_aggregate.h"
@@ -91,12 +92,21 @@ public:
help << "count objects in collection";
}
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) {
- ActionSet actions;
- actions.addAction(ActionType::find);
- out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions));
+ Status checkAuthForOperation(OperationContext* opCtx,
+ const std::string& dbname,
+ const BSONObj& cmdObj) override {
+ AuthorizationSession* authSession = AuthorizationSession::get(opCtx->getClient());
+
+ if (!authSession->isAuthorizedToParseNamespaceElement(cmdObj.firstElement())) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+
+ const NamespaceString nss(parseNsOrUUID(opCtx, dbname, cmdObj));
+ if (!authSession->isAuthorizedForActionsOnNamespace(nss, ActionType::find)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+
+ return Status::OK();
}
virtual Status explain(OperationContext* opCtx,
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index cbe0ce20d55..d3d9aafc096 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -123,12 +123,17 @@ public:
return false;
}
- Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) override {
- const NamespaceString nss(parseNs(dbname, cmdObj));
+ Status checkAuthForOperation(OperationContext* opCtx,
+ const std::string& dbname,
+ const BSONObj& cmdObj) override {
+ AuthorizationSession* authSession = AuthorizationSession::get(opCtx->getClient());
+
+ if (!authSession->isAuthorizedToParseNamespaceElement(cmdObj.firstElement())) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+ const NamespaceString nss(parseNsOrUUID(opCtx, dbname, cmdObj));
auto hasTerm = cmdObj.hasField(kTermField);
- return AuthorizationSession::get(client)->checkAuthForFind(nss, hasTerm);
+ return authSession->checkAuthForFind(nss, hasTerm);
}
Status explain(OperationContext* opCtx,
diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp
index 75d79099c39..d4e77888247 100644
--- a/src/mongo/db/commands/list_indexes.cpp
+++ b/src/mongo/db/commands/list_indexes.cpp
@@ -98,6 +98,10 @@ public:
const BSONObj& cmdObj) {
AuthorizationSession* authzSession = AuthorizationSession::get(client);
+ if (!authzSession->isAuthorizedToParseNamespaceElement(cmdObj.firstElement())) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+
// Check for the listIndexes ActionType on the database, or find on system.indexes for pre
// 3.0 systems.
const NamespaceString ns(parseNsOrUUID(client->getOperationContext(), dbname, cmdObj));
diff --git a/src/mongo/db/commands/parallel_collection_scan.cpp b/src/mongo/db/commands/parallel_collection_scan.cpp
index 6b84996369c..533daa6ab94 100644
--- a/src/mongo/db/commands/parallel_collection_scan.cpp
+++ b/src/mongo/db/commands/parallel_collection_scan.cpp
@@ -74,15 +74,21 @@ public:
return ReadWriteType::kCommand;
}
- virtual Status checkAuthForCommand(Client* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
- ActionSet actions;
- actions.addAction(ActionType::find);
- Privilege p(parseResourcePattern(dbname, cmdObj), actions);
- if (AuthorizationSession::get(client)->isAuthorizedForPrivilege(p))
- return Status::OK();
- return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ Status checkAuthForOperation(OperationContext* opCtx,
+ const std::string& dbname,
+ const BSONObj& cmdObj) override {
+ AuthorizationSession* authSession = AuthorizationSession::get(opCtx->getClient());
+
+ if (!authSession->isAuthorizedToParseNamespaceElement(cmdObj.firstElement())) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+
+ const NamespaceString ns(parseNsOrUUID(opCtx, dbname, cmdObj));
+ if (!authSession->isAuthorizedForActionsOnNamespace(ns, ActionType::find)) {
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+
+ return Status::OK();
}
virtual bool run(OperationContext* opCtx,