void ClientMetadata::setMongoSMetadata(StringData hostAndPort, StringData mongosClient, StringData version) { BSONObjBuilder builder; builder.appendElements(_document); { auto sub = BSONObjBuilder(builder.subobjStart(kMongoS)); sub.append(kHost, hostAndPort); sub.append(kClient, mongosClient); sub.append(kVersion, version); } auto document = builder.obj(); if (!_appName.empty()) { // The _appName field points into the existing _document, which we are about to replace. // We must redirect _appName to point into the new doc *before* replacing the old doc. We // expect the 'application' metadata of the new document to be identical to the old. auto appMetaData = document[kApplication]; invariant(appMetaData.isABSONObj()); auto appNameEl = appMetaData[kName]; invariant(appNameEl.type() == BSONType::String); auto appName = appNameEl.valueStringData(); invariant(appName == _appName); _appName = appName; } _document = std::move(document); }
NamespaceString AggregationRequest::parseNs(const std::string& dbname, const BSONObj& cmdObj) { auto firstElement = cmdObj.firstElement(); if (firstElement.isNumber()) { uassert(ErrorCodes::FailedToParse, str::stream() << "Invalid command format: the '" << firstElement.fieldNameStringData() << "' field must specify a collection name or 1", firstElement.number() == 1); return NamespaceString::makeCollectionlessAggregateNSS(dbname); } else { uassert(ErrorCodes::TypeMismatch, str::stream() << "collection name has invalid type: " << typeName(firstElement.type()), firstElement.type() == BSONType::String); const NamespaceString nss(dbname, firstElement.valueStringData()); uassert(ErrorCodes::InvalidNamespace, str::stream() << "Invalid namespace specified '" << nss.ns() << "'", nss.isValid() && !nss.isCollectionlessAggregateNS()); return nss; } }
Status renameCollectionForApplyOps(OperationContext* opCtx, const std::string& dbName, const BSONElement& ui, const BSONObj& cmd) { const auto sourceNsElt = cmd.firstElement(); const auto targetNsElt = cmd["to"]; const auto dropSourceElt = cmd["dropSource"]; uassert(ErrorCodes::TypeMismatch, "'renameCollection' must be of type String", sourceNsElt.type() == BSONType::String); uassert(ErrorCodes::TypeMismatch, "'to' must be of type String", targetNsElt.type() == BSONType::String); NamespaceString sourceNss(sourceNsElt.valueStringData()); NamespaceString targetNss(targetNsElt.valueStringData()); NamespaceString uiNss(getNamespaceFromUUID(opCtx, ui)); NamespaceString dropSourceNss(getNamespaceFromUUID(opCtx, dropSourceElt)); // If the UUID we're targeting already exists, rename from there no matter what. // When dropSource is specified, the rename is accross databases. In that case, ui indicates // the UUID of the new target collection and the dropSourceNss specifies the sourceNss. if (!uiNss.isEmpty()) { sourceNss = uiNss; // The cross-database rename was already done and just needs a local rename, but we may // still need to actually remove the source collection. auto dropSourceNss = getNamespaceFromUUID(opCtx, dropSourceElt); if (!dropSourceNss.isEmpty()) { BSONObjBuilder unusedBuilder; dropCollection(opCtx, dropSourceNss, unusedBuilder, repl::OpTime(), DropCollectionSystemCollectionMode::kAllowSystemCollectionDrops) .ignore(); } } else if (!dropSourceNss.isEmpty()) { sourceNss = dropSourceNss; } else { // When replaying cross-database renames, both source and target collections may no longer // exist. Attempting a rename anyway could result in removing a newer collection of the // same name. uassert(ErrorCodes::NamespaceNotFound, str::stream() << "source collection (UUID " << uassertStatusOK(UUID::parse(dropSourceElt)) << ") for rename to " << targetNss.ns() << " no longer exists", !dropSourceElt); } OptionalCollectionUUID targetUUID; if (!ui.eoo()) targetUUID = uassertStatusOK(UUID::parse(ui)); return renameCollectionCommon(opCtx, sourceNss, targetNss, targetUUID, cmd["dropTarget"].trueValue(), cmd["stayTemp"].trueValue()); }
Status V2UserDocumentParser::checkValidUserDocument(const BSONObj& doc) const { auto userIdElement = doc[AuthorizationManager::USERID_FIELD_NAME]; auto userElement = doc[AuthorizationManager::USER_NAME_FIELD_NAME]; auto userDBElement = doc[AuthorizationManager::USER_DB_FIELD_NAME]; auto credentialsElement = doc[CREDENTIALS_FIELD_NAME]; auto rolesElement = doc[ROLES_FIELD_NAME]; // Validate the "userId" element. if (!userIdElement.eoo()) { if (!userIdElement.isBinData(BinDataType::newUUID)) { return _badValue("User document needs 'userId' field to be a UUID"); } } // Validate the "user" element. if (userElement.type() != String) return _badValue("User document needs 'user' field to be a string"); if (userElement.valueStringData().empty()) return _badValue("User document needs 'user' field to be non-empty"); // Validate the "db" element if (userDBElement.type() != String || userDBElement.valueStringData().empty()) { return _badValue("User document needs 'db' field to be a non-empty string"); } StringData userDBStr = userDBElement.valueStringData(); if (!NamespaceString::validDBName(userDBStr, NamespaceString::DollarInDbNameBehavior::Allow) && userDBStr != "$external") { return _badValue(mongoutils::str::stream() << "'" << userDBStr << "' is not a valid value for the db field."); } // Validate the "credentials" element if (credentialsElement.eoo()) { return _badValue("User document needs 'credentials' object"); } if (credentialsElement.type() != Object) { return _badValue("User document needs 'credentials' field to be an object"); } BSONObj credentialsObj = credentialsElement.Obj(); if (credentialsObj.isEmpty()) { return _badValue("User document needs 'credentials' field to be a non-empty object"); } if (userDBStr == "$external") { BSONElement externalElement = credentialsObj[MONGODB_EXTERNAL_CREDENTIAL_FIELD_NAME]; if (externalElement.eoo() || externalElement.type() != Bool || !externalElement.Bool()) { return _badValue( "User documents for users defined on '$external' must have " "'credentials' field set to {external: true}"); } } else { const auto validateScram = [&credentialsObj](const auto& fieldName) { auto scramElement = credentialsObj[fieldName]; if (scramElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << fieldName << " does not exist"); } if (scramElement.type() != Object) { return _badValue(str::stream() << fieldName << " credential must be an object, if present"); } return Status::OK(); }; const auto sha1status = validateScram(SCRAMSHA1_CREDENTIAL_FIELD_NAME); if (!sha1status.isOK() && (sha1status.code() != ErrorCodes::NoSuchKey)) { return sha1status; } const auto sha256status = validateScram(SCRAMSHA256_CREDENTIAL_FIELD_NAME); if (!sha256status.isOK() && (sha256status.code() != ErrorCodes::NoSuchKey)) { return sha256status; } if (!sha1status.isOK() && !sha256status.isOK()) { return _badValue( "User document must provide credentials for all " "non-external users"); } } // Validate the "roles" element. Status status = _checkV2RolesArray(rolesElement); if (!status.isOK()) return status; // Validate the "authenticationRestrictions" element. status = initializeAuthenticationRestrictionsFromUserDocument(doc, nullptr); if (!status.isOK()) { return status; } return Status::OK(); }