diff options
Diffstat (limited to 'src/mongo/s/query')
-rw-r--r-- | src/mongo/s/query/async_results_merger_test.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_client_cursor.h | 6 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_client_cursor_impl.cpp | 5 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_client_cursor_impl.h | 2 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_client_cursor_impl_test.cpp | 8 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_client_cursor_mock.cpp | 8 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_client_cursor_mock.h | 2 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_client_cursor_params.h | 25 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_cursor_manager.cpp | 5 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_cursor_manager.h | 6 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_find.cpp | 16 | ||||
-rw-r--r-- | src/mongo/s/query/store_possible_cursor.cpp | 5 |
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()); |