mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
SERVER-28190 Add internal tracking ids to users
This commit is contained in:
parent
e6d9d9722c
commit
02edad4ea3
@ -85,6 +85,7 @@ MONGO_INITIALIZER_WITH_PREREQUISITES(SetupInternalSecurityUser, MONGO_NO_PREREQU
|
||||
}
|
||||
|
||||
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";
|
||||
@ -384,6 +385,7 @@ 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 \""
|
||||
@ -394,6 +396,8 @@ Status AuthorizationManager::_initializeUserFromPrivilegeDocument(User* user,
|
||||
0);
|
||||
}
|
||||
|
||||
user->setID(parser.extractUserIDFromUserDocument(privDoc));
|
||||
|
||||
Status status = parser.initializeUserCredentialsFromUserDocument(user, privDoc);
|
||||
if (!status.isOK()) {
|
||||
return status;
|
||||
@ -444,9 +448,36 @@ Status AuthorizationManager::getRoleDescriptionsForDB(OperationContext* opCtx,
|
||||
opCtx, dbname, privileges, showBuiltinRoles, result);
|
||||
}
|
||||
|
||||
Status AuthorizationManager::acquireUser(OperationContext* opCtx,
|
||||
const UserName& userName,
|
||||
User** acquiredUser) {
|
||||
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) {
|
||||
if (userName == internalSecurity.user->getName()) {
|
||||
*acquiredUser = internalSecurity.user;
|
||||
return Status::OK();
|
||||
@ -513,6 +544,7 @@ Status AuthorizationManager::acquireUser(OperationContext* opCtx,
|
||||
|
||||
authzVersion = schemaVersionInvalid;
|
||||
}
|
||||
|
||||
if (!status.isOK())
|
||||
return status;
|
||||
|
||||
|
@ -31,6 +31,8 @@
|
||||
#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"
|
||||
@ -82,6 +84,7 @@ 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;
|
||||
@ -250,16 +253,41 @@ public:
|
||||
std::vector<BSONObj>* result);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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 acquireUser(OperationContext* opCtx, const UserName& userName, User** acquiredUser);
|
||||
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.
|
||||
*/
|
||||
Status acquireUserToRefreshSessionCache(OperationContext* opCtx,
|
||||
const UserName& userName,
|
||||
boost::optional<OID> id,
|
||||
User** acquiredUser);
|
||||
|
||||
/**
|
||||
* Decrements the refcount of the given User object. If the refcount has gone to zero,
|
||||
@ -372,8 +400,8 @@ private:
|
||||
/**
|
||||
* Cached value of the authorization schema version.
|
||||
*
|
||||
* May be set by acquireUser() and getAuthorizationVersion(). Invalidated by
|
||||
* invalidateUserCache().
|
||||
* May be set by acquireUserForInitialAuth(), acquireUserToRefreshSessionCache(),
|
||||
* and getAuthorizationVersion(). Invalidated by invalidateUserCache().
|
||||
*
|
||||
* Reads and writes guarded by CacheGuard.
|
||||
*/
|
||||
|
@ -218,7 +218,7 @@ TEST_F(AuthorizationManagerTest, testAcquireV2User) {
|
||||
BSONObj()));
|
||||
|
||||
User* v2read;
|
||||
ASSERT_OK(authzManager->acquireUser(&opCtx, UserName("v2read", "test"), &v2read));
|
||||
ASSERT_OK(authzManager->acquireUserForInitialAuth(&opCtx, UserName("v2read", "test"), &v2read));
|
||||
ASSERT_EQUALS(UserName("v2read", "test"), v2read->getName());
|
||||
ASSERT(v2read->isValid());
|
||||
ASSERT_EQUALS(1U, v2read->getRefCount());
|
||||
@ -232,7 +232,8 @@ TEST_F(AuthorizationManagerTest, testAcquireV2User) {
|
||||
authzManager->releaseUser(v2read);
|
||||
|
||||
User* v2cluster;
|
||||
ASSERT_OK(authzManager->acquireUser(&opCtx, UserName("v2cluster", "admin"), &v2cluster));
|
||||
ASSERT_OK(authzManager->acquireUserForInitialAuth(
|
||||
&opCtx, UserName("v2cluster", "admin"), &v2cluster));
|
||||
ASSERT_EQUALS(UserName("v2cluster", "admin"), v2cluster->getName());
|
||||
ASSERT(v2cluster->isValid());
|
||||
ASSERT_EQUALS(1U, v2cluster->getRefCount());
|
||||
@ -257,8 +258,8 @@ TEST_F(AuthorizationManagerTest, testLocalX509Authorization) {
|
||||
ServiceContext::UniqueOperationContext opCtx = client->makeOperationContext();
|
||||
|
||||
User* x509User;
|
||||
ASSERT_OK(
|
||||
authzManager->acquireUser(opCtx.get(), UserName("CN=mongodb.com", "$external"), &x509User));
|
||||
ASSERT_OK(authzManager->acquireUserForInitialAuth(
|
||||
opCtx.get(), UserName("CN=mongodb.com", "$external"), &x509User));
|
||||
ASSERT(x509User->isValid());
|
||||
|
||||
stdx::unordered_set<RoleName> expectedRoles{RoleName("read", "test"),
|
||||
@ -291,8 +292,8 @@ TEST_F(AuthorizationManagerTest, testLocalX509AuthorizationInvalidUser) {
|
||||
ServiceContext::UniqueOperationContext opCtx = client->makeOperationContext();
|
||||
|
||||
User* x509User;
|
||||
ASSERT_NOT_OK(
|
||||
authzManager->acquireUser(opCtx.get(), UserName("CN=10gen.com", "$external"), &x509User));
|
||||
ASSERT_NOT_OK(authzManager->acquireUserForInitialAuth(
|
||||
opCtx.get(), UserName("CN=10gen.com", "$external"), &x509User));
|
||||
}
|
||||
|
||||
TEST_F(AuthorizationManagerTest, testLocalX509AuthenticationNoAuthorization) {
|
||||
@ -304,8 +305,8 @@ TEST_F(AuthorizationManagerTest, testLocalX509AuthenticationNoAuthorization) {
|
||||
ServiceContext::UniqueOperationContext opCtx = client->makeOperationContext();
|
||||
|
||||
User* x509User;
|
||||
ASSERT_NOT_OK(
|
||||
authzManager->acquireUser(opCtx.get(), UserName("CN=mongodb.com", "$external"), &x509User));
|
||||
ASSERT_NOT_OK(authzManager->acquireUserForInitialAuth(
|
||||
opCtx.get(), UserName("CN=mongodb.com", "$external"), &x509User));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -403,7 +404,7 @@ TEST_F(AuthorizationManagerTest, testAcquireV2UserWithUnrecognizedActions) {
|
||||
BSONObj()));
|
||||
|
||||
User* myUser;
|
||||
ASSERT_OK(authzManager->acquireUser(&opCtx, UserName("myUser", "test"), &myUser));
|
||||
ASSERT_OK(authzManager->acquireUserForInitialAuth(&opCtx, UserName("myUser", "test"), &myUser));
|
||||
ASSERT_EQUALS(UserName("myUser", "test"), myUser->getName());
|
||||
ASSERT(myUser->isValid());
|
||||
ASSERT_EQUALS(1U, myUser->getRefCount());
|
||||
|
@ -104,7 +104,7 @@ void AuthorizationSession::startRequest(OperationContext* opCtx) {
|
||||
Status AuthorizationSession::addAndAuthorizeUser(OperationContext* opCtx,
|
||||
const UserName& userName) {
|
||||
User* user;
|
||||
Status status = getAuthorizationManager().acquireUser(opCtx, userName, &user);
|
||||
Status status = getAuthorizationManager().acquireUserForInitialAuth(opCtx, userName, &user);
|
||||
if (!status.isOK()) {
|
||||
return status;
|
||||
}
|
||||
@ -753,7 +753,9 @@ void AuthorizationSession::_refreshUserInfoAsNeeded(OperationContext* opCtx) {
|
||||
UserName name = user->getName();
|
||||
User* updatedUser;
|
||||
|
||||
Status status = authMan.acquireUser(opCtx, name, &updatedUser);
|
||||
Status status =
|
||||
authMan.acquireUserToRefreshSessionCache(opCtx, name, user->getID(), &updatedUser);
|
||||
|
||||
switch (status.code()) {
|
||||
case ErrorCodes::OK: {
|
||||
// Success! Replace the old User object with the updated one.
|
||||
|
@ -301,9 +301,12 @@ 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).
|
||||
|
@ -91,11 +91,12 @@ 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().acquireUser(
|
||||
_saslAuthSession->getOpCtxt(),
|
||||
UserName(_user, _saslAuthSession->getAuthenticationDatabase()),
|
||||
&userObj);
|
||||
Status status = _saslAuthSession->getAuthorizationSession()
|
||||
->getAuthorizationManager()
|
||||
.acquireUserForInitialAuth(
|
||||
_saslAuthSession->getOpCtxt(),
|
||||
UserName(_user, _saslAuthSession->getAuthenticationDatabase()),
|
||||
&userObj);
|
||||
|
||||
if (!status.isOK()) {
|
||||
return StatusWith<bool>(status);
|
||||
|
@ -164,9 +164,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().acquireUser(
|
||||
_saslAuthSession->getOpCtxt(), user, &userObj);
|
||||
Status status = _saslAuthSession->getAuthorizationSession()
|
||||
->getAuthorizationManager()
|
||||
.acquireUserForInitialAuth(_saslAuthSession->getOpCtxt(), user, &userObj);
|
||||
|
||||
if (!status.isOK()) {
|
||||
return StatusWith<bool>(status);
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
namespace mongo {
|
||||
|
||||
User::User(const UserName& name) : _name(name), _refCount(0), _isValid(1) {}
|
||||
User::User(const UserName& name) : _name(name), _id(), _refCount(0), _isValid(1) {}
|
||||
|
||||
User::~User() {
|
||||
dassert(_refCount == 0);
|
||||
@ -51,6 +51,10 @@ const UserName& User::getName() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
const boost::optional<OID>& User::getID() const {
|
||||
return _id;
|
||||
}
|
||||
|
||||
RoleNameIterator User::getRoles() const {
|
||||
return makeRoleNameIteratorForContainer(_roles);
|
||||
}
|
||||
@ -85,12 +89,17 @@ const ActionSet User::getActionsForResource(const ResourcePattern& resource) con
|
||||
|
||||
User* User::clone() const {
|
||||
std::unique_ptr<User> result(new User(_name));
|
||||
result->_id = _id;
|
||||
result->_privileges = _privileges;
|
||||
result->_roles = _roles;
|
||||
result->_credentials = _credentials;
|
||||
return result.release();
|
||||
}
|
||||
|
||||
void User::setID(boost::optional<OID> id) {
|
||||
_id = std::move(id);
|
||||
}
|
||||
|
||||
void User::setCredentials(const CredentialData& credentials) {
|
||||
_credentials = credentials;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "mongo/base/disallow_copying.h"
|
||||
#include "mongo/bson/oid.h"
|
||||
#include "mongo/db/auth/privilege.h"
|
||||
#include "mongo/db/auth/resource_pattern.h"
|
||||
#include "mongo/db/auth/role_name.h"
|
||||
@ -85,6 +86,11 @@ public:
|
||||
*/
|
||||
const UserName& getName() const;
|
||||
|
||||
/**
|
||||
* Returns the user's id.
|
||||
*/
|
||||
const boost::optional<OID>& getID() const;
|
||||
|
||||
/**
|
||||
* Returns an iterator over the names of the user's direct roles
|
||||
*/
|
||||
@ -137,6 +143,11 @@ 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.
|
||||
*/
|
||||
@ -206,6 +217,12 @@ 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;
|
||||
|
||||
// Maps resource name to privilege on that resource
|
||||
ResourcePrivilegeMap _privileges;
|
||||
|
||||
|
@ -223,6 +223,7 @@ 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];
|
||||
@ -233,6 +234,11 @@ 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);
|
||||
@ -300,6 +306,15 @@ 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;
|
||||
|
@ -68,6 +68,8 @@ 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;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#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"
|
||||
@ -255,6 +256,32 @@ 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"
|
||||
@ -388,6 +415,25 @@ 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(),
|
||||
|
@ -263,7 +263,8 @@ Status CmdAuthenticate::_authenticateCR(OperationContext* opCtx,
|
||||
}
|
||||
|
||||
User* userObj;
|
||||
Status status = getGlobalAuthorizationManager()->acquireUser(opCtx, user, &userObj);
|
||||
Status status =
|
||||
getGlobalAuthorizationManager()->acquireUserForInitialAuth(opCtx, user, &userObj);
|
||||
if (!status.isOK()) {
|
||||
// Failure to find the privilege document indicates no-such-user, a fact that we do not
|
||||
// wish to reveal to the client. So, we return AuthenticationFailed rather than passing
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "mongo/bson/mutable/algorithm.h"
|
||||
#include "mongo/bson/mutable/document.h"
|
||||
#include "mongo/bson/mutable/element.h"
|
||||
#include "mongo/bson/oid.h"
|
||||
#include "mongo/bson/util/bson_extract.h"
|
||||
#include "mongo/client/dbclientinterface.h"
|
||||
#include "mongo/config.h"
|
||||
@ -141,7 +142,7 @@ Status getCurrentUserRoles(OperationContext* opCtx,
|
||||
unordered_set<RoleName>* roles) {
|
||||
User* user;
|
||||
authzManager->invalidateUserByName(userName); // Need to make sure cache entry is up to date
|
||||
Status status = authzManager->acquireUser(opCtx, userName, &user);
|
||||
Status status = authzManager->acquireUserForInitialAuth(opCtx, userName, &user);
|
||||
if (!status.isOK()) {
|
||||
return status;
|
||||
}
|
||||
@ -668,6 +669,7 @@ public:
|
||||
userObjBuilder.append(
|
||||
"_id", str::stream() << args.userName.getDB() << "." << args.userName.getUser());
|
||||
userObjBuilder.append(AuthorizationManager::USER_NAME_FIELD_NAME, args.userName.getUser());
|
||||
userObjBuilder.append(AuthorizationManager::USER_ID_FIELD_NAME, OID::gen());
|
||||
userObjBuilder.append(AuthorizationManager::USER_DB_FIELD_NAME, args.userName.getDB());
|
||||
|
||||
ServiceContext* serviceContext = opCtx->getClient()->getServiceContext();
|
||||
@ -1197,7 +1199,8 @@ public:
|
||||
BSONObjBuilder userWithoutCredentials(usersArrayBuilder.subobjStart());
|
||||
for (BSONObjIterator it(userDetails); it.more();) {
|
||||
BSONElement e = it.next();
|
||||
if (e.fieldNameStringData() != "credentials")
|
||||
if (e.fieldNameStringData() != "credentials" &&
|
||||
e.fieldNameStringData() != AuthorizationManager::USER_ID_FIELD_NAME)
|
||||
userWithoutCredentials.append(e);
|
||||
}
|
||||
userWithoutCredentials.doneFast();
|
||||
@ -1224,16 +1227,17 @@ public:
|
||||
// Order results by user field then db field, matching how UserNames are ordered
|
||||
queryBuilder.append("orderby", BSON("user" << 1 << "db" << 1));
|
||||
|
||||
BSONObj projection;
|
||||
BSONObjBuilder projection;
|
||||
if (!args.showCredentials) {
|
||||
projection = BSON("credentials" << 0);
|
||||
projection.append(AuthorizationManager::USER_ID_FIELD_NAME, 0);
|
||||
projection.append("credentials", 0);
|
||||
}
|
||||
const stdx::function<void(const BSONObj&)> function = stdx::bind(
|
||||
appendBSONObjToBSONArrayBuilder, &usersArrayBuilder, stdx::placeholders::_1);
|
||||
queryAuthzDocument(opCtx,
|
||||
AuthorizationManager::usersCollectionNamespace,
|
||||
queryBuilder.done(),
|
||||
projection,
|
||||
projection.done(),
|
||||
function);
|
||||
}
|
||||
result.append("users", usersArrayBuilder.arr());
|
||||
|
Loading…
Reference in New Issue
Block a user