diff options
author | Sophia Tan <sophia_tll@hotmail.com> | 2022-01-20 19:18:49 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-01-20 21:36:30 +0000 |
commit | 0f90f936d206032693578db712376489619c0d62 (patch) | |
tree | 8b6f973a9dcfeff7d39ffddb2441e43d3873a43f /src/mongo | |
parent | 08aa07493315218bb47578ec77c94f2d728fb347 (diff) | |
download | mongo-0f90f936d206032693578db712376489619c0d62.tar.gz |
SERVER-62441 Define a new type mongo::TenantId for tenant id
Diffstat (limited to 'src/mongo')
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 |