summaryrefslogtreecommitdiff
path: root/src/mongo/s/query
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/s/query')
-rw-r--r--src/mongo/s/query/async_results_merger_test.cpp4
-rw-r--r--src/mongo/s/query/cluster_client_cursor.h6
-rw-r--r--src/mongo/s/query/cluster_client_cursor_impl.cpp5
-rw-r--r--src/mongo/s/query/cluster_client_cursor_impl.h2
-rw-r--r--src/mongo/s/query/cluster_client_cursor_impl_test.cpp8
-rw-r--r--src/mongo/s/query/cluster_client_cursor_mock.cpp8
-rw-r--r--src/mongo/s/query/cluster_client_cursor_mock.h2
-rw-r--r--src/mongo/s/query/cluster_client_cursor_params.h25
-rw-r--r--src/mongo/s/query/cluster_cursor_manager.cpp5
-rw-r--r--src/mongo/s/query/cluster_cursor_manager.h6
-rw-r--r--src/mongo/s/query/cluster_find.cpp16
-rw-r--r--src/mongo/s/query/store_possible_cursor.cpp5
12 files changed, 75 insertions, 17 deletions
diff --git a/src/mongo/s/query/async_results_merger_test.cpp b/src/mongo/s/query/async_results_merger_test.cpp
index f61cf89f969..0dc06aaa5bd 100644
--- a/src/mongo/s/query/async_results_merger_test.cpp
+++ b/src/mongo/s/query/async_results_merger_test.cpp
@@ -120,7 +120,7 @@ protected:
const auto qr =
unittest::assertGet(QueryRequest::makeFromFindCommand(_nss, findCmd, isExplain));
- _params = stdx::make_unique<ClusterClientCursorParams>(_nss, readPref);
+ _params = stdx::make_unique<ClusterClientCursorParams>(_nss, UserNameIterator(), readPref);
_params->sort = qr->getSort();
_params->limit = qr->getLimit();
_params->batchSize = getMoreBatchSize ? getMoreBatchSize : qr->getBatchSize();
@@ -142,7 +142,7 @@ protected:
*/
void makeCursorFromExistingCursors(
const std::vector<std::pair<HostAndPort, CursorId>>& remotes) {
- _params = stdx::make_unique<ClusterClientCursorParams>(_nss);
+ _params = stdx::make_unique<ClusterClientCursorParams>(_nss, UserNameIterator());
for (const auto& hostIdPair : remotes) {
_params->remotes.emplace_back(hostIdPair.first, hostIdPair.second);
diff --git a/src/mongo/s/query/cluster_client_cursor.h b/src/mongo/s/query/cluster_client_cursor.h
index bd34689e62f..45d5d76a147 100644
--- a/src/mongo/s/query/cluster_client_cursor.h
+++ b/src/mongo/s/query/cluster_client_cursor.h
@@ -30,6 +30,7 @@
#include <boost/optional.hpp>
+#include "mongo/db/auth/user_name.h"
#include "mongo/db/jsobj.h"
#include "mongo/s/query/cluster_query_result.h"
#include "mongo/util/time_support.h"
@@ -80,6 +81,11 @@ public:
virtual bool isTailable() const = 0;
/**
+ * Returns the set of authenticated users when this cursor was created.
+ */
+ virtual UserNameIterator getAuthenticatedUsers() const = 0;
+
+ /**
* Returns the view definition associated with this cursor, if any.
*/
virtual boost::optional<BSONObj> viewDefinition() const = 0;
diff --git a/src/mongo/s/query/cluster_client_cursor_impl.cpp b/src/mongo/s/query/cluster_client_cursor_impl.cpp
index 24ffc0b220a..dec40936d7c 100644
--- a/src/mongo/s/query/cluster_client_cursor_impl.cpp
+++ b/src/mongo/s/query/cluster_client_cursor_impl.cpp
@@ -99,6 +99,11 @@ bool ClusterClientCursorImpl::isTailable() const {
return _params.isTailable;
}
+UserNameIterator ClusterClientCursorImpl::getAuthenticatedUsers() const {
+ return makeUserNameIterator(_params.authenticatedUsers.begin(),
+ _params.authenticatedUsers.end());
+}
+
boost::optional<BSONObj> ClusterClientCursorImpl::viewDefinition() const {
return _params.viewDefinition;
}
diff --git a/src/mongo/s/query/cluster_client_cursor_impl.h b/src/mongo/s/query/cluster_client_cursor_impl.h
index de4e09d0950..27b31dba14c 100644
--- a/src/mongo/s/query/cluster_client_cursor_impl.h
+++ b/src/mongo/s/query/cluster_client_cursor_impl.h
@@ -101,6 +101,8 @@ public:
bool isTailable() const final;
+ UserNameIterator getAuthenticatedUsers() const final;
+
boost::optional<BSONObj> viewDefinition() const final;
long long getNumReturnedSoFar() const final;
diff --git a/src/mongo/s/query/cluster_client_cursor_impl_test.cpp b/src/mongo/s/query/cluster_client_cursor_impl_test.cpp
index f8356b9622f..188b8dbf112 100644
--- a/src/mongo/s/query/cluster_client_cursor_impl_test.cpp
+++ b/src/mongo/s/query/cluster_client_cursor_impl_test.cpp
@@ -51,7 +51,7 @@ TEST(ClusterClientCursorImpl, NumReturnedSoFar) {
}
ClusterClientCursorImpl cursor(std::move(mockStage),
- ClusterClientCursorParams(NamespaceString("unused")));
+ ClusterClientCursorParams(NamespaceString("unused"), {}));
ASSERT_EQ(cursor.getNumReturnedSoFar(), 0);
@@ -74,7 +74,7 @@ TEST(ClusterClientCursorImpl, QueueResult) {
mockStage->queueResult(BSON("a" << 4));
ClusterClientCursorImpl cursor(std::move(mockStage),
- ClusterClientCursorParams(NamespaceString("unused")));
+ ClusterClientCursorParams(NamespaceString("unused"), {}));
auto firstResult = cursor.next(nullptr);
ASSERT_OK(firstResult.getStatus());
@@ -113,7 +113,7 @@ TEST(ClusterClientCursorImpl, RemotesExhausted) {
mockStage->markRemotesExhausted();
ClusterClientCursorImpl cursor(std::move(mockStage),
- ClusterClientCursorParams(NamespaceString("unused")));
+ ClusterClientCursorParams(NamespaceString("unused"), {}));
ASSERT_TRUE(cursor.remotesExhausted());
auto firstResult = cursor.next(nullptr);
@@ -142,7 +142,7 @@ TEST(ClusterClientCursorImpl, ForwardsAwaitDataTimeout) {
ASSERT_NOT_OK(mockStage->getAwaitDataTimeout().getStatus());
ClusterClientCursorImpl cursor(std::move(mockStage),
- ClusterClientCursorParams(NamespaceString("unused")));
+ ClusterClientCursorParams(NamespaceString("unused"), {}));
ASSERT_OK(cursor.setAwaitDataTimeout(Milliseconds(789)));
auto awaitDataTimeout = mockStagePtr->getAwaitDataTimeout();
diff --git a/src/mongo/s/query/cluster_client_cursor_mock.cpp b/src/mongo/s/query/cluster_client_cursor_mock.cpp
index 28a4f2643f3..8b4d64f4d41 100644
--- a/src/mongo/s/query/cluster_client_cursor_mock.cpp
+++ b/src/mongo/s/query/cluster_client_cursor_mock.cpp
@@ -77,6 +77,14 @@ bool ClusterClientCursorMock::isTailable() const {
return false;
}
+namespace {
+const std::vector<UserName> emptyAuthenticatedUsers{};
+} // namespace
+
+UserNameIterator ClusterClientCursorMock::getAuthenticatedUsers() const {
+ return makeUserNameIterator(emptyAuthenticatedUsers.begin(), emptyAuthenticatedUsers.end());
+}
+
boost::optional<BSONObj> ClusterClientCursorMock::viewDefinition() const {
return boost::none;
}
diff --git a/src/mongo/s/query/cluster_client_cursor_mock.h b/src/mongo/s/query/cluster_client_cursor_mock.h
index baea6660535..23d857d59d6 100644
--- a/src/mongo/s/query/cluster_client_cursor_mock.h
+++ b/src/mongo/s/query/cluster_client_cursor_mock.h
@@ -49,6 +49,8 @@ public:
bool isTailable() const final;
+ UserNameIterator getAuthenticatedUsers() const final;
+
boost::optional<BSONObj> viewDefinition() const final;
long long getNumReturnedSoFar() const final;
diff --git a/src/mongo/s/query/cluster_client_cursor_params.h b/src/mongo/s/query/cluster_client_cursor_params.h
index bf7037f98e5..03db1e37194 100644
--- a/src/mongo/s/query/cluster_client_cursor_params.h
+++ b/src/mongo/s/query/cluster_client_cursor_params.h
@@ -34,6 +34,7 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/client/read_preference.h"
+#include "mongo/db/auth/user_name.h"
#include "mongo/db/cursor_id.h"
#include "mongo/db/namespace_string.h"
#include "mongo/s/client/shard.h"
@@ -91,21 +92,27 @@ struct ClusterClientCursorParams {
};
/**
- * Constructor used for cases where initial shard host targeting is necessary (i.e., we don't
+ * Read preference must be provided if initial shard host targeting is necessary (i.e., we don't
* know yet the remote cursor id).
*/
- ClusterClientCursorParams(NamespaceString nss, ReadPreferenceSetting readPref)
- : nsString(std::move(nss)), readPreference(std::move(readPref)) {}
-
- /**
- * Constructor used for cases, where the remote cursor ids are already known and no resolution
- * or retargeting needs to happen.
- */
- ClusterClientCursorParams(NamespaceString nss) : nsString(std::move(nss)) {}
+ ClusterClientCursorParams(NamespaceString nss,
+ UserNameIterator authenticatedUsersIter,
+ boost::optional<ReadPreferenceSetting> readPref = boost::none)
+ : nsString(std::move(nss)) {
+ while (authenticatedUsersIter.more()) {
+ authenticatedUsers.emplace_back(authenticatedUsersIter.next());
+ }
+ if (readPref) {
+ readPreference = std::move(readPref.get());
+ }
+ }
// Namespace against which to query.
NamespaceString nsString;
+ // The set of authenticated users when this cursor was created.
+ std::vector<UserName> authenticatedUsers;
+
// Per-remote node data.
std::vector<Remote> remotes;
diff --git a/src/mongo/s/query/cluster_cursor_manager.cpp b/src/mongo/s/query/cluster_cursor_manager.cpp
index 85d396490c6..abb5513cdd8 100644
--- a/src/mongo/s/query/cluster_cursor_manager.cpp
+++ b/src/mongo/s/query/cluster_cursor_manager.cpp
@@ -120,6 +120,11 @@ bool ClusterCursorManager::PinnedCursor::isTailable() const {
return _cursor->isTailable();
}
+UserNameIterator ClusterCursorManager::PinnedCursor::getAuthenticatedUsers() const {
+ invariant(_cursor);
+ return _cursor->getAuthenticatedUsers();
+}
+
void ClusterCursorManager::PinnedCursor::returnCursor(CursorState cursorState) {
invariant(_cursor);
// Note that unpinning a cursor transfers ownership of the underlying ClusterClientCursor object
diff --git a/src/mongo/s/query/cluster_cursor_manager.h b/src/mongo/s/query/cluster_cursor_manager.h
index ad320452b3b..d71c6966ee7 100644
--- a/src/mongo/s/query/cluster_cursor_manager.h
+++ b/src/mongo/s/query/cluster_cursor_manager.h
@@ -163,6 +163,12 @@ public:
bool isTailable() const;
/**
+ * Returns the set of authenticated users when this cursor was created. Cannot be called
+ * after returnCursor() is called. A cursor must be owned.
+ */
+ UserNameIterator getAuthenticatedUsers() const;
+
+ /**
* Transfers ownership of the underlying cursor back to the manager. A cursor must be
* owned, and a cursor will no longer be owned after this method completes.
*
diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp
index 3d4c384c506..a6dcf1de83e 100644
--- a/src/mongo/s/query/cluster_find.cpp
+++ b/src/mongo/s/query/cluster_find.cpp
@@ -39,6 +39,7 @@
#include "mongo/bson/util/bson_extract.h"
#include "mongo/client/connpool.h"
#include "mongo/client/read_preference.h"
+#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands.h"
#include "mongo/db/query/canonical_query.h"
#include "mongo/db/query/find_common.h"
@@ -179,7 +180,10 @@ StatusWith<CursorId> runQueryWithoutRetrying(OperationContext* opCtx,
}
}
- ClusterClientCursorParams params(query.nss(), readPref);
+ ClusterClientCursorParams params(
+ query.nss(),
+ AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(),
+ readPref);
params.limit = query.getQueryRequest().getLimit();
params.batchSize = query.getQueryRequest().getEffectiveBatchSize();
params.skip = query.getQueryRequest().getSkip();
@@ -381,6 +385,16 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx,
while (MONGO_FAIL_POINT(keepCursorPinnedDuringGetMore)) {
}
+ // A user can only call getMore on their own cursor. If there were multiple users authenticated
+ // when the cursor was created, then at least one of them must be authenticated in order to run
+ // getMore on the cursor.
+ if (!AuthorizationSession::get(opCtx->getClient())
+ ->isCoauthorizedWith(pinnedCursor.getValue().getAuthenticatedUsers())) {
+ return {ErrorCodes::Unauthorized,
+ str::stream() << "cursor id " << request.cursorid
+ << " was not created by the authenticated user"};
+ }
+
if (request.awaitDataTimeout) {
auto status = pinnedCursor.getValue().setAwaitDataTimeout(*request.awaitDataTimeout);
if (!status.isOK()) {
diff --git a/src/mongo/s/query/store_possible_cursor.cpp b/src/mongo/s/query/store_possible_cursor.cpp
index 8647871b6a7..4f53b2441bc 100644
--- a/src/mongo/s/query/store_possible_cursor.cpp
+++ b/src/mongo/s/query/store_possible_cursor.cpp
@@ -32,6 +32,7 @@
#include "mongo/base/status_with.h"
#include "mongo/bson/bsonobj.h"
+#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/query/cursor_response.h"
#include "mongo/s/query/cluster_client_cursor_impl.h"
#include "mongo/s/query/cluster_client_cursor_params.h"
@@ -58,7 +59,9 @@ StatusWith<BSONObj> storePossibleCursor(OperationContext* opCtx,
return cmdResult;
}
- ClusterClientCursorParams params(incomingCursorResponse.getValue().getNSS());
+ ClusterClientCursorParams params(
+ incomingCursorResponse.getValue().getNSS(),
+ AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames());
params.remotes.emplace_back(server, incomingCursorResponse.getValue().getCursorId());