Пример #1
0
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);
}
Пример #2
0
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;
    }
}
Пример #3
0
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());
}
Пример #4
0
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();
}