From 8630f685156c7515c59ce071e59d9d6ec200f2e4 Mon Sep 17 00:00:00 2001 From: Ian Boros Date: Mon, 29 Jan 2018 14:28:05 -0500 Subject: SERVER-32395 Make killCursors work against pinned cursors on mongos when auth is enabled --- src/mongo/s/query/cluster_cursor_manager.h | 71 +++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 17 deletions(-) (limited to 'src/mongo/s/query/cluster_cursor_manager.h') diff --git a/src/mongo/s/query/cluster_cursor_manager.h b/src/mongo/s/query/cluster_cursor_manager.h index 8357117099f..923e6914953 100644 --- a/src/mongo/s/query/cluster_cursor_manager.h +++ b/src/mongo/s/query/cluster_cursor_manager.h @@ -115,6 +115,11 @@ public: size_t cursorsPinned = 0; }; + // Represents a function that may be passed into a ClusterCursorManager method which checks + // whether the current client is authorized to perform the operation in question. The function + // will be passed the list of users authorized to use the cursor. + using AuthzCheckFn = std::function; + /** * PinnedCursor is a moveable, non-copyable class representing ownership of a cursor that has * been leased from a ClusterCursorManager. @@ -185,12 +190,6 @@ public: */ bool isTailableAndAwaitData() 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. @@ -299,7 +298,8 @@ public: std::unique_ptr cursor, const NamespaceString& nss, CursorType cursorType, - CursorLifetime cursorLifetime); + CursorLifetime cursorLifetime, + UserNameIterator authenticatedUsers); /** * Moves the given cursor to the 'pinned' state, and transfers ownership of the cursor to the @@ -310,6 +310,10 @@ public: * returns an error Status with code CursorInUse. If the given cursor is not registered or has * a pending kill, returns an error Status with code CursorNotFound. * + * 'authChecker' is function that will be called with the list of users authorized to use this + * cursor. This function should check whether the current client is also authorized to use this + * cursor, and if not, return an error status, which will cause checkOutCursor to fail. + * * This method updates the 'last active' time associated with the cursor to the current time. * * Does not block. @@ -318,8 +322,19 @@ public: StatusWith checkOutCursor(const NamespaceString& nss, CursorId cursorId, OperationContext* opCtx, + AuthzCheckFn authChecker, AuthCheck checkSessionAuth = kCheckSession); + /** + * This method will find the given cursor, and if it exists, call 'authChecker', passing the + * list of users authorized to use the cursor. Will propagate the return value of authChecker. + */ + Status checkAuthForKillCursors(OperationContext* opCtx, + const NamespaceString& nss, + CursorId cursorId, + AuthzCheckFn authChecker); + + /** * Informs the manager that the given cursor should be killed. The cursor need not necessarily * be in the 'idle' state, and the lifetime type of the cursor is ignored. @@ -462,12 +477,15 @@ private: CursorEntry(std::unique_ptr cursor, CursorType cursorType, CursorLifetime cursorLifetime, - Date_t lastActive) + Date_t lastActive, + UserNameIterator authenticatedUsersIter) : _cursor(std::move(cursor)), _cursorType(cursorType), _cursorLifetime(cursorLifetime), _lastActive(lastActive), - _lsid(_cursor->getLsid()) { + _lsid(_cursor->getLsid()), + _authenticatedUsers( + userNameIteratorToContainer>(authenticatedUsersIter)) { invariant(_cursor); } @@ -494,29 +512,38 @@ private: return _lastActive; } - bool isCursorOwned() const { - return static_cast(_cursor); - } - boost::optional getLsid() const { return _lsid; } /** - * Releases the cursor from this entry. If the cursor has already been released, returns - * null. + * Returns the cursor owned by this CursorEntry for an operation to use. Only one operation + * may use the cursor at a time, so callers should check that getOperationUsingCursor() + * returns null before using this function. Callers may pass nullptr, but only if the + * released cursor is going to be deleted. */ - std::unique_ptr releaseCursor() { + std::unique_ptr releaseCursor(OperationContext* opCtx) { + invariant(!_operationUsingCursor); + invariant(_cursor); + _operationUsingCursor = opCtx; return std::move(_cursor); } + OperationContext* getOperationUsingCursor() const { + return _operationUsingCursor; + } + /** - * Transfers ownership of the given released cursor back to this entry. + * Indicate that the cursor is no longer in use by an operation. Once this is called, + * another operation may check the cursor out. */ void returnCursor(std::unique_ptr cursor) { invariant(cursor); invariant(!_cursor); + invariant(_operationUsingCursor); + _cursor = std::move(cursor); + _operationUsingCursor = nullptr; } void setKillPending() { @@ -531,6 +558,10 @@ private: _lastActive = lastActive; } + UserNameIterator getAuthenticatedUsers() const { + return makeUserNameIterator(_authenticatedUsers.begin(), _authenticatedUsers.end()); + } + private: std::unique_ptr _cursor; bool _killPending = false; @@ -539,6 +570,12 @@ private: CursorLifetime _cursorLifetime = CursorLifetime::Mortal; Date_t _lastActive; boost::optional _lsid; + + // Current operation using the cursor. Non-null if the cursor is checked out. + OperationContext* _operationUsingCursor = nullptr; + + // The set of users authorized to use this cursor. + const std::vector _authenticatedUsers; }; /** -- cgit v1.2.1