diff options
Diffstat (limited to 'src/mongo/db/auth/authorization_session_test.cpp')
-rw-r--r-- | src/mongo/db/auth/authorization_session_test.cpp | 849 |
1 files changed, 452 insertions, 397 deletions
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp index 5ce06edb4a7..0f5b4936e9d 100644 --- a/src/mongo/db/auth/authorization_session_test.cpp +++ b/src/mongo/db/auth/authorization_session_test.cpp @@ -46,409 +46,464 @@ namespace mongo { namespace { - class FailureCapableAuthzManagerExternalStateMock : - public AuthzManagerExternalStateMock { - public: - FailureCapableAuthzManagerExternalStateMock() : _findsShouldFail(false) {} - virtual ~FailureCapableAuthzManagerExternalStateMock() {} - - void setFindsShouldFail(bool enable) { _findsShouldFail = enable; } - - virtual Status findOne(OperationContext* txn, - const NamespaceString& collectionName, - const BSONObj& query, - BSONObj* result) { - if (_findsShouldFail && - collectionName == AuthorizationManager::usersCollectionNamespace) { - - return Status(ErrorCodes::UnknownError, - "findOne on admin.system.users set to fail in mock."); - } - return AuthzManagerExternalStateMock::findOne(txn, collectionName, query, result); - } - - private: - bool _findsShouldFail; - }; - - class AuthorizationSessionTest : public ::mongo::unittest::Test { - public: - FailureCapableAuthzManagerExternalStateMock* managerState; - OperationContextNoop _txn; - AuthzSessionExternalStateMock* sessionState; - std::unique_ptr<AuthorizationManager> authzManager; - std::unique_ptr<AuthorizationSession> authzSession; - - void setUp() { - auto localManagerState = stdx::make_unique<FailureCapableAuthzManagerExternalStateMock>(); - managerState = localManagerState.get(); - managerState->setAuthzVersion(AuthorizationManager::schemaVersion26Final); - authzManager = stdx::make_unique<AuthorizationManager>(std::move(localManagerState)); - auto localSessionState = stdx::make_unique<AuthzSessionExternalStateMock>(authzManager.get()); - sessionState = localSessionState.get(); - authzSession = stdx::make_unique<AuthorizationSession>(std::move(localSessionState)); - authzManager->setAuthEnabled(true); - } - }; - - const ResourcePattern testDBResource(ResourcePattern::forDatabaseName("test")); - const ResourcePattern otherDBResource(ResourcePattern::forDatabaseName("other")); - const ResourcePattern adminDBResource(ResourcePattern::forDatabaseName("admin")); - const ResourcePattern testFooCollResource( - ResourcePattern::forExactNamespace(NamespaceString("test.foo"))); - const ResourcePattern otherFooCollResource( - ResourcePattern::forExactNamespace(NamespaceString("other.foo"))); - const ResourcePattern thirdFooCollResource( - ResourcePattern::forExactNamespace(NamespaceString("third.foo"))); - const ResourcePattern adminFooCollResource( - ResourcePattern::forExactNamespace(NamespaceString("admin.foo"))); - const ResourcePattern testUsersCollResource( - ResourcePattern::forExactNamespace(NamespaceString("test.system.users"))); - const ResourcePattern otherUsersCollResource( - ResourcePattern::forExactNamespace(NamespaceString("other.system.users"))); - const ResourcePattern thirdUsersCollResource( - ResourcePattern::forExactNamespace(NamespaceString("third.system.users"))); - const ResourcePattern testIndexesCollResource( - ResourcePattern::forExactNamespace(NamespaceString("test.system.indexes"))); - const ResourcePattern otherIndexesCollResource( - ResourcePattern::forExactNamespace(NamespaceString("other.system.indexes"))); - const ResourcePattern thirdIndexesCollResource( - ResourcePattern::forExactNamespace(NamespaceString("third.system.indexes"))); - const ResourcePattern testProfileCollResource( - ResourcePattern::forExactNamespace(NamespaceString("test.system.profile"))); - const ResourcePattern otherProfileCollResource( - ResourcePattern::forExactNamespace(NamespaceString("other.system.profile"))); - const ResourcePattern thirdProfileCollResource( - ResourcePattern::forExactNamespace(NamespaceString("third.system.profile"))); - - TEST_F(AuthorizationSessionTest, AddUserAndCheckAuthorization) { - // Check that disabling auth checks works - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - sessionState->setReturnValueForShouldIgnoreAuthChecks(true); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - sessionState->setReturnValueForShouldIgnoreAuthChecks(false); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - - // Check that you can't authorize a user that doesn't exist. - ASSERT_EQUALS(ErrorCodes::UserNotFound, - authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); - - // Add a user with readWrite and dbAdmin on the test DB - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "spencer" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "readWrite" << - "db" << "test") << - BSON("role" << "dbAdmin" << - "db" << "test"))), - BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); - - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testDBResource, ActionType::dbStats)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); - - // Add an admin user with readWriteAnyDatabase - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "admin" << - "db" << "admin" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "readWriteAnyDatabase" << - "db" << "admin"))), - BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("admin", "admin"))); - - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forExactNamespace( - NamespaceString("anydb.somecollection")), - ActionType::insert)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherDBResource, ActionType::insert)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::collMod)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - - authzSession->logoutDatabase("test"); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::collMod)); - - authzSession->logoutDatabase("admin"); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::collMod)); - } +class FailureCapableAuthzManagerExternalStateMock : public AuthzManagerExternalStateMock { +public: + FailureCapableAuthzManagerExternalStateMock() : _findsShouldFail(false) {} + virtual ~FailureCapableAuthzManagerExternalStateMock() {} - TEST_F(AuthorizationSessionTest, DuplicateRolesOK) { - // Add a user with doubled-up readWrite and single dbAdmin on the test DB - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "spencer" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "readWrite" << - "db" << "test") << - BSON("role" << "dbAdmin" << - "db" << "test") << - BSON("role" << "readWrite" << - "db" << "test"))), - BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); - - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testDBResource, ActionType::dbStats)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); + void setFindsShouldFail(bool enable) { + _findsShouldFail = enable; } - TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) { - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "rw" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "readWrite" << - "db" << "test") << - BSON("role" << "dbAdmin" << - "db" << "test"))), - BSONObj())); - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "useradmin" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "userAdmin" << - "db" << "test"))), - BSONObj())); - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "rwany" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "readWriteAnyDatabase" << - "db" << "admin") << - BSON("role" << "dbAdminAnyDatabase" << - "db" << "admin"))), - BSONObj())); - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "useradminany" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "userAdminAnyDatabase" << - "db" << "admin"))), - BSONObj())); - - ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("rwany", "test"))); - - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::find)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testIndexesCollResource, ActionType::find)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testProfileCollResource, ActionType::find)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherIndexesCollResource, ActionType::find)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherProfileCollResource, ActionType::find)); - - // Logging in as useradminany@test implicitly logs out rwany@test. - ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("useradminany", "test"))); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::insert)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::insert)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testIndexesCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testProfileCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherIndexesCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherProfileCollResource, ActionType::find)); - - // Logging in as rw@test implicitly logs out useradminany@test. - ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("rw", "test"))); - - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::find)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testIndexesCollResource, ActionType::find)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testProfileCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherIndexesCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherProfileCollResource, ActionType::find)); - - - // Logging in as useradmin@test implicitly logs out rw@test. - ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("useradmin", "test"))); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testIndexesCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testProfileCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherIndexesCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherProfileCollResource, ActionType::find)); - } - - TEST_F(AuthorizationSessionTest, InvalidateUser) { - // Add a readWrite user - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "spencer" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "readWrite" << - "db" << "test"))), - BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); - - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - - User* user = authzSession->lookupUser(UserName("spencer", "test")); - ASSERT(user->isValid()); - - // Change the user to be read-only - int ignored; - managerState->remove( - &_txn, - AuthorizationManager::usersCollectionNamespace, - BSONObj(), - BSONObj(), - &ignored); - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "spencer" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "read" << - "db" << "test"))), - BSONObj())); - - // Make sure that invalidating the user causes the session to reload its privileges. - authzManager->invalidateUserByName(user->getName()); - authzSession->startRequest(&_txn); // Refreshes cached data for invalid users - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - - user = authzSession->lookupUser(UserName("spencer", "test")); - ASSERT(user->isValid()); - - // Delete the user. - managerState->remove( - &_txn, - AuthorizationManager::usersCollectionNamespace, - BSONObj(), - BSONObj(), - &ignored); - // Make sure that invalidating the user causes the session to reload its privileges. - authzManager->invalidateUserByName(user->getName()); - authzSession->startRequest(&_txn); // Refreshes cached data for invalid users - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - ASSERT_FALSE(authzSession->lookupUser(UserName("spencer", "test"))); + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, + const BSONObj& query, + BSONObj* result) { + if (_findsShouldFail && collectionName == AuthorizationManager::usersCollectionNamespace) { + return Status(ErrorCodes::UnknownError, + "findOne on admin.system.users set to fail in mock."); + } + return AuthzManagerExternalStateMock::findOne(txn, collectionName, query, result); } - TEST_F(AuthorizationSessionTest, UseOldUserInfoInFaceOfConnectivityProblems) { - // Add a readWrite user - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "spencer" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "readWrite" << - "db" << "test"))), - BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); - - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - - User* user = authzSession->lookupUser(UserName("spencer", "test")); - ASSERT(user->isValid()); - - // Change the user to be read-only - int ignored; - managerState->setFindsShouldFail(true); - managerState->remove( - &_txn, - AuthorizationManager::usersCollectionNamespace, - BSONObj(), - BSONObj(), - &ignored); - ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, - BSON("user" << "spencer" << - "db" << "test" << - "credentials" << BSON("MONGODB-CR" << "a") << - "roles" << BSON_ARRAY(BSON("role" << "read" << - "db" << "test"))), - BSONObj())); - - // Even though the user's privileges have been reduced, since we've configured user - // document lookup to fail, the authz session should continue to use its known out-of-date - // privilege data. - authzManager->invalidateUserByName(user->getName()); - authzSession->startRequest(&_txn); // Refreshes cached data for invalid users - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); - - // Once we configure document lookup to succeed again, authorization checks should - // observe the new values. - managerState->setFindsShouldFail(false); - authzSession->startRequest(&_txn); // Refreshes cached data for invalid users - ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); - ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); +private: + bool _findsShouldFail; +}; + +class AuthorizationSessionTest : public ::mongo::unittest::Test { +public: + FailureCapableAuthzManagerExternalStateMock* managerState; + OperationContextNoop _txn; + AuthzSessionExternalStateMock* sessionState; + std::unique_ptr<AuthorizationManager> authzManager; + std::unique_ptr<AuthorizationSession> authzSession; + + void setUp() { + auto localManagerState = stdx::make_unique<FailureCapableAuthzManagerExternalStateMock>(); + managerState = localManagerState.get(); + managerState->setAuthzVersion(AuthorizationManager::schemaVersion26Final); + authzManager = stdx::make_unique<AuthorizationManager>(std::move(localManagerState)); + auto localSessionState = + stdx::make_unique<AuthzSessionExternalStateMock>(authzManager.get()); + sessionState = localSessionState.get(); + authzSession = stdx::make_unique<AuthorizationSession>(std::move(localSessionState)); + authzManager->setAuthEnabled(true); } +}; + +const ResourcePattern testDBResource(ResourcePattern::forDatabaseName("test")); +const ResourcePattern otherDBResource(ResourcePattern::forDatabaseName("other")); +const ResourcePattern adminDBResource(ResourcePattern::forDatabaseName("admin")); +const ResourcePattern testFooCollResource( + ResourcePattern::forExactNamespace(NamespaceString("test.foo"))); +const ResourcePattern otherFooCollResource( + ResourcePattern::forExactNamespace(NamespaceString("other.foo"))); +const ResourcePattern thirdFooCollResource( + ResourcePattern::forExactNamespace(NamespaceString("third.foo"))); +const ResourcePattern adminFooCollResource( + ResourcePattern::forExactNamespace(NamespaceString("admin.foo"))); +const ResourcePattern testUsersCollResource( + ResourcePattern::forExactNamespace(NamespaceString("test.system.users"))); +const ResourcePattern otherUsersCollResource( + ResourcePattern::forExactNamespace(NamespaceString("other.system.users"))); +const ResourcePattern thirdUsersCollResource( + ResourcePattern::forExactNamespace(NamespaceString("third.system.users"))); +const ResourcePattern testIndexesCollResource( + ResourcePattern::forExactNamespace(NamespaceString("test.system.indexes"))); +const ResourcePattern otherIndexesCollResource( + ResourcePattern::forExactNamespace(NamespaceString("other.system.indexes"))); +const ResourcePattern thirdIndexesCollResource( + ResourcePattern::forExactNamespace(NamespaceString("third.system.indexes"))); +const ResourcePattern testProfileCollResource( + ResourcePattern::forExactNamespace(NamespaceString("test.system.profile"))); +const ResourcePattern otherProfileCollResource( + ResourcePattern::forExactNamespace(NamespaceString("other.system.profile"))); +const ResourcePattern thirdProfileCollResource( + ResourcePattern::forExactNamespace(NamespaceString("third.system.profile"))); + +TEST_F(AuthorizationSessionTest, AddUserAndCheckAuthorization) { + // Check that disabling auth checks works + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + sessionState->setReturnValueForShouldIgnoreAuthChecks(true); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + sessionState->setReturnValueForShouldIgnoreAuthChecks(false); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + + // Check that you can't authorize a user that doesn't exist. + ASSERT_EQUALS(ErrorCodes::UserNotFound, + authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); + + // Add a user with readWrite and dbAdmin on the test DB + ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "spencer" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "readWrite" + << "db" + << "test") + << BSON("role" + << "dbAdmin" + << "db" + << "test"))), + BSONObj())); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); + + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testDBResource, ActionType::dbStats)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherFooCollResource, ActionType::insert)); + + // Add an admin user with readWriteAnyDatabase + ASSERT_OK( + managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "admin" + << "db" + << "admin" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "readWriteAnyDatabase" + << "db" + << "admin"))), + BSONObj())); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("admin", "admin"))); + + ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( + ResourcePattern::forExactNamespace(NamespaceString("anydb.somecollection")), + ActionType::insert)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(otherDBResource, ActionType::insert)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(otherFooCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherFooCollResource, ActionType::collMod)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + + authzSession->logoutDatabase("test"); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(otherFooCollResource, ActionType::insert)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::collMod)); + + authzSession->logoutDatabase("admin"); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherFooCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::collMod)); +} + +TEST_F(AuthorizationSessionTest, DuplicateRolesOK) { + // Add a user with doubled-up readWrite and single dbAdmin on the test DB + ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "spencer" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "readWrite" + << "db" + << "test") + << BSON("role" + << "dbAdmin" + << "db" + << "test") + << BSON("role" + << "readWrite" + << "db" + << "test"))), + BSONObj())); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); + + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testDBResource, ActionType::dbStats)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherFooCollResource, ActionType::insert)); +} + +TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) { + ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "rw" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "readWrite" + << "db" + << "test") + << BSON("role" + << "dbAdmin" + << "db" + << "test"))), + BSONObj())); + ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "useradmin" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "userAdmin" + << "db" + << "test"))), + BSONObj())); + ASSERT_OK( + managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "rwany" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "readWriteAnyDatabase" + << "db" + << "admin") + << BSON("role" + << "dbAdminAnyDatabase" + << "db" + << "admin"))), + BSONObj())); + ASSERT_OK( + managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "useradminany" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "userAdminAnyDatabase" + << "db" + << "admin"))), + BSONObj())); + + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("rwany", "test"))); + + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherUsersCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherUsersCollResource, ActionType::find)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testIndexesCollResource, ActionType::find)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testProfileCollResource, ActionType::find)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(otherIndexesCollResource, ActionType::find)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(otherProfileCollResource, ActionType::find)); + + // Logging in as useradminany@test implicitly logs out rwany@test. + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("useradminany", "test"))); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::insert)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherUsersCollResource, ActionType::insert)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(otherUsersCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testIndexesCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testProfileCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherIndexesCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherProfileCollResource, ActionType::find)); + + // Logging in as rw@test implicitly logs out useradminany@test. + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("rw", "test"))); + + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherUsersCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherUsersCollResource, ActionType::find)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testIndexesCollResource, ActionType::find)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testProfileCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherIndexesCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherProfileCollResource, ActionType::find)); + + + // Logging in as useradmin@test implicitly logs out rw@test. + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("useradmin", "test"))); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testUsersCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherUsersCollResource, ActionType::insert)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherUsersCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testIndexesCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testProfileCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherIndexesCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(otherProfileCollResource, ActionType::find)); +} + +TEST_F(AuthorizationSessionTest, InvalidateUser) { + // Add a readWrite user + ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "spencer" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "readWrite" + << "db" + << "test"))), + BSONObj())); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); + + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::find)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + + User* user = authzSession->lookupUser(UserName("spencer", "test")); + ASSERT(user->isValid()); + + // Change the user to be read-only + int ignored; + managerState->remove( + &_txn, AuthorizationManager::usersCollectionNamespace, BSONObj(), BSONObj(), &ignored); + ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "spencer" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "read" + << "db" + << "test"))), + BSONObj())); + + // Make sure that invalidating the user causes the session to reload its privileges. + authzManager->invalidateUserByName(user->getName()); + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + + user = authzSession->lookupUser(UserName("spencer", "test")); + ASSERT(user->isValid()); + + // Delete the user. + managerState->remove( + &_txn, AuthorizationManager::usersCollectionNamespace, BSONObj(), BSONObj(), &ignored); + // Make sure that invalidating the user causes the session to reload its privileges. + authzManager->invalidateUserByName(user->getName()); + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + ASSERT_FALSE(authzSession->lookupUser(UserName("spencer", "test"))); +} + +TEST_F(AuthorizationSessionTest, UseOldUserInfoInFaceOfConnectivityProblems) { + // Add a readWrite user + ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "spencer" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "readWrite" + << "db" + << "test"))), + BSONObj())); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); + + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::find)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + + User* user = authzSession->lookupUser(UserName("spencer", "test")); + ASSERT(user->isValid()); + + // Change the user to be read-only + int ignored; + managerState->setFindsShouldFail(true); + managerState->remove( + &_txn, AuthorizationManager::usersCollectionNamespace, BSONObj(), BSONObj(), &ignored); + ASSERT_OK(managerState->insertPrivilegeDocument(&_txn, + BSON("user" + << "spencer" + << "db" + << "test" + << "credentials" << BSON("MONGODB-CR" + << "a") << "roles" + << BSON_ARRAY(BSON("role" + << "read" + << "db" + << "test"))), + BSONObj())); + + // Even though the user's privileges have been reduced, since we've configured user + // document lookup to fail, the authz session should continue to use its known out-of-date + // privilege data. + authzManager->invalidateUserByName(user->getName()); + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::find)); + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); + + // Once we configure document lookup to succeed again, authorization checks should + // observe the new values. + managerState->setFindsShouldFail(false); + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users + ASSERT_TRUE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::find)); + ASSERT_FALSE( + authzSession->isAuthorizedForActionsOnResource(testFooCollResource, ActionType::insert)); +} } // namespace } // namespace mongo |