diff options
author | Spencer Jackson <spencer.jackson@mongodb.com> | 2017-08-08 15:13:51 -0400 |
---|---|---|
committer | Spencer Jackson <spencer.jackson@mongodb.com> | 2017-08-11 15:19:33 -0400 |
commit | 718e9c68e0526e2db4fbfd0ecac31eae1b3a095a (patch) | |
tree | eb077f4a2facde33afbd5eb65b33f027d32ad586 /src/mongo/db/auth | |
parent | ba11e4172e8d5f9149a212a0b42da60873338527 (diff) | |
download | mongo-718e9c68e0526e2db4fbfd0ecac31eae1b3a095a.tar.gz |
SERVER-30566: Unwind SERVER-28190
Diffstat (limited to 'src/mongo/db/auth')
-rw-r--r-- | src/mongo/db/auth/authorization_manager.cpp | 38 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager.h | 50 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_manager_test.cpp | 19 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_session.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/auth/authorization_session.h | 5 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_plain_server_conversation.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/auth/user.cpp | 20 | ||||
-rw-r--r-- | src/mongo/db/auth/user.h | 18 | ||||
-rw-r--r-- | src/mongo/db/auth/user_document_parser.cpp | 15 | ||||
-rw-r--r-- | src/mongo/db/auth/user_document_parser.h | 2 | ||||
-rw-r--r-- | src/mongo/db/auth/user_document_parser_test.cpp | 46 |
12 files changed, 37 insertions, 199 deletions
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp index 0cac76e7398..0e97504b782 100644 --- a/src/mongo/db/auth/authorization_manager.cpp +++ b/src/mongo/db/auth/authorization_manager.cpp @@ -108,7 +108,6 @@ MONGO_INITIALIZER_WITH_PREREQUISITES(SetupInternalSecurityUser, ("EndStartupOpti } const std::string AuthorizationManager::USER_NAME_FIELD_NAME = "user"; -const std::string AuthorizationManager::USER_ID_FIELD_NAME = "userId"; const std::string AuthorizationManager::USER_DB_FIELD_NAME = "db"; const std::string AuthorizationManager::ROLE_NAME_FIELD_NAME = "role"; const std::string AuthorizationManager::ROLE_DB_FIELD_NAME = "db"; @@ -411,7 +410,6 @@ Status AuthorizationManager::_initializeUserFromPrivilegeDocument(User* user, const BSONObj& privDoc) { V2UserDocumentParser parser; std::string userName = parser.extractUserNameFromUserDocument(privDoc); - if (userName != user->getName().getUser()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "User name from privilege document \"" @@ -422,8 +420,6 @@ Status AuthorizationManager::_initializeUserFromPrivilegeDocument(User* user, 0); } - user->setID(parser.extractUserIDFromUserDocument(privDoc)); - Status status = parser.initializeUserCredentialsFromUserDocument(user, privDoc); if (!status.isOK()) { return status; @@ -481,36 +477,9 @@ Status AuthorizationManager::getRoleDescriptionsForDB(OperationContext* opCtx, opCtx, dbname, privileges, restrictions, showBuiltinRoles, result); } -Status AuthorizationManager::acquireUserToRefreshSessionCache(OperationContext* opCtx, - const UserName& userName, - boost::optional<OID> id, - User** acquiredUser) { - // Funnel down to acquireUserForInitialAuth, and then do the id checking. - auto status = acquireUserForInitialAuth(opCtx, userName, acquiredUser); - if (!status.isOK()) { - // If we got a non-ok status, no acquiredUser should be set, so we can simply - // return without doing an id check. - return status; - } - - // Verify that the returned user matches the id that we were passed. - if (id != (*acquiredUser)->getID()) { - // If the generations don't match, then fail. - releaseUser(*acquiredUser); - *acquiredUser = nullptr; - return Status(ErrorCodes::UserNotFound, - mongoutils::str::stream() << "User id from privilege document \"" - << userName.toString() - << "\" doesn't match provided user id", - 0); - } - - return status; -} - -Status AuthorizationManager::acquireUserForInitialAuth(OperationContext* opCtx, - const UserName& userName, - User** acquiredUser) { +Status AuthorizationManager::acquireUser(OperationContext* opCtx, + const UserName& userName, + User** acquiredUser) { if (userName == internalSecurity.user->getName()) { *acquiredUser = internalSecurity.user; return Status::OK(); @@ -577,7 +546,6 @@ Status AuthorizationManager::acquireUserForInitialAuth(OperationContext* opCtx, authzVersion = schemaVersionInvalid; } - if (!status.isOK()) return status; diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h index e8840838e11..578d9b384e5 100644 --- a/src/mongo/db/auth/authorization_manager.h +++ b/src/mongo/db/auth/authorization_manager.h @@ -31,8 +31,6 @@ #include <memory> #include <string> -#include <boost/optional.hpp> - #include "mongo/base/disallow_copying.h" #include "mongo/base/status.h" #include "mongo/bson/mutable/element.h" @@ -92,7 +90,6 @@ public: ~AuthorizationManager(); static const std::string USER_NAME_FIELD_NAME; - static const std::string USER_ID_FIELD_NAME; static const std::string USER_DB_FIELD_NAME; static const std::string ROLE_NAME_FIELD_NAME; static const std::string ROLE_DB_FIELD_NAME; @@ -278,41 +275,16 @@ public: std::vector<BSONObj>* result); /** - * Returns the User object for the given userName in the out parameter "acquiredUser". - * - * This method should be used only when initially authenticating a user, in contexts when - * the caller does not yet have an id for this user. When the caller already has access - * to a user document, acquireUserToRefreshSessionCache should be used instead. - * - * If no user object for this user name exists yet in the cache, read the user's privilege - * document from disk, build up a User object, sets the refcount to 1, and give that out. - * - * The returned user may be invalid by the time the caller gets access to it. - * The AuthorizationManager retains ownership of the returned User object. - * On non-OK Status return values, acquiredUser will not be modified. - */ - Status acquireUserForInitialAuth(OperationContext* opCtx, - const UserName& userName, - User** acquiredUser); - /** - * Returns the User object for the given userName in the out parameter "acquiredUser". - * - * This method must be called with a user id (the unset optional, boost::none, will be - * understood as a distinct id for a pre-3.6 user). The acquired user must match - * both the given name and given id, or this method will return an error. This method - * should be used when the caller is refresing a user document they already have. - * - * If no user object for this user name exists yet in the cache, read the user's privilege - * document from disk, build up a User object, sets the refcount to 1, and give that out. - * - * The returned user may be invalid by the time the caller gets access to it. - * The AuthorizationManager retains ownership of the returned User object. - * On non-OK Status return values, acquiredUser will not be modified. + * Returns the User object for the given userName in the out parameter "acquiredUser". + * If the user cache already has a user object for this user, it increments the refcount + * on that object and gives out a pointer to it. If no user object for this user name + * exists yet in the cache, reads the user's privilege document from disk, builds up + * a User object, sets the refcount to 1, and gives that out. The returned user may + * be invalid by the time the caller gets access to it. + * The AuthorizationManager retains ownership of the returned User object. + * On non-OK Status return values, acquiredUser will not be modified. */ - Status acquireUserToRefreshSessionCache(OperationContext* opCtx, - const UserName& userName, - boost::optional<OID> id, - User** acquiredUser); + Status acquireUser(OperationContext* opCtx, const UserName& userName, User** acquiredUser); /** * Decrements the refcount of the given User object. If the refcount has gone to zero, @@ -425,8 +397,8 @@ private: /** * Cached value of the authorization schema version. * - * May be set by acquireUserForInitialAuth(), acquireUserToRefreshSessionCache(), - * and getAuthorizationVersion(). Invalidated by invalidateUserCache(). + * May be set by acquireUser() and getAuthorizationVersion(). Invalidated by + * invalidateUserCache(). * * Reads and writes guarded by CacheGuard. */ diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp index 1af1bec1f30..7eb3c980e3b 100644 --- a/src/mongo/db/auth/authorization_manager_test.cpp +++ b/src/mongo/db/auth/authorization_manager_test.cpp @@ -218,7 +218,7 @@ TEST_F(AuthorizationManagerTest, testAcquireV2User) { BSONObj())); User* v2read; - ASSERT_OK(authzManager->acquireUserForInitialAuth(&opCtx, UserName("v2read", "test"), &v2read)); + ASSERT_OK(authzManager->acquireUser(&opCtx, UserName("v2read", "test"), &v2read)); ASSERT_EQUALS(UserName("v2read", "test"), v2read->getName()); ASSERT(v2read->isValid()); ASSERT_EQUALS(1U, v2read->getRefCount()); @@ -232,8 +232,7 @@ TEST_F(AuthorizationManagerTest, testAcquireV2User) { authzManager->releaseUser(v2read); User* v2cluster; - ASSERT_OK(authzManager->acquireUserForInitialAuth( - &opCtx, UserName("v2cluster", "admin"), &v2cluster)); + ASSERT_OK(authzManager->acquireUser(&opCtx, UserName("v2cluster", "admin"), &v2cluster)); ASSERT_EQUALS(UserName("v2cluster", "admin"), v2cluster->getName()); ASSERT(v2cluster->isValid()); ASSERT_EQUALS(1U, v2cluster->getRefCount()); @@ -258,8 +257,8 @@ TEST_F(AuthorizationManagerTest, testLocalX509Authorization) { ServiceContext::UniqueOperationContext opCtx = client->makeOperationContext(); User* x509User; - ASSERT_OK(authzManager->acquireUserForInitialAuth( - opCtx.get(), UserName("CN=mongodb.com", "$external"), &x509User)); + ASSERT_OK( + authzManager->acquireUser(opCtx.get(), UserName("CN=mongodb.com", "$external"), &x509User)); ASSERT(x509User->isValid()); stdx::unordered_set<RoleName> expectedRoles{RoleName("read", "test"), @@ -292,8 +291,8 @@ TEST_F(AuthorizationManagerTest, testLocalX509AuthorizationInvalidUser) { ServiceContext::UniqueOperationContext opCtx = client->makeOperationContext(); User* x509User; - ASSERT_NOT_OK(authzManager->acquireUserForInitialAuth( - opCtx.get(), UserName("CN=10gen.com", "$external"), &x509User)); + ASSERT_NOT_OK( + authzManager->acquireUser(opCtx.get(), UserName("CN=10gen.com", "$external"), &x509User)); } TEST_F(AuthorizationManagerTest, testLocalX509AuthenticationNoAuthorization) { @@ -305,8 +304,8 @@ TEST_F(AuthorizationManagerTest, testLocalX509AuthenticationNoAuthorization) { ServiceContext::UniqueOperationContext opCtx = client->makeOperationContext(); User* x509User; - ASSERT_NOT_OK(authzManager->acquireUserForInitialAuth( - opCtx.get(), UserName("CN=mongodb.com", "$external"), &x509User)); + ASSERT_NOT_OK( + authzManager->acquireUser(opCtx.get(), UserName("CN=mongodb.com", "$external"), &x509User)); } /** @@ -404,7 +403,7 @@ TEST_F(AuthorizationManagerTest, testAcquireV2UserWithUnrecognizedActions) { BSONObj())); User* myUser; - ASSERT_OK(authzManager->acquireUserForInitialAuth(&opCtx, UserName("myUser", "test"), &myUser)); + ASSERT_OK(authzManager->acquireUser(&opCtx, UserName("myUser", "test"), &myUser)); ASSERT_EQUALS(UserName("myUser", "test"), myUser->getName()); ASSERT(myUser->isValid()); ASSERT_EQUALS(1U, myUser->getRefCount()); diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp index a29e1c2ff5e..4c72c4677e3 100644 --- a/src/mongo/db/auth/authorization_session.cpp +++ b/src/mongo/db/auth/authorization_session.cpp @@ -140,7 +140,7 @@ Status AuthorizationSession::addAndAuthorizeUser(OperationContext* opCtx, const UserName& userName) { User* user; AuthorizationManager* authzManager = AuthorizationManager::get(opCtx->getServiceContext()); - Status status = authzManager->acquireUserForInitialAuth(opCtx, userName, &user); + Status status = authzManager->acquireUser(opCtx, userName, &user); if (!status.isOK()) { return status; } @@ -797,9 +797,7 @@ void AuthorizationSession::_refreshUserInfoAsNeeded(OperationContext* opCtx) { UserName name = user->getName(); User* updatedUser; - Status status = - authMan.acquireUserToRefreshSessionCache(opCtx, name, user->getID(), &updatedUser); - + Status status = authMan.acquireUser(opCtx, name, &updatedUser); switch (status.code()) { case ErrorCodes::OK: { diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h index eccb2dcbbc3..7da7d21c9a1 100644 --- a/src/mongo/db/auth/authorization_session.h +++ b/src/mongo/db/auth/authorization_session.h @@ -305,12 +305,9 @@ protected: private: // 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. - // - // When refreshing a user document, we will use the current user's id to confirm that our - // user is of the same generation as the refreshed user document. If the generations don't - // match we will remove the outdated user document from the cache. void _refreshUserInfoAsNeeded(OperationContext* opCtx); + // 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 // lock on the admin database (to update out-of-date user privilege information). diff --git a/src/mongo/db/auth/sasl_plain_server_conversation.cpp b/src/mongo/db/auth/sasl_plain_server_conversation.cpp index 67ad4d52272..03b58dc1819 100644 --- a/src/mongo/db/auth/sasl_plain_server_conversation.cpp +++ b/src/mongo/db/auth/sasl_plain_server_conversation.cpp @@ -91,12 +91,11 @@ StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::st User* userObj; // The authentication database is also the source database for the user. - Status status = _saslAuthSession->getAuthorizationSession() - ->getAuthorizationManager() - .acquireUserForInitialAuth( - _saslAuthSession->getOpCtxt(), - UserName(_user, _saslAuthSession->getAuthenticationDatabase()), - &userObj); + Status status = + _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().acquireUser( + _saslAuthSession->getOpCtxt(), + UserName(_user, _saslAuthSession->getAuthenticationDatabase()), + &userObj); if (!status.isOK()) { return StatusWith<bool>(status); diff --git a/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp b/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp index 5ade83dc708..98469c1137d 100644 --- a/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp +++ b/src/mongo/db/auth/sasl_scramsha1_server_conversation.cpp @@ -168,9 +168,9 @@ StatusWith<bool> SaslSCRAMSHA1ServerConversation::_firstStep(std::vector<string> // The authentication database is also the source database for the user. User* userObj; - Status status = _saslAuthSession->getAuthorizationSession() - ->getAuthorizationManager() - .acquireUserForInitialAuth(_saslAuthSession->getOpCtxt(), user, &userObj); + Status status = + _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().acquireUser( + _saslAuthSession->getOpCtxt(), user, &userObj); if (!status.isOK()) { return StatusWith<bool>(status); diff --git a/src/mongo/db/auth/user.cpp b/src/mongo/db/auth/user.cpp index 36039d2ef14..698e78297fd 100644 --- a/src/mongo/db/auth/user.cpp +++ b/src/mongo/db/auth/user.cpp @@ -43,20 +43,15 @@ namespace mongo { namespace { -SHA256Block computeDigest(const UserName& name, const boost::optional<OID>& id) { +SHA256Block computeDigest(const UserName& name) { const auto& fn = name.getFullName(); - - if (id) { - return SHA256Block::computeHash({id->toCDR(), ConstDataRange(fn.c_str(), fn.size())}); - } else { - return SHA256Block::computeHash({ConstDataRange(fn.c_str(), fn.size())}); - } + return SHA256Block::computeHash({ConstDataRange(fn.c_str(), fn.size())}); }; } // namespace User::User(const UserName& name) - : _name(name), _id(), _digest(computeDigest(_name, _id)), _refCount(0), _isValid(1) {} + : _name(name), _digest(computeDigest(_name)), _refCount(0), _isValid(1) {} User::~User() { dassert(_refCount == 0); @@ -66,10 +61,6 @@ const UserName& User::getName() const { return _name; } -const boost::optional<OID>& User::getID() const { - return _id; -} - const SHA256Block& User::getDigest() const { return _digest; } @@ -106,11 +97,6 @@ const ActionSet User::getActionsForResource(const ResourcePattern& resource) con return it->second.getActions(); } -void User::setID(boost::optional<OID> id) { - _id = std::move(id); - _digest = computeDigest(_name, _id); -} - void User::setCredentials(const CredentialData& credentials) { _credentials = credentials; } diff --git a/src/mongo/db/auth/user.h b/src/mongo/db/auth/user.h index 7807043652d..8deead28046 100644 --- a/src/mongo/db/auth/user.h +++ b/src/mongo/db/auth/user.h @@ -31,8 +31,6 @@ #include <vector> #include "mongo/base/disallow_copying.h" -#include "mongo/bson/oid.h" -#include "mongo/crypto/sha256_block.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/auth/resource_pattern.h" #include "mongo/db/auth/restriction_set.h" @@ -89,11 +87,6 @@ public: const UserName& getName() const; /** - * Returns the user's id. - */ - const boost::optional<OID>& getID() const; - - /** * Returns a digest of the user's identity */ const SHA256Block& getDigest() const; @@ -146,11 +139,6 @@ public: // Mutators below. Mutation functions should *only* be called by the AuthorizationManager /** - * Set the id for this user. - */ - void setID(boost::optional<OID> id); - - /** * Sets this user's authentication credentials. */ void setCredentials(const CredentialData& credentials); @@ -232,12 +220,6 @@ public: private: UserName _name; - // An id for this user. We use this to identify different "generations" of the same username - // (ie a user "Lily" is dropped and then added). This field is optional to facilitate the - // upgrade path from 3.4 to 3.6. When comparing User documents' generations, we consider - // an unset _id field to be a distinct value that will fail to compare to any other id value. - boost::optional<OID> _id; - // Digest of the full username SHA256Block _digest; diff --git a/src/mongo/db/auth/user_document_parser.cpp b/src/mongo/db/auth/user_document_parser.cpp index 1b778ed4e17..aca408636a3 100644 --- a/src/mongo/db/auth/user_document_parser.cpp +++ b/src/mongo/db/auth/user_document_parser.cpp @@ -228,7 +228,6 @@ Status _checkV2RolesArray(const BSONElement& rolesElement) { Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const { BSONElement userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME]; - BSONElement userIDElement = doc[AuthorizationManager::USER_ID_FIELD_NAME]; BSONElement userDBElement = doc[AuthorizationManager::USER_DB_FIELD_NAME]; BSONElement credentialsElement = doc[CREDENTIALS_FIELD_NAME]; BSONElement rolesElement = doc[ROLES_FIELD_NAME]; @@ -239,11 +238,6 @@ Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const { if (userElement.valueStringData().empty()) return _badValue("User document needs 'user' field to be non-empty", 0); - // If we have an id field, make sure it is an OID - if (!userIDElement.eoo() && (userIDElement.type() != BSONType::jstOID)) { - return _badValue("User document 'userId' field must be an OID", 0); - } - // Validate the "db" element if (userDBElement.type() != String || userDBElement.valueStringData().empty()) { return _badValue("User document needs 'db' field to be a non-empty string", 0); @@ -317,15 +311,6 @@ std::string V2UserDocumentParser::extractUserNameFromUserDocument(const BSONObj& return doc[AuthorizationManager::USER_NAME_FIELD_NAME].str(); } -boost::optional<OID> V2UserDocumentParser::extractUserIDFromUserDocument(const BSONObj& doc) const { - BSONElement e = doc[AuthorizationManager::USER_ID_FIELD_NAME]; - if (e.type() == BSONType::EOO) { - return boost::optional<OID>(); - } - - return e.OID(); -} - Status V2UserDocumentParser::initializeUserCredentialsFromUserDocument( User* user, const BSONObj& privDoc) const { User::CredentialData credentials; diff --git a/src/mongo/db/auth/user_document_parser.h b/src/mongo/db/auth/user_document_parser.h index 2deb27d05e2..2e8aadc2a25 100644 --- a/src/mongo/db/auth/user_document_parser.h +++ b/src/mongo/db/auth/user_document_parser.h @@ -68,8 +68,6 @@ public: std::string extractUserNameFromUserDocument(const BSONObj& doc) const; - boost::optional<OID> extractUserIDFromUserDocument(const BSONObj& doc) const; - Status initializeUserCredentialsFromUserDocument(User* user, const BSONObj& privDoc) const; Status initializeUserRolesFromUserDocument(const BSONObj& doc, User* user) const; diff --git a/src/mongo/db/auth/user_document_parser_test.cpp b/src/mongo/db/auth/user_document_parser_test.cpp index ae27f0d0c6c..0ce0d378ea9 100644 --- a/src/mongo/db/auth/user_document_parser_test.cpp +++ b/src/mongo/db/auth/user_document_parser_test.cpp @@ -32,7 +32,6 @@ #include "mongo/platform/basic.h" #include "mongo/base/status.h" -#include "mongo/bson/oid.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_manager.h" @@ -260,32 +259,6 @@ TEST_F(V2UserDocumentParsing, V2DocumentValidation) { << "roles" << emptyArray))); - // Id field should be OID - ASSERT_OK(v2parser.checkValidUserDocument(BSON("user" - << "spencer" - << "userId" - << OID::gen() - << "db" - << "test" - << "credentials" - << BSON("MONGODB-CR" - << "a") - << "roles" - << emptyArray))); - - // Non-OID id fields are rejected - ASSERT_NOT_OK(v2parser.checkValidUserDocument(BSON("user" - << "spencer" - << "userId" - << "notAnOID" - << "db" - << "test" - << "credentials" - << BSON("MONGODB-CR" - << "a") - << "roles" - << emptyArray))); - // Need source field ASSERT_NOT_OK(v2parser.checkValidUserDocument(BSON("user" << "spencer" @@ -459,25 +432,6 @@ TEST_F(V2UserDocumentParsing, V2DocumentValidation) { << "dbA"))))); } -TEST_F(V2UserDocumentParsing, V2UserIDExtraction) { - OID oid = OID::gen(); - - // No id is present - ASSERT(!v2parser.extractUserIDFromUserDocument(BSON("user" - << "sam" - << "db" - << "test"))); - // Valid OID is present - auto res = v2parser.extractUserIDFromUserDocument(BSON("user" - << "sam" - << "userId" - << oid - << "db" - << "test")); - ASSERT(res); - ASSERT(res == oid); -} - TEST_F(V2UserDocumentParsing, V2CredentialExtraction) { // Old "pwd" field not valid ASSERT_NOT_OK(v2parser.initializeUserCredentialsFromUserDocument(user.get(), |