summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorSophia Tan <sophia_tll@hotmail.com>2022-01-20 19:18:49 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-01-20 21:36:30 +0000
commit0f90f936d206032693578db712376489619c0d62 (patch)
tree8b6f973a9dcfeff7d39ffddb2441e43d3873a43f /src/mongo
parent08aa07493315218bb47578ec77c94f2d728fb347 (diff)
downloadmongo-0f90f936d206032693578db712376489619c0d62.tar.gz
SERVER-62441 Define a new type mongo::TenantId for tenant id
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/SConscript5
-rw-r--r--src/mongo/db/auth/SConscript1
-rw-r--r--src/mongo/db/auth/auth_identifier_test.cpp12
-rw-r--r--src/mongo/db/auth/auth_name.cpp18
-rw-r--r--src/mongo/db/auth/auth_name.h22
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.cpp27
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.h5
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.h2
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_s.cpp2
-rw-r--r--src/mongo/db/auth/security_token.cpp4
-rw-r--r--src/mongo/db/auth/user_document_parser.h6
-rw-r--r--src/mongo/db/commands/user_management_commands.cpp5
-rw-r--r--src/mongo/db/commands/user_management_commands.idl3
-rw-r--r--src/mongo/db/dollar_tenant_decoration_test.cpp14
-rw-r--r--src/mongo/db/multitenancy.cpp13
-rw-r--r--src/mongo/db/multitenancy.h15
-rw-r--r--src/mongo/db/multitenancy.idl10
-rw-r--r--src/mongo/db/tenant_database_name.h7
-rw-r--r--src/mongo/db/tenant_database_name_test.cpp18
-rw-r--r--src/mongo/db/tenant_id.cpp70
-rw-r--r--src/mongo/db/tenant_id.h152
-rw-r--r--src/mongo/db/tenant_namespace.cpp4
-rw-r--r--src/mongo/db/tenant_namespace.h9
-rw-r--r--src/mongo/db/tenant_namespace_test.cpp8
-rw-r--r--src/mongo/logv2/SConscript1
-rw-r--r--src/mongo/logv2/bson_formatter.cpp5
-rw-r--r--src/mongo/logv2/json_formatter.cpp4
-rw-r--r--src/mongo/logv2/json_formatter.h4
-rw-r--r--src/mongo/logv2/log_detail.cpp3
-rw-r--r--src/mongo/logv2/log_detail.h4
-rw-r--r--src/mongo/logv2/logv2_test.cpp12
-rw-r--r--src/mongo/rpc/metadata/security_token_metadata_test.cpp9
32 files changed, 356 insertions, 118 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index b90571ed322..f5558891fe1 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -86,11 +86,11 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
- 'auth/auth',
- 'auth/security_token',
'multitenancy_params',
],
LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/db/auth/auth',
+ '$BUILD_DIR/mongo/db/auth/security_token',
'$BUILD_DIR/mongo/idl/feature_flag',
'namespace_string',
'server_feature_flags',
@@ -279,6 +279,7 @@ env.Library(
target='multitenancy_params',
source=[
'multitenancy.idl',
+ 'tenant_id.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index efaa8d533d3..57af14b709d 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -48,6 +48,7 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/multitenancy_params',
'$BUILD_DIR/mongo/db/service_context',
],
LIBDEPS_PRIVATE=[
diff --git a/src/mongo/db/auth/auth_identifier_test.cpp b/src/mongo/db/auth/auth_identifier_test.cpp
index 55d6fc98a25..0fa86167825 100644
--- a/src/mongo/db/auth/auth_identifier_test.cpp
+++ b/src/mongo/db/auth/auth_identifier_test.cpp
@@ -41,6 +41,7 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/db/auth/role_name.h"
#include "mongo/db/auth/user_name.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -65,7 +66,7 @@ template <typename T, typename Name, typename Db>
void checkValueAssertions(const T& obj,
Name name,
Db db,
- const boost::optional<OID>& tenant = boost::none) {
+ const boost::optional<TenantId>& tenant = boost::none) {
const bool expectEmpty = StringData(name).empty() && StringData(db).empty() && !tenant;
ASSERT_EQ(obj.empty(), expectEmpty);
@@ -112,14 +113,15 @@ TEST(AuthName, ConstructorTest) {
template <typename T, typename Name, typename Db>
void doBSONParseTest(Name name, Db db) {
- // Without TenantID.
+ // Without TenantId.
auto obj = BSON(T::kFieldName << name << "db" << db);
checkValueAssertions(T::parseFromBSON(BSON("" << obj).firstElement()), name, db);
checkValueAssertions(T::parseFromBSONObj(obj), name, db);
- // With TenantID.
- const auto tenant = OID::gen();
- auto tobj = BSON(T::kFieldName << name << "db" << db << "tenant" << tenant);
+ // With TenantId.
+ auto oid = OID::gen();
+ auto tenant = TenantId(oid);
+ auto tobj = BSON(T::kFieldName << name << "db" << db << "tenant" << oid);
checkValueAssertions(T::parseFromBSON(BSON("" << tobj).firstElement()), name, db, tenant);
checkValueAssertions(T::parseFromBSONObj(tobj), name, db, tenant);
}
diff --git a/src/mongo/db/auth/auth_name.cpp b/src/mongo/db/auth/auth_name.cpp
index acde60ea5c1..4b8116b23e8 100644
--- a/src/mongo/db/auth/auth_name.cpp
+++ b/src/mongo/db/auth/auth_name.cpp
@@ -38,7 +38,7 @@ constexpr auto kTenantFieldName = "tenant"_sd;
} // namespace
template <typename T>
-StatusWith<T> AuthName<T>::parse(StringData str, const boost::optional<OID>& tenant) {
+StatusWith<T> AuthName<T>::parse(StringData str, const boost::optional<TenantId>& tenant) {
auto split = str.find('.');
if (split == std::string::npos) {
@@ -52,7 +52,7 @@ StatusWith<T> AuthName<T>::parse(StringData str, const boost::optional<OID>& ten
template <typename T>
T AuthName<T>::parseFromVariant(const stdx::variant<std::string, BSONObj>& name,
- const boost::optional<OID>& tenant) {
+ const boost::optional<TenantId>& tenant) {
if (stdx::holds_alternative<std::string>(name)) {
return uassertStatusOK(parse(stdx::get<std::string>(name)));
}
@@ -61,19 +61,20 @@ T AuthName<T>::parseFromVariant(const stdx::variant<std::string, BSONObj>& name,
}
template <typename T>
-T AuthName<T>::parseFromBSONObj(const BSONObj& obj, const boost::optional<OID>& activeTenant) {
+T AuthName<T>::parseFromBSONObj(const BSONObj& obj, const boost::optional<TenantId>& activeTenant) {
std::bitset<3> usedFields;
constexpr size_t kNameFieldBit = 0;
constexpr size_t kDbFieldBit = 1;
constexpr size_t kTenantFieldBit = 2;
StringData name, db;
- boost::optional<OID> tenant = activeTenant;
+ boost::optional<TenantId> tenant = activeTenant;
const auto validateField = [&](const BSONElement& elem, const size_t bit, BSONType expType) {
const auto fieldName = elem.fieldNameStringData();
uassert(ErrorCodes::BadValue,
str::stream() << T::kName << " must contain a " << typeName(expType)
- << " field named: " << fieldName,
+ << " field named: " << fieldName << ". But, has type "
+ << typeName(elem.type()),
elem.type() == expType);
uassert(ErrorCodes::BadValue,
str::stream() << T::kName << " has more than one field named: " << fieldName,
@@ -94,12 +95,12 @@ T AuthName<T>::parseFromBSONObj(const BSONObj& obj, const boost::optional<OID>&
} else if (fieldName == kTenantFieldName) {
validateField(element, kTenantFieldBit, jstOID);
- tenant = element.OID();
+ tenant = TenantId::parseFromBSON(element);
if (activeTenant) {
uassert(ErrorCodes::BadValue,
str::stream()
<< T::kName
- << " contains a TenantID which does not match the active tenant",
+ << " contains a TenantId which does not match the active tenant",
tenant == activeTenant);
}
@@ -123,7 +124,8 @@ T AuthName<T>::parseFromBSONObj(const BSONObj& obj, const boost::optional<OID>&
}
template <typename T>
-T AuthName<T>::parseFromBSON(const BSONElement& elem, const boost::optional<OID>& activeTenant) {
+T AuthName<T>::parseFromBSON(const BSONElement& elem,
+ const boost::optional<TenantId>& activeTenant) {
if (elem.type() == String) {
return uassertStatusOK(parse(elem.valueStringData(), activeTenant));
} else if (elem.type() == Object) {
diff --git a/src/mongo/db/auth/auth_name.h b/src/mongo/db/auth/auth_name.h
index db6027e53d2..62fd1d6fa8e 100644
--- a/src/mongo/db/auth/auth_name.h
+++ b/src/mongo/db/auth/auth_name.h
@@ -39,7 +39,7 @@
#include "mongo/base/string_data.h"
#include "mongo/bson/bsonelement.h"
#include "mongo/bson/bsonobjbuilder.h"
-#include "mongo/bson/oid.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/stdx/variant.h"
namespace mongo {
@@ -55,7 +55,7 @@ public:
AuthName() = default;
template <typename Name, typename DB>
- AuthName(Name name, DB db, boost::optional<OID> tenant = boost::none) {
+ AuthName(Name name, DB db, boost::optional<TenantId> tenant = boost::none) {
if constexpr (std::is_same_v<Name, std::string>) {
_name = std::move(name);
} else {
@@ -74,16 +74,18 @@ public:
/**
* Parses a string of the form "db.name" into an AuthName object with an optional tenant.
*/
- static StatusWith<T> parse(StringData str, const boost::optional<OID>& tenant = boost::none);
+ static StatusWith<T> parse(StringData str,
+ const boost::optional<TenantId>& tenant = boost::none);
/**
* These methods support parsing usernames from IDL
*/
static T parseFromVariant(const stdx::variant<std::string, mongo::BSONObj>& name,
- const boost::optional<OID>& tenant = boost::none);
- static T parseFromBSONObj(const BSONObj& obj, const boost::optional<OID>& tenant = boost::none);
+ const boost::optional<TenantId>& tenant = boost::none);
+ static T parseFromBSONObj(const BSONObj& obj,
+ const boost::optional<TenantId>& tenant = boost::none);
static T parseFromBSON(const BSONElement& elem,
- const boost::optional<OID>& tenant = boost::none);
+ const boost::optional<TenantId>& tenant = boost::none);
void serializeToBSON(StringData fieldName, BSONObjBuilder* bob) const;
void serializeToBSON(BSONArrayBuilder* bob) const;
void appendToBSON(BSONObjBuilder* bob, bool encodeTenant = false) const;
@@ -104,9 +106,9 @@ public:
}
/**
- * Gets the TenantID, if any, associated with this AuthName.
+ * Gets the TenantId, if any, associated with this AuthName.
*/
- const boost::optional<OID>& getTenant() const {
+ const boost::optional<TenantId>& getTenant() const {
return _tenant;
}
@@ -169,7 +171,7 @@ public:
friend H AbslHashValue(H h, const AuthName& name) {
auto state = std::move(h);
if (name._tenant) {
- state = H::combine(std::move(state), OID::Hasher()(name._tenant.get()), '_');
+ state = H::combine(std::move(state), TenantId::Hasher()(name._tenant.get()), '_');
}
return H::combine(std::move(state), name._db, '.', name._name);
}
@@ -177,7 +179,7 @@ public:
private:
std::string _name;
std::string _db;
- boost::optional<OID> _tenant;
+ boost::optional<TenantId> _tenant;
};
template <typename Stream, typename T>
diff --git a/src/mongo/db/auth/authz_manager_external_state_local.cpp b/src/mongo/db/auth/authz_manager_external_state_local.cpp
index 63a06bcdfde..de11d9f7f87 100644
--- a/src/mongo/db/auth/authz_manager_external_state_local.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp
@@ -44,6 +44,7 @@
#include "mongo/db/operation_context.h"
#include "mongo/db/server_options.h"
#include "mongo/db/storage/snapshot_manager.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/log.h"
#include "mongo/util/duration.h"
#include "mongo/util/fail_point.h"
@@ -92,7 +93,7 @@ namespace {
// Temporary placeholder pending availability of NamespaceWithTenant.
NamespaceString getNamespaceWithTenant(const NamespaceString& nss,
- const boost::optional<OID>& tenant) {
+ const boost::optional<TenantId>& tenant) {
if (tenant) {
return NamespaceString(str::stream() << tenant.get() << '_' << nss.db(), nss.coll());
} else {
@@ -100,11 +101,11 @@ NamespaceString getNamespaceWithTenant(const NamespaceString& nss,
}
}
-NamespaceString getUsersCollection(const boost::optional<OID>& tenant) {
+NamespaceString getUsersCollection(const boost::optional<TenantId>& tenant) {
return getNamespaceWithTenant(AuthorizationManager::usersCollectionNamespace, tenant);
}
-NamespaceString getRolesCollection(const boost::optional<OID>& tenant) {
+NamespaceString getRolesCollection(const boost::optional<TenantId>& tenant) {
return getNamespaceWithTenant(AuthorizationManager::rolesCollectionNamespace, tenant);
}
@@ -273,7 +274,7 @@ bool AuthzManagerExternalStateLocal::hasAnyPrivilegeDocuments(OperationContext*
}
AuthzManagerExternalStateLocal::RolesLocks::RolesLocks(OperationContext* opCtx,
- const boost::optional<OID>& tenant) {
+ const boost::optional<TenantId>& tenant) {
if (!storageGlobalParams.disableLockFreeReads) {
_readLockFree = std::make_unique<AutoReadLockFree>(opCtx);
} else {
@@ -291,7 +292,7 @@ AuthzManagerExternalStateLocal::RolesLocks::~RolesLocks() {
}
AuthzManagerExternalStateLocal::RolesLocks AuthzManagerExternalStateLocal::_lockRoles(
- OperationContext* opCtx, const boost::optional<OID>& tenant) {
+ OperationContext* opCtx, const boost::optional<TenantId>& tenant) {
return AuthzManagerExternalStateLocal::RolesLocks(opCtx, tenant);
}
@@ -318,7 +319,7 @@ StatusWith<User> AuthzManagerExternalStateLocal::getUserObject(OperationContext*
}
V2UserDocumentParser userDocParser;
- userDocParser.setTenantID(userReq.name.getTenant());
+ userDocParser.setTenantId(userReq.name.getTenant());
uassertStatusOK(userDocParser.initializeUserFromUserDocument(userDoc, &user));
for (auto iter = user.getRoles(); iter.more();) {
directRoles.push_back(iter.next());
@@ -775,18 +776,18 @@ public:
return _type;
}
- const boost::optional<OID>& getTenant() const {
+ const boost::optional<TenantId>& getTenant() const {
return _tenant;
}
private:
/**
- * Attempt to parse "{tenant}_admin" into an OID.
+ * Attempt to parse "{tenant}_admin" into a Tenant ID.
* Returns boost::none if the db is not in the above format.
*
* Temporary fixture pending availability of NamespaceWithTenant.
*/
- static boost::optional<OID> isAdminDBWithTenant(StringData db) {
+ static boost::optional<TenantId> isAdminDBWithTenant(StringData db) {
constexpr std::size_t len =
(OID::kOIDSize * 2) + 1 /* '_' */ + NamespaceString::kAdminDb.size();
if (db.size() != len) {
@@ -804,17 +805,17 @@ private:
return boost::none;
}
- auto swTenant = OID::parse(db.substr(0, OID::kOIDSize * 2));
- if (!swTenant.isOK()) {
+ auto swOID = OID::parse(db.substr(0, OID::kOIDSize * 2));
+ if (!swOID.isOK()) {
// Not a valid OID
return boost::none;
}
- return swTenant.getValue();
+ return TenantId(swOID.getValue());
}
AuthzCollectionType _type = AuthzCollectionType::kNone;
- boost::optional<OID> _tenant;
+ boost::optional<TenantId> _tenant;
};
constexpr auto kOpInsert = "i"_sd;
diff --git a/src/mongo/db/auth/authz_manager_external_state_local.h b/src/mongo/db/auth/authz_manager_external_state_local.h
index dea8bd7228c..2d6ae65b235 100644
--- a/src/mongo/db/auth/authz_manager_external_state_local.h
+++ b/src/mongo/db/auth/authz_manager_external_state_local.h
@@ -39,6 +39,7 @@
#include "mongo/db/auth/user_name.h"
#include "mongo/db/concurrency/d_concurrency.h"
#include "mongo/db/db_raii.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/platform/mutex.h"
namespace mongo {
@@ -137,7 +138,7 @@ protected:
class RolesLocks {
public:
RolesLocks() = default;
- RolesLocks(OperationContext*, const boost::optional<OID>&);
+ RolesLocks(OperationContext*, const boost::optional<TenantId>&);
~RolesLocks();
private:
@@ -152,7 +153,7 @@ protected:
*
* virtual to allow Mock to not lock anything.
*/
- virtual RolesLocks _lockRoles(OperationContext* opCtx, const boost::optional<OID>&);
+ virtual RolesLocks _lockRoles(OperationContext* opCtx, const boost::optional<TenantId>&);
private:
/**
diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.h b/src/mongo/db/auth/authz_manager_external_state_mock.h
index df719d2757a..0eb82b74e4a 100644
--- a/src/mongo/db/auth/authz_manager_external_state_mock.h
+++ b/src/mongo/db/auth/authz_manager_external_state_mock.h
@@ -115,7 +115,7 @@ public:
std::vector<BSONObj> getCollectionContents(const NamespaceString& collectionName);
protected:
- RolesLocks _lockRoles(OperationContext* opCtx, const boost::optional<OID>&) override {
+ RolesLocks _lockRoles(OperationContext* opCtx, const boost::optional<TenantId>&) override {
return RolesLocks();
}
diff --git a/src/mongo/db/auth/authz_manager_external_state_s.cpp b/src/mongo/db/auth/authz_manager_external_state_s.cpp
index 6753dffd28c..91f9f41aa68 100644
--- a/src/mongo/db/auth/authz_manager_external_state_s.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp
@@ -120,7 +120,7 @@ StatusWith<User> AuthzManagerExternalStateMongos::getUserObject(OperationContext
User user(userReq.name);
V2UserDocumentParser dp;
- dp.setTenantID(getActiveTenant(opCtx));
+ dp.setTenantId(getActiveTenant(opCtx));
status = dp.initializeUserFromUserDocument(userDoc, &user);
if (!status.isOK()) {
return status;
diff --git a/src/mongo/db/auth/security_token.cpp b/src/mongo/db/auth/security_token.cpp
index 7ab41457a21..527e5bcb30d 100644
--- a/src/mongo/db/auth/security_token.cpp
+++ b/src/mongo/db/auth/security_token.cpp
@@ -34,10 +34,10 @@
#include <boost/optional.hpp>
#include "mongo/base/init.h"
-#include "mongo/bson/oid.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/multitenancy_gen.h"
#include "mongo/db/server_feature_flags_gen.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/log.h"
#include "mongo/logv2/log_detail.h"
@@ -50,7 +50,7 @@ MONGO_INITIALIZER(SecurityTokenOptionValidate)(InitializerContext*) {
"multitenancySupport may not be specified if featureFlagMongoStore is not enabled",
!gMultitenancySupport || gFeatureFlagMongoStore.isEnabledAndIgnoreFCV());
if (gMultitenancySupport) {
- logv2::detail::setGetTenantIDCallback([]() -> boost::optional<OID> {
+ logv2::detail::setGetTenantIDCallback([]() -> boost::optional<TenantId> {
auto* client = Client::getCurrent();
if (!client)
return boost::none;
diff --git a/src/mongo/db/auth/user_document_parser.h b/src/mongo/db/auth/user_document_parser.h
index 18eb6d88ece..d4593a5ae12 100644
--- a/src/mongo/db/auth/user_document_parser.h
+++ b/src/mongo/db/auth/user_document_parser.h
@@ -30,8 +30,8 @@
#pragma once
#include "mongo/base/status.h"
-#include "mongo/bson/oid.h"
#include "mongo/db/auth/user.h"
+#include "mongo/db/tenant_id.h"
namespace mongo {
@@ -45,7 +45,7 @@ public:
/**
* Apply a tenant identifier to every tenant aware object during parsing.
*/
- void setTenantID(boost::optional<OID> tenant) {
+ void setTenantId(boost::optional<TenantId> tenant) {
_tenant = std::move(tenant);
}
@@ -64,7 +64,7 @@ public:
User* user) const;
private:
- boost::optional<OID> _tenant;
+ boost::optional<TenantId> _tenant;
};
} // namespace mongo
diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp
index a9a08d44856..d2bb8bbb225 100644
--- a/src/mongo/db/commands/user_management_commands.cpp
+++ b/src/mongo/db/commands/user_management_commands.cpp
@@ -72,6 +72,7 @@
#include "mongo/db/query/cursor_response.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/service_context.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/log.h"
#include "mongo/platform/mutex.h"
#include "mongo/rpc/factory.h"
@@ -209,7 +210,7 @@ Status checkOkayToGrantPrivilegesToRole(const RoleName& role, const PrivilegeVec
// Temporary placeholder pending availability of NamespaceWithTenant.
NamespaceString getNamespaceWithTenant(const NamespaceString& nss,
- const boost::optional<OID>& tenant) {
+ const boost::optional<TenantId>& tenant) {
if (tenant) {
return NamespaceString(str::stream() << tenant.get() << '_' << nss.db(), nss.coll());
} else {
@@ -455,7 +456,7 @@ Status removeRoleDocuments(OperationContext* opCtx,
*/
Status insertPrivilegeDocument(OperationContext* opCtx,
const BSONObj& userObj,
- const boost::optional<OID>& tenant = boost::none) {
+ const boost::optional<TenantId>& tenant = boost::none) {
auto nss = getNamespaceWithTenant(AuthorizationManager::usersCollectionNamespace, tenant);
Status status = insertAuthzDocument(opCtx, nss, userObj);
if (status.isOK()) {
diff --git a/src/mongo/db/commands/user_management_commands.idl b/src/mongo/db/commands/user_management_commands.idl
index 720e8663ab5..36e410dc1dc 100644
--- a/src/mongo/db/commands/user_management_commands.idl
+++ b/src/mongo/db/commands/user_management_commands.idl
@@ -33,6 +33,7 @@ imports:
- "mongo/db/auth/auth_types.idl"
- "mongo/db/auth/address_restriction.idl"
- "mongo/db/auth/user_management_commands_parser.idl"
+ - "mongo/db/multitenancy.idl"
structs:
dropAllUsersFromDatabaseReply:
@@ -130,7 +131,7 @@ commands:
"$tenant":
# Only available with enableTestCommands and multitenancySupport
description: "Associate this user with a specific tenant"
- type: objectid
+ type: tenant_id
cpp_name: tenantOverride
optional: true
diff --git a/src/mongo/db/dollar_tenant_decoration_test.cpp b/src/mongo/db/dollar_tenant_decoration_test.cpp
index 161164710cc..c095592ab39 100644
--- a/src/mongo/db/dollar_tenant_decoration_test.cpp
+++ b/src/mongo/db/dollar_tenant_decoration_test.cpp
@@ -79,25 +79,25 @@ TEST_F(DollarTenantDecorationTest, ParseDollarTenantFromRequestSecurityTokenAlre
gMultitenancySupport = true;
// Ensure the security token is set on the opCtx.
- const auto kOid = OID::gen();
- auto token = makeSecurityToken(UserName("user", "admin", kOid));
+ const auto kTenantId = TenantId(OID::gen());
+ auto token = makeSecurityToken(UserName("user", "admin", kTenantId));
auth::readSecurityTokenMetadata(opCtx, token);
ASSERT(getActiveTenant(opCtx));
- ASSERT_EQ(*getActiveTenant(opCtx), kOid);
+ ASSERT_EQ(*getActiveTenant(opCtx), kTenantId);
// TODO SERVER-62406 use the new ActionType for use with $tenant.
// Grant internal auth so that we're authenticated as the internal __system user.
AuthorizationSession::get(opCtx->getClient())->grantInternalAuthorization(opCtx);
// The dollarTenantDecoration should not be set because the security token is already set.
- const auto kOidParameter = OID::gen();
- auto opMsgRequest = OpMsgRequest::fromDBAndBody("test", BSON("$tenant" << kOidParameter));
+ const auto kTenantParameter = OID::gen();
+ auto opMsgRequest = OpMsgRequest::fromDBAndBody("test", BSON("$tenant" << kTenantParameter));
ASSERT_THROWS_CODE(
parseDollarTenantFromRequest(opCtx, opMsgRequest), AssertionException, 6223901);
// getActiveTenant should still return the tenantId in the security token.
ASSERT(getActiveTenant(opCtx));
- ASSERT_EQ(*getActiveTenant(opCtx), kOid);
+ ASSERT_EQ(*getActiveTenant(opCtx), kTenantId);
}
TEST_F(DollarTenantDecorationTest, ParseDollarTenantFromRequestNotInternalSecurityUser) {
@@ -144,7 +144,7 @@ TEST_F(DollarTenantDecorationTest, ParseDollarTenantFromRequestSuccess) {
auto tenantId = getActiveTenant(opCtx);
ASSERT(tenantId);
- ASSERT_EQ(*tenantId, kOid);
+ ASSERT_EQ(tenantId->toString(), kOid.toString());
}
} // namespace
diff --git a/src/mongo/db/multitenancy.cpp b/src/mongo/db/multitenancy.cpp
index ddc849ae3e5..cf3a7576147 100644
--- a/src/mongo/db/multitenancy.cpp
+++ b/src/mongo/db/multitenancy.cpp
@@ -30,23 +30,18 @@
#include "mongo/db/multitenancy.h"
-#include "mongo/bson/oid.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/security_token.h"
#include "mongo/db/multitenancy_gen.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/log.h"
namespace mongo {
-const OID kSystemTenantID(
- "15650000" /* timestamp: 1981-05-17 */
- "0102030405" /* process id */
- "060708" /* counter */);
-
// Holds the tenantId for the operation if it was provided in the request on the $tenant field only
// if the tenantId was not also provided in the security token.
const auto dollarTenantDecoration =
- OperationContext::declareDecoration<boost::optional<mongo::OID>>();
+ OperationContext::declareDecoration<boost::optional<mongo::TenantId>>();
void parseDollarTenantFromRequest(OperationContext* opCtx, const OpMsg& request) {
// The internal security user is allowed to run commands on behalf of a tenant by passing
@@ -66,7 +61,7 @@ void parseDollarTenantFromRequest(OperationContext* opCtx, const OpMsg& request)
->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(),
ActionType::internal));
- auto tenantId = tenantElem.OID();
+ auto tenantId = TenantId::parseFromBSON(tenantElem);
uassert(6223901,
str::stream() << "Cannot pass $tenant id if also passing securityToken, securityToken: "
@@ -80,7 +75,7 @@ void parseDollarTenantFromRequest(OperationContext* opCtx, const OpMsg& request)
6223900, 4, "Setting tenantId from $tenant request parameter", "tenantId"_attr = tenantId);
}
-boost::optional<OID> getActiveTenant(OperationContext* opCtx) {
+boost::optional<TenantId> getActiveTenant(OperationContext* opCtx) {
auto token = auth::getSecurityToken(opCtx);
if (!token) {
return dollarTenantDecoration(opCtx);
diff --git a/src/mongo/db/multitenancy.h b/src/mongo/db/multitenancy.h
index ba537108d79..f354d225a50 100644
--- a/src/mongo/db/multitenancy.h
+++ b/src/mongo/db/multitenancy.h
@@ -31,29 +31,20 @@
#include <boost/optional.hpp>
-#include "mongo/bson/oid.h"
#include "mongo/db/operation_context.h"
+#include "mongo/db/tenant_id.h"
namespace mongo {
/**
- * kSystemTenantID must be unique across all possible tenant IDs.
- * Since the first four bytes of an OID are a unix epoch timestamp,
- * we can simply select a value prior to the inception of MongoDB,
- * and be guaranteed to never have a collision with a value
- * produced by OID::gen().
- */
-extern const OID kSystemTenantID;
-
-/**
* Parses the tenantId from the '$tenant' field in the request if it exists and
* "multitenancySupport" is enabled. Then, sets the parsed tenantId on the opCtx.
*/
void parseDollarTenantFromRequest(OperationContext* opCtx, const OpMsg& request);
/**
- * Extract the active TenantID for this operation.
+ * Extract the active TenantId for this operation.
*/
-boost::optional<OID> getActiveTenant(OperationContext* opCtx);
+boost::optional<TenantId> getActiveTenant(OperationContext* opCtx);
} // namespace mongo
diff --git a/src/mongo/db/multitenancy.idl b/src/mongo/db/multitenancy.idl
index e7840f6d482..a45623c6f99 100644
--- a/src/mongo/db/multitenancy.idl
+++ b/src/mongo/db/multitenancy.idl
@@ -28,6 +28,8 @@
global:
cpp_namespace: "mongo"
+ cpp_includes:
+ - "mongo/db/tenant_id.h"
server_parameters:
multitenancySupport:
@@ -37,3 +39,11 @@ server_parameters:
cpp_varname: gMultitenancySupport
default: false
+types:
+ tenant_id:
+ bson_serialization_type: any
+ description: "A struct representing a tenant id"
+ cpp_type: "TenantId"
+ deserializer: "mongo::TenantId::parseFromBSON"
+ serializer: "mongo::TenantId::serializeToBSON"
+
diff --git a/src/mongo/db/tenant_database_name.h b/src/mongo/db/tenant_database_name.h
index fedba92649e..eebe8301618 100644
--- a/src/mongo/db/tenant_database_name.h
+++ b/src/mongo/db/tenant_database_name.h
@@ -34,6 +34,7 @@
#include "mongo/base/string_data.h"
#include "mongo/db/server_feature_flags_gen.h"
+#include "mongo/db/tenant_id.h"
namespace mongo {
class TenantDatabaseName {
@@ -45,7 +46,7 @@ public:
*
* If featureFlagRequireTenantID is set, tenantId is required.
*/
- TenantDatabaseName(boost::optional<mongo::OID> tenantId, StringData dbName) {
+ TenantDatabaseName(boost::optional<TenantId> tenantId, StringData dbName) {
// TODO SERVER-62114 Check instead if gMultitenancySupport is enabled.
if (gFeatureFlagRequireTenantID.isEnabledAndIgnoreFCV())
invariant(tenantId);
@@ -57,7 +58,7 @@ public:
_tenantId ? boost::make_optional(_tenantId->toString() + "_" + _dbName) : boost::none;
}
- const boost::optional<mongo::OID> tenantId() const {
+ const boost::optional<TenantId> tenantId() const {
return _tenantId;
}
@@ -95,7 +96,7 @@ public:
}
private:
- boost::optional<mongo::OID> _tenantId;
+ boost::optional<TenantId> _tenantId;
std::string _dbName;
boost::optional<std::string> _tenantDbName;
};
diff --git a/src/mongo/db/tenant_database_name_test.cpp b/src/mongo/db/tenant_database_name_test.cpp
index 91d75b335f9..b2aa8632404 100644
--- a/src/mongo/db/tenant_database_name_test.cpp
+++ b/src/mongo/db/tenant_database_name_test.cpp
@@ -27,11 +27,10 @@
* it in the license file.
*/
-#include "mongo/db/multitenancy_gen.h"
+#include "mongo/db/multitenancy.h"
#include "mongo/db/server_feature_flags_gen.h"
#include "mongo/db/tenant_database_name.h"
#include "mongo/idl/server_parameter_test_util.h"
-#include "mongo/platform/basic.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
@@ -44,7 +43,7 @@ TEST(TenantDatabaseNameTest, MultitenancySupportDisabled) {
ASSERT_EQUALS(std::string("a"), tdnWithoutTenant1.dbName());
ASSERT_EQUALS(std::string("a"), tdnWithoutTenant1.fullName());
- mongo::OID tenantId = OID::gen();
+ TenantId tenantId = TenantId(OID::gen());
TenantDatabaseName tdnWithTenant(tenantId, "a");
ASSERT(tdnWithTenant.tenantId());
ASSERT_EQUALS(tenantId, *tdnWithTenant.tenantId());
@@ -61,7 +60,7 @@ TEST(TenantDatabaseNameTest, MultitenancySupportEnabledTenantIDNotRequired) {
ASSERT_EQUALS(std::string("a"), tdnWithoutTenant.dbName());
ASSERT_EQUALS(std::string("a"), tdnWithoutTenant.fullName());
- mongo::OID tenantId = OID::gen();
+ TenantId tenantId = TenantId(OID::gen());
TenantDatabaseName tdnWithTenant(tenantId, "a");
ASSERT(tdnWithTenant.tenantId());
ASSERT_EQUALS(tenantId, *tdnWithTenant.tenantId());
@@ -82,7 +81,7 @@ TEST(TenantDatabaseNameTest, TenantIDRequiredBasic) {
// TODO SERVER-62114 Remove enabling this feature flag.
RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true);
- mongo::OID tenantId = OID::gen();
+ TenantId tenantId = TenantId(OID::gen());
TenantDatabaseName tdn(tenantId, "a");
ASSERT(tdn.tenantId());
ASSERT_EQUALS(tenantId, *tdn.tenantId());
@@ -91,18 +90,19 @@ TEST(TenantDatabaseNameTest, TenantIDRequiredBasic) {
}
TEST(TenantDatabaseNameTest, VerifyEqualsOperator) {
- mongo::OID tenantId = OID::gen();
+ TenantId tenantId = TenantId(OID::gen());
TenantDatabaseName tdn(tenantId, "a");
ASSERT_TRUE(TenantDatabaseName(tenantId, "a") == tdn);
ASSERT_TRUE(TenantDatabaseName(tenantId, "b") != tdn);
- ASSERT_TRUE(TenantDatabaseName(OID::gen(), "a") != tdn);
+ TenantId otherTenantId = TenantId(OID::gen());
+ ASSERT_TRUE(TenantDatabaseName(otherTenantId, "a") != tdn);
ASSERT_TRUE(TenantDatabaseName(boost::none, "a") != tdn);
}
TEST(TenantDatabaseNameTest, VerifyHashFunction) {
- mongo::OID tenantId1 = OID::gen();
- mongo::OID tenantId2 = OID::gen();
+ TenantId tenantId1 = TenantId(OID::gen());
+ TenantId tenantId2 = TenantId(OID::gen());
TenantDatabaseName tdn1 = TenantDatabaseName(tenantId1, "a");
TenantDatabaseName tdn2 = TenantDatabaseName(tenantId2, "a");
TenantDatabaseName tdn3 = TenantDatabaseName(boost::none, "a");
diff --git a/src/mongo/db/tenant_id.cpp b/src/mongo/db/tenant_id.cpp
new file mode 100644
index 00000000000..ebef1dab3de
--- /dev/null
+++ b/src/mongo/db/tenant_id.cpp
@@ -0,0 +1,70 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/db/tenant_id.h"
+
+#include "mongo/bson/oid.h"
+
+namespace mongo {
+
+const TenantId TenantId::kSystemTenantId(
+ OID("15650000" /* timestamp: 1981-05-17 */
+ "0102030405" /* process id */
+ "060708" /* counter */));
+
+TenantId TenantId::parseFromBSON(const BSONElement& elem) {
+ if (elem.isNull()) {
+ uasserted(ErrorCodes::BadValue, "Could not deserialize TenantId from empty element");
+ }
+
+ // Expect objectid in the element for tenant.
+ if (elem.type() != BSONType::jstOID) {
+ uasserted(ErrorCodes::BadValue,
+ fmt::format("Could not deserialize TenantId with type {}", elem.type()));
+ }
+ return TenantId(elem.OID());
+}
+
+void TenantId::serializeToBSON(StringData fieldName, BSONObjBuilder* builder) const {
+ // Append objectid to the builder.
+ builder->append(fieldName, _oid);
+}
+
+void TenantId::serializeToBSON(BSONArrayBuilder* builder) const {
+ builder->append(_oid);
+}
+
+template <>
+BSONObjBuilder& BSONObjBuilderValueStream::operator<<<TenantId>(TenantId value) {
+ value.serializeToBSON(_fieldName, _builder);
+ _fieldName = StringData();
+ return *_builder;
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/tenant_id.h b/src/mongo/db/tenant_id.h
new file mode 100644
index 00000000000..7af08a45d95
--- /dev/null
+++ b/src/mongo/db/tenant_id.h
@@ -0,0 +1,152 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <ostream>
+#include <string>
+
+#include "mongo/base/string_data.h"
+#include "mongo/bson/bsonelement.h"
+#include "mongo/bson/bsonmisc.h"
+#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/bson/oid.h"
+#include "mongo/bson/util/builder.h"
+
+namespace mongo {
+
+/**
+ * Representation of a tenant identifier.
+ */
+class TenantId {
+public:
+ /**
+ * kSystemTenantId must be unique across all possible tenant IDs.
+ * Since the first four bytes of an OID are a unix epoch timestamp,
+ * we can simply select a value prior to the inception of MongoDB,
+ * and be guaranteed to never have a collision with a value
+ * produced by OID::gen().
+ */
+ static const TenantId kSystemTenantId;
+
+ explicit TenantId(const OID& oid) : _oid(oid), _idStr(oid.toString()) {}
+
+ TenantId() = delete;
+
+ const std::string& toString() const {
+ return _idStr;
+ }
+
+ /**
+ * Returns -1, 0, or 1 if 'this' is less, equal, or greater than 'other' in
+ * lexicographical order.
+ */
+ int compare(const TenantId& other) const {
+ return _oid.compare(other._oid);
+ }
+
+ std::size_t hash() const {
+ return OID::Hasher()(_oid);
+ }
+
+ /**
+ * Functor compatible with std::hash for std::unordered_{map,set}
+ */
+ struct Hasher {
+ std::size_t operator()(const TenantId& tenantId) const {
+ return tenantId.hash();
+ }
+ };
+
+ /**
+ * Hash function compatible with absl::Hash for absl::unordered_{map,set}
+ */
+ template <typename H>
+ friend H AbslHashValue(H h, const TenantId& tenantId) {
+ return H::combine(std::move(h), tenantId.hash());
+ }
+
+ /**
+ * Parse tenant id from BSON. The function is used by IDL parsers.
+ */
+ static TenantId parseFromBSON(const BSONElement& elem);
+
+ /**
+ * Serialize tenant id to BSON. These functions are used by IDL parsers.
+ */
+ void serializeToBSON(StringData fieldName, BSONObjBuilder* builder) const;
+ void serializeToBSON(BSONArrayBuilder* builder) const;
+
+private:
+ OID _oid;
+ std::string _idStr;
+};
+
+inline bool operator==(const TenantId& lhs, const TenantId& rhs) {
+ return lhs.compare(rhs) == 0;
+}
+
+inline bool operator!=(const TenantId& lhs, const TenantId& rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator<(const TenantId& lhs, const TenantId& rhs) {
+ return lhs.compare(rhs) < 0;
+}
+
+inline bool operator>(const TenantId& lhs, const TenantId& rhs) {
+ return rhs < lhs;
+}
+
+inline bool operator<=(const TenantId& lhs, const TenantId& rhs) {
+ return !(lhs > rhs);
+}
+
+inline bool operator>=(const TenantId& lhs, const TenantId& rhs) {
+ return !(lhs < rhs);
+}
+
+inline std::ostream& operator<<(std::ostream& os, const TenantId& tenantId) {
+ return os << tenantId.toString();
+}
+
+template <typename Allocator>
+StringBuilderImpl<Allocator>& operator<<(StringBuilderImpl<Allocator>& stream,
+ const TenantId& tenantId) {
+ return stream << tenantId.toString();
+}
+
+/**
+ * Supports use of TenantId with the BSON macro:
+ * BSON("tenant" << tenantId)
+ */
+template <>
+BSONObjBuilder& BSONObjBuilderValueStream::operator<<<TenantId>(TenantId value);
+
+} // namespace mongo
diff --git a/src/mongo/db/tenant_namespace.cpp b/src/mongo/db/tenant_namespace.cpp
index fac9df72788..e482b954703 100644
--- a/src/mongo/db/tenant_namespace.cpp
+++ b/src/mongo/db/tenant_namespace.cpp
@@ -34,7 +34,7 @@
namespace mongo {
-TenantNamespace::TenantNamespace(boost::optional<mongo::OID> tenantId, NamespaceString nss) {
+TenantNamespace::TenantNamespace(boost::optional<mongo::TenantId> tenantId, NamespaceString nss) {
// TODO SERVER-62114 Check instead if gMultitenancySupport is enabled.
if (gFeatureFlagRequireTenantID.isEnabledAndIgnoreFCV())
invariant(tenantId);
@@ -54,7 +54,7 @@ TenantNamespace TenantNamespace::parseTenantNamespaceFromDisk(StringData ns) {
if (tenantDelim == std::string::npos)
return TenantNamespace(boost::none, NamespaceString(ns));
- auto tenantId = OID(ns.substr(0, tenantDelim));
+ const TenantId tenantId(OID(ns.substr(0, tenantDelim)));
auto nss = NamespaceString(ns.substr(tenantDelim + 1, ns.size() - 1 - tenantDelim));
return TenantNamespace(tenantId, nss);
}
diff --git a/src/mongo/db/tenant_namespace.h b/src/mongo/db/tenant_namespace.h
index 7373502a87e..868792d96f6 100644
--- a/src/mongo/db/tenant_namespace.h
+++ b/src/mongo/db/tenant_namespace.h
@@ -36,9 +36,8 @@
#include "mongo/base/string_data.h"
#include "mongo/bson/util/builder.h"
-#include "mongo/db/multitenancy_gen.h"
#include "mongo/db/namespace_string.h"
-#include "mongo/db/server_feature_flags_gen.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/log_attr.h"
namespace mongo {
@@ -55,7 +54,7 @@ public:
*
* If featureFlagRequireTenantID is set, tenantId is required.
*/
- TenantNamespace(boost::optional<mongo::OID> tenantId, NamespaceString nss);
+ TenantNamespace(boost::optional<mongo::TenantId> tenantId, NamespaceString nss);
/**
* Constructs a TenantNamespace from the string "ns". When the server parameter
@@ -77,7 +76,7 @@ public:
*/
static TenantNamespace parseTenantNamespaceFromDisk(StringData ns);
- boost::optional<mongo::OID> tenantId() const {
+ boost::optional<TenantId> tenantId() const {
return _tenantId;
}
@@ -131,7 +130,7 @@ public:
}
private:
- boost::optional<mongo::OID> _tenantId;
+ boost::optional<TenantId> _tenantId;
NamespaceString _nss;
boost::optional<std::string> _tenantNsStr; // Only set if _tenantId exists
};
diff --git a/src/mongo/db/tenant_namespace_test.cpp b/src/mongo/db/tenant_namespace_test.cpp
index 6b4917422af..3c1c4684ecb 100644
--- a/src/mongo/db/tenant_namespace_test.cpp
+++ b/src/mongo/db/tenant_namespace_test.cpp
@@ -55,7 +55,7 @@ TEST(TenantNamespaceTest, TenantNamespaceParseFromDiskMultitenancySupportDisable
ASSERT_EQUALS(std::string("a"), tenantNs.db());
ASSERT_EQUALS(std::string("b"), tenantNs.coll());
- mongo::OID tenantId = OID::gen();
+ TenantId tenantId = TenantId(OID::gen());
std::string ns = tenantId.toString() + "_a.b";
TenantNamespace tenantNs2 = TenantNamespace::parseTenantNamespaceFromDisk(ns);
ASSERT(!tenantNs2.tenantId());
@@ -76,7 +76,7 @@ TEST(TenantNamespaceTest, TenantNamespaceMultitenancySupportEnabledFeatureFlagDi
// If the feature flag is disabled but a tenantId is given, the tenantId should be parsed
// separately from the db name.
- mongo::OID tenantId = OID::gen();
+ TenantId tenantId = TenantId(OID::gen());
TenantNamespace tenantNs2(tenantId, NamespaceString("a.b"));
ASSERT(tenantNs2.tenantId());
ASSERT_EQUALS(tenantId, *tenantNs2.tenantId());
@@ -112,7 +112,7 @@ TEST(TenantNamespaceTest, TenantNamespaceMultitenancySupportEnabledBasic) {
// TODO SERVER-62114 Remove enabling this feature flag.
RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true);
- mongo::OID tenantId = OID::gen();
+ TenantId tenantId = TenantId(OID::gen());
TenantNamespace tenantNs(tenantId, NamespaceString("a.b"));
ASSERT(tenantNs.tenantId());
ASSERT_EQUALS(tenantId, *tenantNs.tenantId());
@@ -126,7 +126,7 @@ TEST(TenantNamespaceTest, TenantNamespaceParseFromDiskMultitenancySupportEnabled
// TODO SERVER-62114 Remove enabling this feature flag.
RAIIServerParameterControllerForTest featureFlagController("featureFlagRequireTenantID", true);
- mongo::OID tenantId = OID::gen();
+ TenantId tenantId = TenantId(OID::gen());
std::string tenantNsStr = str::stream() << tenantId << "_a.b";
TenantNamespace tenantNs = TenantNamespace::parseTenantNamespaceFromDisk(tenantNsStr);
diff --git a/src/mongo/logv2/SConscript b/src/mongo/logv2/SConscript
index a324973bcba..2ceefd5b03c 100644
--- a/src/mongo/logv2/SConscript
+++ b/src/mongo/logv2/SConscript
@@ -14,6 +14,7 @@ env.CppUnitTest(
LIBDEPS=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/db/auth/security_token',
+ '$BUILD_DIR/mongo/db/multitenancy_params',
]
)
diff --git a/src/mongo/logv2/bson_formatter.cpp b/src/mongo/logv2/bson_formatter.cpp
index 3d85fbbb5f8..edf69478e20 100644
--- a/src/mongo/logv2/bson_formatter.cpp
+++ b/src/mongo/logv2/bson_formatter.cpp
@@ -34,6 +34,7 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/attribute_storage.h"
#include "mongo/logv2/attributes.h"
#include "mongo/logv2/constants.h"
@@ -123,8 +124,8 @@ void BSONFormatter::operator()(boost::log::record_view const& rec, BSONObjBuilde
builder.append(constants::kComponentFieldName,
extract<LogComponent>(attributes::component(), rec).get().getNameForLog());
builder.append(constants::kIdFieldName, extract<int32_t>(attributes::id(), rec).get());
- if (auto ptr = extract<OID>(attributes::tenant(), rec).get_ptr()) {
- builder.append(constants::kTenantFieldName, *ptr);
+ if (auto ptr = extract<TenantId>(attributes::tenant(), rec).get_ptr()) {
+ builder.append(constants::kTenantFieldName, ptr->toString());
}
builder.append(constants::kContextFieldName,
extract<StringData>(attributes::threadName(), rec).get());
diff --git a/src/mongo/logv2/json_formatter.cpp b/src/mongo/logv2/json_formatter.cpp
index c19de341c2e..cbcfc85f121 100644
--- a/src/mongo/logv2/json_formatter.cpp
+++ b/src/mongo/logv2/json_formatter.cpp
@@ -217,7 +217,7 @@ void JSONFormatter::format(fmt::memory_buffer& buffer,
StringData message,
const TypeErasedAttributeStorage& attrs,
LogTag tags,
- const OID* tenant,
+ const TenantId* tenant,
LogTruncation truncation) const {
namespace c = constants;
static constexpr auto kFmt = JsonStringFormat::ExtendedRelaxedV2_0_0;
@@ -350,7 +350,7 @@ void JSONFormatter::operator()(boost::log::record_view const& rec,
extract<StringData>(attributes::message(), rec).get(),
extract<TypeErasedAttributeStorage>(attributes::attributes(), rec).get(),
extract<LogTag>(attributes::tags(), rec).get(),
- extract<OID>(attributes::tenant(), rec).get_ptr(),
+ extract<TenantId>(attributes::tenant(), rec).get_ptr(),
extract<LogTruncation>(attributes::truncation(), rec).get());
// Write final JSON object to output stream
diff --git a/src/mongo/logv2/json_formatter.h b/src/mongo/logv2/json_formatter.h
index 4a2edd15740..44d9b7ea66d 100644
--- a/src/mongo/logv2/json_formatter.h
+++ b/src/mongo/logv2/json_formatter.h
@@ -32,7 +32,7 @@
#include <boost/log/core/record_view.hpp>
#include <boost/log/utility/formatting_ostream_fwd.hpp>
-#include "mongo/bson/oid.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/attribute_storage.h"
#include "mongo/logv2/constants.h"
#include "mongo/logv2/log_component.h"
@@ -59,7 +59,7 @@ public:
StringData message,
const TypeErasedAttributeStorage& attrs,
LogTag tags,
- const OID* tenant,
+ const TenantId* tenant,
LogTruncation truncation) const;
void operator()(boost::log::record_view const& rec, boost::log::formatting_ostream& strm) const;
diff --git a/src/mongo/logv2/log_detail.cpp b/src/mongo/logv2/log_detail.cpp
index 1a0f4edab3b..188ede8032a 100644
--- a/src/mongo/logv2/log_detail.cpp
+++ b/src/mongo/logv2/log_detail.cpp
@@ -33,6 +33,7 @@
#include <fmt/format.h>
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/attributes.h"
#include "mongo/logv2/log.h"
#include "mongo/logv2/log_domain.h"
@@ -178,7 +179,7 @@ void doLogImpl(int32_t id,
record.attribute_values().insert(
attributes::tenant(),
boost::log::attribute_value(
- new boost::log::attributes::attribute_value_impl<OID>(tenant.get())));
+ new boost::log::attributes::attribute_value_impl<TenantId>(tenant.get())));
}
}
diff --git a/src/mongo/logv2/log_detail.h b/src/mongo/logv2/log_detail.h
index 780d776c062..6f60ae10c74 100644
--- a/src/mongo/logv2/log_detail.h
+++ b/src/mongo/logv2/log_detail.h
@@ -32,8 +32,8 @@
#include <boost/optional.hpp>
#include "mongo/base/status.h"
-#include "mongo/bson/oid.h"
#include "mongo/bson/util/builder.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/attribute_storage.h"
#include "mongo/logv2/log_attr.h"
#include "mongo/logv2/log_component.h"
@@ -44,7 +44,7 @@
namespace mongo {
namespace logv2::detail {
-using GetTenantIDFn = std::function<boost::optional<OID>()>;
+using GetTenantIDFn = std::function<boost::optional<TenantId>()>;
void setGetTenantIDCallback(GetTenantIDFn&& fn);
void doLogImpl(int32_t id,
diff --git a/src/mongo/logv2/logv2_test.cpp b/src/mongo/logv2/logv2_test.cpp
index fed5d05f2d1..7102e720203 100644
--- a/src/mongo/logv2/logv2_test.cpp
+++ b/src/mongo/logv2/logv2_test.cpp
@@ -41,6 +41,7 @@
#include "mongo/bson/json.h"
#include "mongo/bson/oid.h"
#include "mongo/db/auth/security_token.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/logv2/bson_formatter.h"
#include "mongo/logv2/component_settings_filter.h"
#include "mongo/logv2/composite_backend.h"
@@ -79,6 +80,7 @@ using constants::kIdFieldName;
using constants::kMessageFieldName;
using constants::kSeverityFieldName;
using constants::kTagsFieldName;
+using constants::kTenantFieldName;
using constants::kTimestampFieldName;
struct TypeWithoutBSON {
@@ -361,7 +363,8 @@ class LogV2TypesTest : public LogV2Test {
public:
using LogV2Test::LogV2Test;
LogV2TypesTest() : LogV2Test() {
- detail::setGetTenantIDCallback([this]() -> boost::optional<OID> { return this->tenant; });
+ detail::setGetTenantIDCallback(
+ [this]() -> boost::optional<TenantId> { return this->tenant; });
}
~LogV2TypesTest() {
detail::setGetTenantIDCallback(nullptr);
@@ -374,16 +377,17 @@ public:
std::istringstream json_stream(json.back());
pt::ptree ptree;
pt::json_parser::read_json(json_stream, ptree);
- ASSERT_EQUALS(OID(ptree.get<std::string>("tenant")), OID(tenant));
+ ASSERT_EQUALS(ptree.get<std::string>(std::string(kTenantFieldName)), tenant.toString());
ASSERT_EQUALS(ptree.get<T>(std::string(kAttributesFieldName) + ".name"), expected);
}
auto lastBSONElement() {
- ASSERT_EQUALS(BSONObj(bson.back().data()).getField("tenant").OID(), tenant);
+ ASSERT_EQUALS(BSONObj(bson.back().data()).getField(kTenantFieldName).str(),
+ tenant.toString());
return BSONObj(bson.back().data()).getField(kAttributesFieldName).Obj().getField("name"_sd);
}
- OID tenant = OID::gen();
+ TenantId tenant = TenantId(OID::gen());
LineCapture text = makeLineCapture(PlainFormatter());
LineCapture json = makeLineCapture(JSONFormatter());
LineCapture bson = makeLineCapture(BSONFormatter());
diff --git a/src/mongo/rpc/metadata/security_token_metadata_test.cpp b/src/mongo/rpc/metadata/security_token_metadata_test.cpp
index 1319dae55c7..9fcb2a55adc 100644
--- a/src/mongo/rpc/metadata/security_token_metadata_test.cpp
+++ b/src/mongo/rpc/metadata/security_token_metadata_test.cpp
@@ -36,6 +36,7 @@
#include "mongo/db/client.h"
#include "mongo/db/concurrency/locker_noop_service_context_test_fixture.h"
#include "mongo/db/multitenancy_gen.h"
+#include "mongo/db/tenant_id.h"
#include "mongo/rpc/op_msg_test.h"
#include "mongo/unittest/unittest.h"
@@ -65,7 +66,7 @@ class SecurityTokenMetadataTest : public LockerNoopServiceContextTest {};
TEST_F(SecurityTokenMetadataTest, SecurityTokenNotAccepted) {
const auto kPingBody = BSON(kPingFieldName << 1);
- const auto kTokenBody = makeSecurityToken(UserName("user", "admin", OID::gen()));
+ const auto kTokenBody = makeSecurityToken(UserName("user", "admin", TenantId(OID::gen())));
gMultitenancySupport = false;
auto msgBytes = OpMsgBytes{0, kBodySection, kPingBody, kSecurityTokenSection, kTokenBody};
@@ -76,9 +77,9 @@ TEST_F(SecurityTokenMetadataTest, SecurityTokenNotAccepted) {
}
TEST_F(SecurityTokenMetadataTest, BasicSuccess) {
- const auto kOid = OID::gen();
+ const auto kTenantId = TenantId(OID::gen());
const auto kPingBody = BSON(kPingFieldName << 1);
- const auto kTokenBody = makeSecurityToken(UserName("user", "admin", kOid));
+ const auto kTokenBody = makeSecurityToken(UserName("user", "admin", kTenantId));
gMultitenancySupport = true;
auto msg = OpMsgBytes{0, kBodySection, kPingBody, kSecurityTokenSection, kTokenBody}.parse();
@@ -97,7 +98,7 @@ TEST_F(SecurityTokenMetadataTest, BasicSuccess) {
ASSERT_EQ(authedUser.getUser(), "user");
ASSERT_EQ(authedUser.getDB(), "admin");
ASSERT_TRUE(authedUser.getTenant() != boost::none);
- ASSERT_EQ(authedUser.getTenant().get(), kOid);
+ ASSERT_EQ(authedUser.getTenant().get(), kTenantId);
}
} // namespace