diff options
Diffstat (limited to 'src/mongo/db/auth')
27 files changed, 159 insertions, 122 deletions
diff --git a/src/mongo/db/auth/auth_index_d.cpp b/src/mongo/db/auth/auth_index_d.cpp index 2b510698b60..b8ed201226e 100644 --- a/src/mongo/db/auth/auth_index_d.cpp +++ b/src/mongo/db/auth/auth_index_d.cpp @@ -72,9 +72,10 @@ namespace { } // namespace - void configureSystemIndexes(const StringData& dbname) { + void configureSystemIndexes(OperationContext* txn, const StringData& dbname) { int authzVersion; - Status status = getGlobalAuthorizationManager()->getAuthorizationVersion(&authzVersion); + Status status = getGlobalAuthorizationManager()->getAuthorizationVersion( + txn, &authzVersion); if (!status.isOK()) { return; } @@ -83,8 +84,8 @@ namespace { NamespaceString systemUsers(dbname, "system.users"); // Make sure the old unique index from v2.4 on system.users doesn't exist. - Client::WriteContext wctx(systemUsers); OperationContextImpl txn; + Client::WriteContext wctx(&txn, systemUsers); Collection* collection = wctx.ctx().db()->getCollection(NamespaceString(systemUsers)); if (!collection) { return; diff --git a/src/mongo/db/auth/auth_index_d.h b/src/mongo/db/auth/auth_index_d.h index 3d3cf711e40..964eec9fbb0 100644 --- a/src/mongo/db/auth/auth_index_d.h +++ b/src/mongo/db/auth/auth_index_d.h @@ -50,7 +50,7 @@ namespace authindex { * It is appropriate to call this function on new or existing databases, though it is * primarily intended for use on existing databases. */ - void configureSystemIndexes(const StringData& dbname); + void configureSystemIndexes(OperationContext* txn, const StringData& dbname); } // namespace authindex } // namespace mongo diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp index c3466c922eb..cc60b795c0a 100644 --- a/src/mongo/db/auth/authorization_manager.cpp +++ b/src/mongo/db/auth/authorization_manager.cpp @@ -258,14 +258,14 @@ namespace mongo { } } - Status AuthorizationManager::getAuthorizationVersion(int* version) { + Status AuthorizationManager::getAuthorizationVersion(OperationContext* txn, int* version) { CacheGuard guard(this, CacheGuard::fetchSynchronizationManual); int newVersion = _version; if (schemaVersionInvalid == newVersion) { while (guard.otherUpdateInFetchPhase()) guard.wait(); guard.beginFetchPhase(); - Status status = _externalState->getStoredAuthorizationVersion(&newVersion); + Status status = _externalState->getStoredAuthorizationVersion(txn, &newVersion); guard.endFetchPhase(); if (!status.isOK()) { warning() << "Problem fetching the stored schema version of authorization data: " @@ -295,8 +295,8 @@ namespace mongo { return _authEnabled; } - bool AuthorizationManager::hasAnyPrivilegeDocuments() const { - return _externalState->hasAnyPrivilegeDocuments(); + bool AuthorizationManager::hasAnyPrivilegeDocuments(OperationContext* txn) const { + return _externalState->hasAnyPrivilegeDocuments(txn); } Status AuthorizationManager::writeAuthSchemaVersionIfNeeded() { @@ -493,8 +493,10 @@ namespace mongo { return Status::OK(); } - Status AuthorizationManager::getUserDescription(const UserName& userName, BSONObj* result) { - return _externalState->getUserDescription(userName, result); + Status AuthorizationManager::getUserDescription(OperationContext* txn, + const UserName& userName, + BSONObj* result) { + return _externalState->getUserDescription(txn, userName, result); } Status AuthorizationManager::getRoleDescription(const RoleName& roleName, @@ -513,7 +515,8 @@ namespace mongo { result); } - Status AuthorizationManager::acquireUser(const UserName& userName, User** acquiredUser) { + Status AuthorizationManager::acquireUser( + OperationContext* txn, const UserName& userName, User** acquiredUser) { if (userName == internalSecurity.user->getName()) { *acquiredUser = internalSecurity.user; return Status::OK(); @@ -549,7 +552,7 @@ namespace mongo { Status status = Status::OK(); for (int i = 0; i < maxAcquireRetries; ++i) { if (authzVersion == schemaVersionInvalid) { - Status status = _externalState->getStoredAuthorizationVersion(&authzVersion); + Status status = _externalState->getStoredAuthorizationVersion(txn, &authzVersion); if (!status.isOK()) return status; } @@ -562,7 +565,7 @@ namespace mongo { break; case schemaVersion26Final: case schemaVersion26Upgrade: - status = _fetchUserV2(userName, &user); + status = _fetchUserV2(txn, userName, &user); break; case schemaVersion24: status = Status(ErrorCodes::AuthSchemaIncompatible, mongoutils::str::stream() << @@ -600,10 +603,11 @@ namespace mongo { return Status::OK(); } - Status AuthorizationManager::_fetchUserV2(const UserName& userName, + Status AuthorizationManager::_fetchUserV2(OperationContext* txn, + const UserName& userName, std::auto_ptr<User>* acquiredUser) { BSONObj userObj; - Status status = getUserDescription(userName, &userObj); + Status status = getUserDescription(txn, userName, &userObj); if (!status.isOK()) { return status; } @@ -700,9 +704,10 @@ namespace mongo { return _externalState->releaseAuthzUpdateLock(); } - Status AuthorizationManager::upgradeSchemaStep(const BSONObj& writeConcern, bool* isDone) { + Status AuthorizationManager::upgradeSchemaStep( + OperationContext* txn, const BSONObj& writeConcern, bool* isDone) { int authzVersion; - Status status = getAuthorizationVersion(&authzVersion); + Status status = getAuthorizationVersion(txn, &authzVersion); if (!status.isOK()) { return status; } @@ -717,7 +722,8 @@ namespace mongo { } } - Status AuthorizationManager::upgradeSchema(int maxSteps, const BSONObj& writeConcern) { + Status AuthorizationManager::upgradeSchema( + OperationContext* txn, int maxSteps, const BSONObj& writeConcern) { if (maxSteps < 1) { return Status(ErrorCodes::BadValue, @@ -726,7 +732,7 @@ namespace mongo { invalidateUserCache(); for (int i = 0; i < maxSteps; ++i) { bool isDone; - Status status = upgradeSchemaStep(writeConcern, &isDone); + Status status = upgradeSchemaStep(txn, writeConcern, &isDone); invalidateUserCache(); if (!status.isOK() || isDone) { return status; diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h index be11d634e83..c03e5b3eb66 100644 --- a/src/mongo/db/auth/authorization_manager.h +++ b/src/mongo/db/auth/authorization_manager.h @@ -53,6 +53,7 @@ namespace mongo { class AuthzManagerExternalState; class UserDocumentParser; + class OperationContext; /** * Internal secret key info. @@ -164,7 +165,7 @@ namespace mongo { * returns a non-OK status. When returning a non-OK status, *version will be set to * schemaVersionInvalid (0). */ - Status getAuthorizationVersion(int* version); + Status getAuthorizationVersion(OperationContext* txn, int* version); /** * Returns the user cache generation identifier. @@ -172,7 +173,7 @@ namespace mongo { OID getCacheGeneration(); // Returns true if there exists at least one privilege document in the system. - bool hasAnyPrivilegeDocuments() const; + bool hasAnyPrivilegeDocuments(OperationContext* txn) const; /** * Updates the auth schema version document to reflect that the system is upgraded to @@ -281,7 +282,7 @@ namespace mongo { * * If the user does not exist, returns ErrorCodes::UserNotFound. */ - Status getUserDescription(const UserName& userName, BSONObj* result); + Status getUserDescription(OperationContext* txn, const UserName& userName, BSONObj* result); /** * Writes into "result" a document describing the named role and returns Status::OK(). The @@ -324,7 +325,7 @@ namespace mongo { * The AuthorizationManager retains ownership of the returned User object. * On non-OK Status return values, acquiredUser will not be modified. */ - Status acquireUser(const UserName& userName, User** acquiredUser); + Status acquireUser(OperationContext* txn, const UserName& userName, User** acquiredUser); /** * Decrements the refcount of the given User object. If the refcount has gone to zero, @@ -389,7 +390,8 @@ namespace mongo { * On failure, returns a status other than Status::OK(). In this case, is is typically safe * to try again. */ - Status upgradeSchemaStep(const BSONObj& writeConcern, bool* isDone); + Status upgradeSchemaStep( + OperationContext* txn, const BSONObj& writeConcern, bool* isDone); /** * Performs up to maxSteps steps in the process of upgrading the stored authorization data @@ -404,7 +406,7 @@ namespace mongo { * progress performing the upgrade, and the specific code and message in the returned status * may provide additional information. */ - Status upgradeSchema(int maxSteps, const BSONObj& writeConcern); + Status upgradeSchema(OperationContext* txn, int maxSteps, const BSONObj& writeConcern); /** * Hook called by replication code to let the AuthorizationManager observe changes @@ -448,7 +450,9 @@ namespace mongo { * Fetches user information from a v2-schema user document for the named user, * and stores a pointer to a new user object into *acquiredUser on success. */ - Status _fetchUserV2(const UserName& userName, std::auto_ptr<User>* acquiredUser); + Status _fetchUserV2(OperationContext* txn, + const UserName& userName, + std::auto_ptr<User>* acquiredUser); /** * True if access control enforcement is enabled in this AuthorizationManager. diff --git a/src/mongo/db/auth/authorization_manager_global.cpp b/src/mongo/db/auth/authorization_manager_global.cpp index 68e5cd1e7cb..5e6c680cd16 100644 --- a/src/mongo/db/auth/authorization_manager_global.cpp +++ b/src/mongo/db/auth/authorization_manager_global.cpp @@ -44,7 +44,7 @@ namespace { MONGO_DISALLOW_COPYING(AuthzVersionParameter); public: AuthzVersionParameter(ServerParameterSet* sps, const std::string& name); - virtual void append(BSONObjBuilder& b, const std::string& name); + virtual void append(OperationContext* txn, BSONObjBuilder& b, const std::string& name); virtual Status set(const BSONElement& newValueElement); virtual Status setFromString(const std::string& str); }; @@ -60,9 +60,11 @@ namespace { AuthzVersionParameter::AuthzVersionParameter(ServerParameterSet* sps, const std::string& name) : ServerParameter(sps, name, false, false) {} - void AuthzVersionParameter::append(BSONObjBuilder& b, const std::string& name) { + void AuthzVersionParameter::append( + OperationContext* txn, BSONObjBuilder& b, const std::string& name) { int authzVersion; - uassertStatusOK(getGlobalAuthorizationManager()->getAuthorizationVersion(&authzVersion)); + uassertStatusOK( + getGlobalAuthorizationManager()->getAuthorizationVersion(txn, &authzVersion)); b.append(name, authzVersion); } diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp index 0e4c71447bb..e230dc1e405 100644 --- a/src/mongo/db/auth/authorization_manager_test.cpp +++ b/src/mongo/db/auth/authorization_manager_test.cpp @@ -39,6 +39,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/unittest/unittest.h" #include "mongo/util/map_util.h" @@ -186,8 +187,10 @@ namespace { "roles" << BSON_ARRAY(BSON("role" << "clusterAdmin" << "db" << "admin"))), BSONObj())); + OperationContextNoop txn; + User* v2read; - ASSERT_OK(authzManager->acquireUser(UserName("v2read", "test"), &v2read)); + ASSERT_OK(authzManager->acquireUser(&txn, UserName("v2read", "test"), &v2read)); ASSERT_EQUALS(UserName("v2read", "test"), v2read->getName()); ASSERT(v2read->isValid()); ASSERT_EQUALS(1U, v2read->getRefCount()); @@ -198,7 +201,7 @@ namespace { authzManager->releaseUser(v2read); User* v2cluster; - ASSERT_OK(authzManager->acquireUser(UserName("v2cluster", "admin"), &v2cluster)); + ASSERT_OK(authzManager->acquireUser(&txn, UserName("v2cluster", "admin"), &v2cluster)); ASSERT_EQUALS(UserName("v2cluster", "admin"), v2cluster->getName()); ASSERT(v2cluster->isValid()); ASSERT_EQUALS(1U, v2cluster->getRefCount()); diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp index 2946cbfd352..f731266721c 100644 --- a/src/mongo/db/auth/authorization_session.cpp +++ b/src/mongo/db/auth/authorization_session.cpp @@ -67,14 +67,15 @@ namespace { return _externalState->getAuthorizationManager(); } - void AuthorizationSession::startRequest() { - _externalState->startRequest(); - _refreshUserInfoAsNeeded(); + void AuthorizationSession::startRequest(OperationContext* txn) { + _externalState->startRequest(txn); + _refreshUserInfoAsNeeded(txn); } - Status AuthorizationSession::addAndAuthorizeUser(const UserName& userName) { + Status AuthorizationSession::addAndAuthorizeUser( + OperationContext* txn, const UserName& userName) { User* user; - Status status = getAuthorizationManager().acquireUser(userName, &user); + Status status = getAuthorizationManager().acquireUser(txn, userName, &user); if (!status.isOK()) { return status; } @@ -251,7 +252,8 @@ namespace { << resource.databaseToMatch() << "database"); } } else if (!isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName("admin"), ActionType::grantRole)) { + ResourcePattern::forDatabaseName("admin"), + ActionType::grantRole)) { return Status(ErrorCodes::Unauthorized, "To grant privileges affecting multiple databases or the cluster," " must be authorized to grant roles from the admin database"); @@ -271,7 +273,8 @@ namespace { << resource.databaseToMatch() << "database"); } } else if (!isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName("admin"), ActionType::revokeRole)) { + ResourcePattern::forDatabaseName("admin"), + ActionType::revokeRole)) { return Status(ErrorCodes::Unauthorized, "To revoke privileges affecting multiple databases or the cluster," " must be authorized to revoke roles from the admin database"); @@ -281,14 +284,14 @@ namespace { bool AuthorizationSession::isAuthorizedToGrantRole(const RoleName& role) { return isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(role.getDB()), - ActionType::grantRole); + ResourcePattern::forDatabaseName(role.getDB()), + ActionType::grantRole); } bool AuthorizationSession::isAuthorizedToRevokeRole(const RoleName& role) { return isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(role.getDB()), - ActionType::revokeRole); + ResourcePattern::forDatabaseName(role.getDB()), + ActionType::revokeRole); } bool AuthorizationSession::isAuthorizedForPrivilege(const Privilege& privilege) { @@ -322,12 +325,14 @@ namespace { bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns, ActionType action) { - return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), action)); + return isAuthorizedForPrivilege( + Privilege(ResourcePattern::forExactNamespace(ns), action)); } bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns, - const ActionSet& actions) { - return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), actions)); + const ActionSet& actions) { + return isAuthorizedForPrivilege( + Privilege(ResourcePattern::forExactNamespace(ns), actions)); } static const int resourceSearchListCapacity = 5; @@ -422,7 +427,7 @@ namespace { return false; } - void AuthorizationSession::_refreshUserInfoAsNeeded() { + void AuthorizationSession::_refreshUserInfoAsNeeded(OperationContext* txn) { AuthorizationManager& authMan = getAuthorizationManager(); UserSet::iterator it = _authenticatedUsers.begin(); while (it != _authenticatedUsers.end()) { @@ -434,7 +439,7 @@ namespace { UserName name = user->getName(); User* updatedUser; - Status status = authMan.acquireUser(name, &updatedUser); + Status status = authMan.acquireUser(txn, name, &updatedUser); switch (status.code()) { case ErrorCodes::OK: { // Success! Replace the old User object with the updated one. @@ -490,7 +495,6 @@ namespace { for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end(); ++it) { User* user = *it; - for (int i = 0; i < resourceSearchListLength; ++i) { ActionSet userActions = user->getActionsForResource(resourceSearchList[i]); unmetRequirements.removeAllActionsFromSet(userActions); diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h index 1a12a0719e0..f0484e26f1b 100644 --- a/src/mongo/db/auth/authorization_session.h +++ b/src/mongo/db/auth/authorization_session.h @@ -71,13 +71,13 @@ namespace mongo { // Should be called at the beginning of every new request. This performs the checks // necessary to determine if localhost connections should be given full access. // TODO: try to eliminate the need for this call. - void startRequest(); + void startRequest(OperationContext* txn); /** * Adds the User identified by "UserName" to the authorization session, acquiring privileges * for it in the process. */ - Status addAndAuthorizeUser(const UserName& userName); + Status addAndAuthorizeUser(OperationContext* txn, const UserName& userName); // Returns the authenticated user with the given name. Returns NULL // if no such user is found. @@ -182,7 +182,8 @@ namespace mongo { // Utility function for // isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), actions). - bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, const ActionSet& actions); + bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, + const ActionSet& actions); // Replaces the vector of UserNames that a system user is impersonating with a new vector. // The auditing system adds these to each audit record in the log. @@ -203,7 +204,7 @@ namespace mongo { // If any users authenticated on this session are marked as invalid this updates them with // up-to-date information. May require a read lock on the "admin" db to read the user data. - void _refreshUserInfoAsNeeded(); + void _refreshUserInfoAsNeeded(OperationContext* txn); // Checks if this connection is authorized for the given Privilege, ignoring whether or not // we should even be doing authorization checks in general. Note: this may acquire a read diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp index f9410440af8..8c25e9b6e3d 100644 --- a/src/mongo/db/auth/authorization_session_test.cpp +++ b/src/mongo/db/auth/authorization_session_test.cpp @@ -36,6 +36,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/unittest/unittest.h" #include "mongo/util/map_util.h" @@ -53,7 +54,8 @@ namespace { void setFindsShouldFail(bool enable) { _findsShouldFail = enable; } - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result) { if (_findsShouldFail && @@ -62,7 +64,7 @@ namespace { return Status(ErrorCodes::UnknownError, "findOne on admin.system.users set to fail in mock."); } - return AuthzManagerExternalStateMock::findOne(collectionName, query, result); + return AuthzManagerExternalStateMock::findOne(txn, collectionName, query, result); } private: @@ -72,6 +74,7 @@ namespace { class AuthorizationSessionTest : public ::mongo::unittest::Test { public: FailureCapableAuthzManagerExternalStateMock* managerState; + OperationContextNoop _txn; AuthzSessionExternalStateMock* sessionState; scoped_ptr<AuthorizationManager> authzManager; scoped_ptr<AuthorizationSession> authzSession; @@ -129,7 +132,7 @@ namespace { // Check that you can't authorize a user that doesn't exist. ASSERT_EQUALS(ErrorCodes::UserNotFound, - authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); // Add a user with readWrite and dbAdmin on the test DB ASSERT_OK(managerState->insertPrivilegeDocument("admin", @@ -141,7 +144,7 @@ namespace { BSON("role" << "dbAdmin" << "db" << "test"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( testFooCollResource, ActionType::insert)); @@ -158,7 +161,7 @@ namespace { "roles" << BSON_ARRAY(BSON("role" << "readWriteAnyDatabase" << "db" << "admin"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("admin", "admin"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("admin", "admin"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( ResourcePattern::forExactNamespace( @@ -203,7 +206,7 @@ namespace { BSON("role" << "readWrite" << "db" << "test"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( testFooCollResource, ActionType::insert)); @@ -247,7 +250,7 @@ namespace { "db" << "admin"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("rwany", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("rwany", "test"))); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( testUsersCollResource, ActionType::insert)); @@ -267,7 +270,7 @@ namespace { otherProfileCollResource, ActionType::find)); // Logging in as useradminany@test implicitly logs out rwany@test. - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("useradminany", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("useradminany", "test"))); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( testUsersCollResource, ActionType::insert)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( @@ -286,7 +289,7 @@ namespace { otherProfileCollResource, ActionType::find)); // Logging in as rw@test implicitly logs out useradminany@test. - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("rw", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("rw", "test"))); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( testUsersCollResource, ActionType::insert)); @@ -307,7 +310,7 @@ namespace { // Logging in as useradmin@test implicitly logs out rw@test. - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("useradmin", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("useradmin", "test"))); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( testUsersCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( @@ -335,7 +338,7 @@ namespace { "roles" << BSON_ARRAY(BSON("role" << "readWrite" << "db" << "test"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( testFooCollResource, ActionType::find)); @@ -362,7 +365,7 @@ namespace { // Make sure that invalidating the user causes the session to reload its privileges. authzManager->invalidateUserByName(user->getName()); - authzSession->startRequest(); // Refreshes cached data for invalid users + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( testFooCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( @@ -379,7 +382,7 @@ namespace { &ignored); // Make sure that invalidating the user causes the session to reload its privileges. authzManager->invalidateUserByName(user->getName()); - authzSession->startRequest(); // Refreshes cached data for invalid users + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( testFooCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( @@ -396,7 +399,7 @@ namespace { "roles" << BSON_ARRAY(BSON("role" << "readWrite" << "db" << "test"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( testFooCollResource, ActionType::find)); @@ -426,7 +429,7 @@ namespace { // document lookup to fail, the authz session should continue to use its known out-of-date // privilege data. authzManager->invalidateUserByName(user->getName()); - authzSession->startRequest(); // Refreshes cached data for invalid users + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( testFooCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( @@ -435,7 +438,7 @@ namespace { // Once we configure document lookup to succeed again, authorization checks should // observe the new values. managerState->setFindsShouldFail(false); - authzSession->startRequest(); // Refreshes cached data for invalid users + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( testFooCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( diff --git a/src/mongo/db/auth/authz_manager_external_state.cpp b/src/mongo/db/auth/authz_manager_external_state.cpp index 5a369cade31..4b9b3501a11 100644 --- a/src/mongo/db/auth/authz_manager_external_state.cpp +++ b/src/mongo/db/auth/authz_manager_external_state.cpp @@ -40,9 +40,10 @@ namespace mongo { AuthzManagerExternalState::AuthzManagerExternalState() {} AuthzManagerExternalState::~AuthzManagerExternalState() {} - bool AuthzManagerExternalState::hasAnyPrivilegeDocuments() { + bool AuthzManagerExternalState::hasAnyPrivilegeDocuments(OperationContext* txn) { BSONObj userBSONObj; Status status = findOne( + txn, AuthorizationManager::usersCollectionNamespace, BSONObj(), &userBSONObj); diff --git a/src/mongo/db/auth/authz_manager_external_state.h b/src/mongo/db/auth/authz_manager_external_state.h index 47226e9735b..397d7cb718f 100644 --- a/src/mongo/db/auth/authz_manager_external_state.h +++ b/src/mongo/db/auth/authz_manager_external_state.h @@ -41,6 +41,8 @@ namespace mongo { + class OperationContext; + /** * Public interface for a class that encapsulates all the information related to system * state not stored in AuthorizationManager. This is primarily to make AuthorizationManager @@ -64,7 +66,7 @@ namespace mongo { * Retrieves the schema version of the persistent data describing users and roles. * Will leave *outVersion unmodified on non-OK status return values. */ - virtual Status getStoredAuthorizationVersion(int* outVersion) = 0; + virtual Status getStoredAuthorizationVersion(OperationContext* txn, int* outVersion) = 0; /** * Writes into "result" a document describing the named user and returns Status::OK(). The @@ -76,7 +78,8 @@ namespace mongo { * * If the user does not exist, returns ErrorCodes::UserNotFound. */ - virtual Status getUserDescription(const UserName& userName, BSONObj* result) = 0; + virtual Status getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result) = 0; /** * Writes into "result" a document describing the named role and returns Status::OK(). The @@ -114,7 +117,7 @@ namespace mongo { /** * Returns true if there exists at least one privilege document in the system. */ - bool hasAnyPrivilegeDocuments(); + bool hasAnyPrivilegeDocuments(OperationContext* txn); /** * Creates the given user object in the given database. @@ -153,7 +156,8 @@ namespace mongo { * Returns Status::OK() on success. If no match is found, returns * ErrorCodes::NoMatchingDocument. Other errors returned as appropriate. */ - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result) = 0; diff --git a/src/mongo/db/auth/authz_manager_external_state_d.cpp b/src/mongo/db/auth/authz_manager_external_state_d.cpp index 2c009314f48..852f6d96b71 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_d.cpp @@ -47,12 +47,13 @@ namespace mongo { AuthzManagerExternalStateMongod::AuthzManagerExternalStateMongod() {} AuthzManagerExternalStateMongod::~AuthzManagerExternalStateMongod() {} - Status AuthzManagerExternalStateMongod::_getUserDocument(const UserName& userName, - BSONObj* userDoc) { + Status AuthzManagerExternalStateMongod::_getUserDocument( + OperationContext* txn, const UserName& userName, BSONObj* userDoc) { + + Client::ReadContext ctx(txn, "admin"); - Client::ReadContext ctx("admin"); int authzVersion; - Status status = getStoredAuthorizationVersion(&authzVersion); + Status status = getStoredAuthorizationVersion(txn, &authzVersion); if (!status.isOK()) return status; @@ -67,6 +68,7 @@ namespace mongo { } status = findOne( + txn, (authzVersion == AuthorizationManager::schemaVersion26Final ? AuthorizationManager::usersCollectionNamespace : AuthorizationManager::usersAltCollectionNamespace), @@ -102,11 +104,13 @@ namespace mongo { } Status AuthzManagerExternalStateMongod::findOne( + OperationContext* txn, const NamespaceString& collectionName, const BSONObj& query, BSONObj* result) { - Client::ReadContext ctx(collectionName.ns()); + Client::ReadContext ctx(txn, collectionName.ns()); + BSONObj found; if (Helpers::findOne(ctx.ctx().db()->getCollection(collectionName), query, diff --git a/src/mongo/db/auth/authz_manager_external_state_d.h b/src/mongo/db/auth/authz_manager_external_state_d.h index 380d4eb6bef..213fcc56152 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.h +++ b/src/mongo/db/auth/authz_manager_external_state_d.h @@ -52,7 +52,8 @@ namespace mongo { virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames); - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result); virtual Status query(const NamespaceString& collectionName, @@ -83,7 +84,8 @@ namespace mongo { virtual void releaseAuthzUpdateLock(); private: - virtual Status _getUserDocument(const UserName& userName, BSONObj* userDoc); + virtual Status _getUserDocument( + OperationContext* txn, const UserName& userName, BSONObj* userDoc); boost::timed_mutex _authzDataUpdateLock; }; 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 099e5638020..926158bc740 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp @@ -59,9 +59,11 @@ namespace mongo { return Status::OK(); } - Status AuthzManagerExternalStateLocal::getStoredAuthorizationVersion(int* outVersion) { + Status AuthzManagerExternalStateLocal::getStoredAuthorizationVersion( + OperationContext* txn, int* outVersion) { BSONObj versionDoc; - Status status = findOne(AuthorizationManager::versionCollectionNamespace, + Status status = findOne(txn, + AuthorizationManager::versionCollectionNamespace, AuthorizationManager::versionDocumentQuery, &versionDoc); if (status.isOK()) { @@ -85,7 +87,7 @@ namespace mongo { } } else if (status == ErrorCodes::NoMatchingDocument) { - if (hasAnyPrivilegeDocuments()) { + if (hasAnyPrivilegeDocuments(txn)) { *outVersion = AuthorizationManager::schemaVersion24; } else { @@ -136,11 +138,12 @@ namespace { } // namespace Status AuthzManagerExternalStateLocal::getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result) { BSONObj userDoc; - Status status = _getUserDocument(userName, &userDoc); + Status status = _getUserDocument(txn, userName, &userDoc); if (!status.isOK()) return status; 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 2c49c4b7cc7..ba48862e277 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.h +++ b/src/mongo/db/auth/authz_manager_external_state_local.h @@ -53,8 +53,9 @@ namespace mongo { virtual Status initialize(); - virtual Status getStoredAuthorizationVersion(int* outVersion); - virtual Status getUserDescription(const UserName& userName, BSONObj* result); + virtual Status getStoredAuthorizationVersion(OperationContext* txn, int* outVersion); + virtual Status getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result); virtual Status getRoleDescription(const RoleName& roleName, bool showPrivileges, BSONObj* result); @@ -88,7 +89,9 @@ namespace mongo { /** * Fetches the user document for "userName" from local storage, and stores it into "result". */ - virtual Status _getUserDocument(const UserName& userName, BSONObj* result) = 0; + virtual Status _getUserDocument(OperationContext* txn, + const UserName& userName, + BSONObj* result) = 0; Status _getRoleDescription_inlock(const RoleName& roleName, bool showPrivileges, diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.cpp b/src/mongo/db/auth/authz_manager_external_state_mock.cpp index 5ee19c863a5..809d4ecb747 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp @@ -97,10 +97,11 @@ namespace { BSONObj())); } - Status AuthzManagerExternalStateMock::_getUserDocument(const UserName& userName, + Status AuthzManagerExternalStateMock::_getUserDocument(OperationContext* txn, + const UserName& userName, BSONObj* userDoc) { int authzVersion; - Status status = getStoredAuthorizationVersion(&authzVersion); + Status status = getStoredAuthorizationVersion(txn, &authzVersion); if (!status.isOK()) return status; @@ -115,6 +116,7 @@ namespace { } status = findOne( + txn, (authzVersion == AuthorizationManager::schemaVersion26Final ? AuthorizationManager::usersCollectionNamespace : AuthorizationManager::usersAltCollectionNamespace), @@ -139,18 +141,8 @@ namespace { return Status::OK(); } - Status AuthzManagerExternalStateMock::_findUser( - const std::string& usersNamespace, - const BSONObj& query, - BSONObj* result) { - if (!findOne(NamespaceString(usersNamespace), query, result).isOK()) { - return Status(ErrorCodes::UserNotFound, - "No matching user for query " + query.toString()); - } - return Status::OK(); - } - Status AuthzManagerExternalStateMock::findOne( + OperationContext* txn, const NamespaceString& collectionName, const BSONObj& query, BSONObj* result) { diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.h b/src/mongo/db/auth/authz_manager_external_state_mock.h index 6ec06f97692..06db6b77890 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.h +++ b/src/mongo/db/auth/authz_manager_external_state_mock.h @@ -60,7 +60,8 @@ namespace mongo { virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames); - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result); @@ -101,16 +102,14 @@ namespace mongo { virtual bool tryAcquireAuthzUpdateLock(const StringData& why); virtual void releaseAuthzUpdateLock(); - Status _findUser(const std::string& usersNamespace, - const BSONObj& query, - BSONObj* result); std::vector<BSONObj> getCollectionContents(const NamespaceString& collectionName); private: typedef std::vector<BSONObj> BSONObjCollection; typedef std::map<NamespaceString, BSONObjCollection> NamespaceDocumentMap; - virtual Status _getUserDocument(const UserName& userName, BSONObj* userDoc); + virtual Status _getUserDocument( + OperationContext* txn, const UserName& userName, BSONObj* userDoc); Status _findOneIter(const NamespaceString& collectionName, const BSONObj& query, diff --git a/src/mongo/db/auth/authz_manager_external_state_s.cpp b/src/mongo/db/auth/authz_manager_external_state_s.cpp index 8f1dd6d1256..0cd3760258c 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp @@ -70,7 +70,8 @@ namespace mongo { } } - Status AuthzManagerExternalStateMongos::getStoredAuthorizationVersion(int* outVersion) { + Status AuthzManagerExternalStateMongos::getStoredAuthorizationVersion( + OperationContext* txn, int* outVersion) { scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection( AuthorizationManager::usersCollectionNamespace)); Status status = auth::getRemoteStoredAuthorizationVersion(conn->get(), outVersion); @@ -78,8 +79,8 @@ namespace mongo { return status; } - Status AuthzManagerExternalStateMongos::getUserDescription(const UserName& userName, - BSONObj* result) { + Status AuthzManagerExternalStateMongos::getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result) { try { scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection( AuthorizationManager::usersCollectionNamespace)); @@ -190,6 +191,7 @@ namespace mongo { } Status AuthzManagerExternalStateMongos::findOne( + OperationContext* txn, const NamespaceString& collectionName, const BSONObj& queryDoc, BSONObj* result) { diff --git a/src/mongo/db/auth/authz_manager_external_state_s.h b/src/mongo/db/auth/authz_manager_external_state_s.h index 203ce25f5ac..c19e3ed056e 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.h +++ b/src/mongo/db/auth/authz_manager_external_state_s.h @@ -52,8 +52,9 @@ namespace mongo { virtual ~AuthzManagerExternalStateMongos(); virtual Status initialize(); - virtual Status getStoredAuthorizationVersion(int* outVersion); - virtual Status getUserDescription(const UserName& userName, BSONObj* result); + virtual Status getStoredAuthorizationVersion(OperationContext* txn, int* outVersion); + virtual Status getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result); virtual Status getRoleDescription(const RoleName& roleName, bool showPrivileges, BSONObj* result); @@ -70,7 +71,8 @@ namespace mongo { * NOTE: The data returned from this helper may be from any config server or replica set * node. The first config server or primary node is preferred, when available. */ - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result); diff --git a/src/mongo/db/auth/authz_session_external_state.h b/src/mongo/db/auth/authz_session_external_state.h index dbd838cb68f..2e1b41a0565 100644 --- a/src/mongo/db/auth/authz_session_external_state.h +++ b/src/mongo/db/auth/authz_session_external_state.h @@ -39,6 +39,7 @@ namespace mongo { class Principal; + class OperationContext; /** * Public interface for a class that encapsulates all the session information related to system @@ -68,7 +69,7 @@ namespace mongo { // Should be called at the beginning of every new request. This performs the checks // necessary to determine if localhost connections should be given full access. - virtual void startRequest() = 0; + virtual void startRequest(OperationContext* txn) = 0; protected: // This class should never be instantiated directly. diff --git a/src/mongo/db/auth/authz_session_external_state_d.cpp b/src/mongo/db/auth/authz_session_external_state_d.cpp index 0156ccf6c9b..614b5e67505 100644 --- a/src/mongo/db/auth/authz_session_external_state_d.cpp +++ b/src/mongo/db/auth/authz_session_external_state_d.cpp @@ -45,9 +45,9 @@ namespace mongo { AuthzSessionExternalStateServerCommon(authzManager) {} AuthzSessionExternalStateMongod::~AuthzSessionExternalStateMongod() {} - void AuthzSessionExternalStateMongod::startRequest() { + void AuthzSessionExternalStateMongod::startRequest(OperationContext* txn) { if (!Lock::isLocked()) { - _checkShouldAllowLocalhost(); + _checkShouldAllowLocalhost(txn); } } diff --git a/src/mongo/db/auth/authz_session_external_state_d.h b/src/mongo/db/auth/authz_session_external_state_d.h index f5b2c82cd03..0df26d507c7 100644 --- a/src/mongo/db/auth/authz_session_external_state_d.h +++ b/src/mongo/db/auth/authz_session_external_state_d.h @@ -47,7 +47,7 @@ namespace mongo { virtual bool shouldIgnoreAuthChecks() const; - virtual void startRequest(); + virtual void startRequest(OperationContext* txn); }; } // namespace mongo diff --git a/src/mongo/db/auth/authz_session_external_state_mock.h b/src/mongo/db/auth/authz_session_external_state_mock.h index c884654ac91..0acc98366ea 100644 --- a/src/mongo/db/auth/authz_session_external_state_mock.h +++ b/src/mongo/db/auth/authz_session_external_state_mock.h @@ -62,7 +62,7 @@ namespace mongo { _allowLocalhostReturnValue = returnValue; } - virtual void startRequest() {} + virtual void startRequest(OperationContext* txn) {} private: bool _ignoreAuthChecksReturnValue; diff --git a/src/mongo/db/auth/authz_session_external_state_s.cpp b/src/mongo/db/auth/authz_session_external_state_s.cpp index 14801eae945..4009670c6c4 100644 --- a/src/mongo/db/auth/authz_session_external_state_s.cpp +++ b/src/mongo/db/auth/authz_session_external_state_s.cpp @@ -43,8 +43,8 @@ namespace mongo { AuthzSessionExternalStateServerCommon(authzManager) {} AuthzSessionExternalStateMongos::~AuthzSessionExternalStateMongos() {} - void AuthzSessionExternalStateMongos::startRequest() { - _checkShouldAllowLocalhost(); + void AuthzSessionExternalStateMongos::startRequest(OperationContext* txn) { + _checkShouldAllowLocalhost(txn); } } // namespace mongo diff --git a/src/mongo/db/auth/authz_session_external_state_s.h b/src/mongo/db/auth/authz_session_external_state_s.h index 6672957ced4..777082faadc 100644 --- a/src/mongo/db/auth/authz_session_external_state_s.h +++ b/src/mongo/db/auth/authz_session_external_state_s.h @@ -45,7 +45,7 @@ namespace mongo { AuthzSessionExternalStateMongos(AuthorizationManager* authzManager); virtual ~AuthzSessionExternalStateMongos(); - virtual void startRequest(); + virtual void startRequest(OperationContext* txn); }; } // namespace mongo diff --git a/src/mongo/db/auth/authz_session_external_state_server_common.cpp b/src/mongo/db/auth/authz_session_external_state_server_common.cpp index b5c6f6a4bc3..a62b472e5ab 100644 --- a/src/mongo/db/auth/authz_session_external_state_server_common.cpp +++ b/src/mongo/db/auth/authz_session_external_state_server_common.cpp @@ -49,7 +49,7 @@ namespace { _allowLocalhost(enableLocalhostAuthBypass) {} AuthzSessionExternalStateServerCommon::~AuthzSessionExternalStateServerCommon() {} - void AuthzSessionExternalStateServerCommon::_checkShouldAllowLocalhost() { + void AuthzSessionExternalStateServerCommon::_checkShouldAllowLocalhost(OperationContext* txn) { if (!_authzManager->isAuthEnabled()) return; // If we know that an admin user exists, don't re-check. @@ -61,7 +61,7 @@ namespace { return; } - _allowLocalhost = !_authzManager->hasAnyPrivilegeDocuments(); + _allowLocalhost = !_authzManager->hasAnyPrivilegeDocuments(txn); if (_allowLocalhost) { ONCE { log() << "note: no users configured in admin.system.users, allowing localhost " diff --git a/src/mongo/db/auth/authz_session_external_state_server_common.h b/src/mongo/db/auth/authz_session_external_state_server_common.h index f6e1a97f4a9..59599a6befd 100644 --- a/src/mongo/db/auth/authz_session_external_state_server_common.h +++ b/src/mongo/db/auth/authz_session_external_state_server_common.h @@ -53,7 +53,7 @@ namespace mongo { // Checks whether or not localhost connections should be given full access and stores the // result in _allowLocalhost. Currently localhost connections are only given full access // if there are no users in the admin database. - virtual void _checkShouldAllowLocalhost(); + void _checkShouldAllowLocalhost(OperationContext* txn); private: |