summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/bson/bsonelement.h10
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp1
-rw-r--r--src/mongo/db/auth/authorization_manager.h8
-rw-r--r--src/mongo/db/auth/authorization_manager_impl.cpp19
-rw-r--r--src/mongo/db/auth/authorization_manager_impl.h3
-rw-r--r--src/mongo/db/auth/authorization_session_impl.cpp2
-rw-r--r--src/mongo/db/auth/user.h13
-rw-r--r--src/mongo/db/auth/user_document_parser.cpp28
-rw-r--r--src/mongo/db/auth/user_document_parser.h1
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp2
-rw-r--r--src/mongo/embedded/embedded_auth_manager.cpp6
11 files changed, 86 insertions, 7 deletions
diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h
index e9e19fd0584..a42f993c4a5 100644
--- a/src/mongo/bson/bsonelement.h
+++ b/src/mongo/bson/bsonelement.h
@@ -614,11 +614,16 @@ public:
return Timestamp();
}
+ bool isBinData(BinDataType bdt) const {
+ return (type() == BinData) && (binDataType() == bdt);
+ }
+
const std::array<unsigned char, 16> uuid() const {
int len = 0;
const char* data = nullptr;
- if (type() == BinData && binDataType() == BinDataType::newUUID)
+ if (isBinData(BinDataType::newUUID)) {
data = binData(len);
+ }
uassert(ErrorCodes::InvalidUUID,
"uuid must be a 16-byte binary field with UUID (4) subtype",
len == 16);
@@ -630,8 +635,9 @@ public:
const std::array<unsigned char, 16> md5() const {
int len = 0;
const char* data = nullptr;
- if (type() == BinData && binDataType() == BinDataType::MD5Type)
+ if (isBinData(BinDataType::MD5Type)) {
data = binData(len);
+ }
uassert(40437, "md5 must be a 16-byte binary field with MD5 (5) subtype", len == 16);
std::array<unsigned char, 16> result;
memcpy(&result, data, len);
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp
index 6bbb5f486dc..9d9575c1a08 100644
--- a/src/mongo/db/auth/authorization_manager.cpp
+++ b/src/mongo/db/auth/authorization_manager.cpp
@@ -68,6 +68,7 @@ mongo::AuthInfo mongo::internalSecurity;
namespace mongo {
+constexpr StringData AuthorizationManager::USERID_FIELD_NAME;
constexpr StringData AuthorizationManager::USER_NAME_FIELD_NAME;
constexpr StringData AuthorizationManager::USER_DB_FIELD_NAME;
constexpr StringData AuthorizationManager::ROLE_NAME_FIELD_NAME;
diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h
index f9cd1248d4b..1ec9f421a4c 100644
--- a/src/mongo/db/auth/authorization_manager.h
+++ b/src/mongo/db/auth/authorization_manager.h
@@ -99,6 +99,7 @@ public:
static MONGO_DECLARE_SHIM(()->std::unique_ptr<AuthorizationManager>) create;
+ static constexpr StringData USERID_FIELD_NAME = "userId"_sd;
static constexpr StringData USER_NAME_FIELD_NAME = "user"_sd;
static constexpr StringData USER_DB_FIELD_NAME = "db"_sd;
static constexpr StringData ROLE_NAME_FIELD_NAME = "role"_sd;
@@ -267,6 +268,13 @@ public:
const UserName& userName) = 0;
/**
+ * Validate the ID associated with a known user while refreshing session cache.
+ */
+ virtual StatusWith<UserHandle> acquireUserForSessionRefresh(OperationContext* opCtx,
+ const UserName& userName,
+ const User::UserId& uid) = 0;
+
+ /**
* Marks the given user as invalid and removes it from the user cache.
*/
virtual void invalidateUserByName(OperationContext* opCtx, const UserName& user) = 0;
diff --git a/src/mongo/db/auth/authorization_manager_impl.cpp b/src/mongo/db/auth/authorization_manager_impl.cpp
index 93ce163d6c6..5230d3b03b4 100644
--- a/src/mongo/db/auth/authorization_manager_impl.cpp
+++ b/src/mongo/db/auth/authorization_manager_impl.cpp
@@ -456,6 +456,8 @@ Status AuthorizationManagerImpl::_initializeUserFromPrivilegeDocument(User* user
<< "\"");
}
+ user->setID(parser.extractUserIDFromUserDocument(privDoc));
+
Status status = parser.initializeUserCredentialsFromUserDocument(user, privDoc);
if (!status.isOK()) {
return status;
@@ -576,6 +578,23 @@ StatusWith<UserHandle> AuthorizationManagerImpl::acquireUser(OperationContext* o
return user;
}
+StatusWith<UserHandle> AuthorizationManagerImpl::acquireUserForSessionRefresh(
+ OperationContext* opCtx, const UserName& userName, const User::UserId& uid) {
+ auto swUserHandle = acquireUser(opCtx, userName);
+ if (!swUserHandle.isOK()) {
+ return swUserHandle.getStatus();
+ }
+
+ auto ret = std::move(swUserHandle.getValue());
+ if (uid != ret->getID()) {
+ return {ErrorCodes::UserNotFound,
+ str::stream() << "User id from privilege document '" << userName.toString()
+ << "' does not match user id in session."};
+ }
+
+ return ret;
+}
+
StatusWith<UserHandle> AuthorizationManagerImpl::_acquireUserSlowPath(CacheGuard& guard,
OperationContext* opCtx,
const UserName& userName) {
diff --git a/src/mongo/db/auth/authorization_manager_impl.h b/src/mongo/db/auth/authorization_manager_impl.h
index 80f052338ff..66f088b69b6 100644
--- a/src/mongo/db/auth/authorization_manager_impl.h
+++ b/src/mongo/db/auth/authorization_manager_impl.h
@@ -118,6 +118,9 @@ public:
std::vector<BSONObj>* result) override;
StatusWith<UserHandle> acquireUser(OperationContext* opCtx, const UserName& userName) override;
+ StatusWith<UserHandle> acquireUserForSessionRefresh(OperationContext* opCtx,
+ const UserName& userName,
+ const User::UserId& uid) override;
void invalidateUserByName(OperationContext* opCtx, const UserName& user) override;
diff --git a/src/mongo/db/auth/authorization_session_impl.cpp b/src/mongo/db/auth/authorization_session_impl.cpp
index 4bd6f2dd62c..65e7558a7f5 100644
--- a/src/mongo/db/auth/authorization_session_impl.cpp
+++ b/src/mongo/db/auth/authorization_session_impl.cpp
@@ -729,7 +729,7 @@ void AuthorizationSessionImpl::_refreshUserInfoAsNeeded(OperationContext* opCtx)
UserName name = user->getName();
UserHandle updatedUser;
- auto swUser = authMan.acquireUser(opCtx, name);
+ auto swUser = authMan.acquireUserForSessionRefresh(opCtx, name, user->getID());
auto& status = swUser.getStatus();
switch (status.code()) {
case ErrorCodes::OK: {
diff --git a/src/mongo/db/auth/user.h b/src/mongo/db/auth/user.h
index 715b849fe9b..5b3edfb767f 100644
--- a/src/mongo/db/auth/user.h
+++ b/src/mongo/db/auth/user.h
@@ -104,6 +104,15 @@ public:
explicit User(const UserName& name);
+ using UserId = std::vector<std::uint8_t>;
+ const UserId& getID() const {
+ return _id;
+ }
+
+ void setID(UserId id) {
+ _id = std::move(id);
+ }
+
/**
* Returns the user name for this user.
*/
@@ -230,6 +239,10 @@ protected:
void _invalidate();
private:
+ // Unique ID (often UUID) for this user.
+ // May be empty for legacy users.
+ UserId _id;
+
UserName _name;
// Digest of the full username
diff --git a/src/mongo/db/auth/user_document_parser.cpp b/src/mongo/db/auth/user_document_parser.cpp
index 0cbed973483..552898b8552 100644
--- a/src/mongo/db/auth/user_document_parser.cpp
+++ b/src/mongo/db/auth/user_document_parser.cpp
@@ -127,10 +127,18 @@ Status _checkV2RolesArray(const BSONElement& rolesElement) {
}
Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const {
- BSONElement userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME];
- BSONElement userDBElement = doc[AuthorizationManager::USER_DB_FIELD_NAME];
- BSONElement credentialsElement = doc[CREDENTIALS_FIELD_NAME];
- BSONElement rolesElement = doc[ROLES_FIELD_NAME];
+ auto userIdElement = doc[AuthorizationManager::USERID_FIELD_NAME];
+ auto userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME];
+ auto userDBElement = doc[AuthorizationManager::USER_DB_FIELD_NAME];
+ auto credentialsElement = doc[CREDENTIALS_FIELD_NAME];
+ auto rolesElement = doc[ROLES_FIELD_NAME];
+
+ // Validate the "userId" element.
+ if (!userIdElement.eoo()) {
+ if (!userIdElement.isBinData(BinDataType::newUUID)) {
+ return _badValue("User document needs 'userId' field to be a UUID");
+ }
+ }
// Validate the "user" element.
if (userElement.type() != String)
@@ -213,6 +221,18 @@ Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const {
return Status::OK();
}
+User::UserId V2UserDocumentParser::extractUserIDFromUserDocument(const BSONObj& doc) const {
+ auto userId = doc[AuthorizationManager::USERID_FIELD_NAME];
+ if (userId.isBinData(BinDataType::newUUID)) {
+ auto id = userId.uuid();
+ User::UserId ret;
+ std::copy(id.begin(), id.end(), std::back_inserter(ret));
+ return ret;
+ }
+
+ return User::UserId();
+}
+
std::string V2UserDocumentParser::extractUserNameFromUserDocument(const BSONObj& doc) const {
return doc[AuthorizationManager::USER_NAME_FIELD_NAME].str();
}
diff --git a/src/mongo/db/auth/user_document_parser.h b/src/mongo/db/auth/user_document_parser.h
index a1349104224..7493ce7d324 100644
--- a/src/mongo/db/auth/user_document_parser.h
+++ b/src/mongo/db/auth/user_document_parser.h
@@ -54,6 +54,7 @@ public:
static Status parseRoleVector(const BSONArray& rolesArray, std::vector<RoleName>* result);
std::string extractUserNameFromUserDocument(const BSONObj& doc) const;
+ User::UserId extractUserIDFromUserDocument(const BSONObj& doc) const;
Status initializeUserCredentialsFromUserDocument(User* user, const BSONObj& privDoc) const;
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index 3c83c58fbf0..3520097a5c3 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -78,6 +78,7 @@
#include "mongo/util/password_digest.h"
#include "mongo/util/sequence_util.h"
#include "mongo/util/time_support.h"
+#include "mongo/util/uuid.h"
namespace mongo {
@@ -828,6 +829,7 @@ public:
BSONObjBuilder userObjBuilder;
userObjBuilder.append(
"_id", str::stream() << args.userName.getDB() << "." << args.userName.getUser());
+ UUID::gen().appendToBuilder(&userObjBuilder, AuthorizationManager::USERID_FIELD_NAME);
userObjBuilder.append(AuthorizationManager::USER_NAME_FIELD_NAME, args.userName.getUser());
userObjBuilder.append(AuthorizationManager::USER_DB_FIELD_NAME, args.userName.getDB());
diff --git a/src/mongo/embedded/embedded_auth_manager.cpp b/src/mongo/embedded/embedded_auth_manager.cpp
index 50841d42762..dc3a3ffd1eb 100644
--- a/src/mongo/embedded/embedded_auth_manager.cpp
+++ b/src/mongo/embedded/embedded_auth_manager.cpp
@@ -102,6 +102,12 @@ public:
UASSERT_NOT_IMPLEMENTED;
}
+ StatusWith<UserHandle> acquireUserForSessionRefresh(OperationContext*,
+ const UserName&,
+ const User::UserId&) override {
+ UASSERT_NOT_IMPLEMENTED;
+ }
+
void invalidateUserByName(OperationContext*, const UserName& user) override {
UASSERT_NOT_IMPLEMENTED;
}