rxdi/xmigrate

Connection error using URI that enforces access control

acfatah opened this issue · 6 comments

I have a connection string in the form of
mongodb://<username>:<somepassword>@<ip number>:27017/development that enforces access control from development and set the databaseName to 'development'.

Whenever I try to migrate, I get this error:

Message: failed to connect to server [<ip number>:27017] on first connect [MongoError: Invalid database name: 'development/development'

Changing connection string to
mongodb://<username>:<somepassword>@<ip number>:27017 will fire authentication error:

Message: failed to connect to server [167.71.216.187:27017] on first connect [MongoError: Authentication failed.

Setting databaseName to an empty string will fire this error:

Message: failed to connect to server [167.71.216.187:27017] on first connect [MongoError: Invalid database name: 'development/'

How to correctly set the database name?

@acfatah

  1. Can you please copy your configuration here like JSON ?
  2. Please specify what Mongo database version you are using ?

I think you should setup configuration as follow:

export default async () => {
  return {
    mongodb: {
      url: `mongodb://<username>:<somepassword>@<ip number>:27017`,
      databaseName: 'development',
      options: {
        useNewUrlParser: true,
      },
    },
  };
};

Have you tried this way ?

I will try to reproduce it on my local setup. If you can please provide some example repostory.

Regards,
Kristiyan Tachev (@Stradivario )

export default async () => {
  return {
    mongodb: {
      url: 'mongodb://rampage:12123@localhost:27017/development',
      databaseName: 'development',
      options: {
        useNewUrlParser: true
      }
    }
  };
};

With the following configuration i was able to introduce the problem.
I was thinking why you didn't remove the database name at the end of url and specify databaseName as development ?

Correct configuration

export default async () => {
  return {
    mongodb: {
      url: 'mongodb://rampage:12123@localhost:27017',
      databaseName: 'development',
      options: {
        useNewUrlParser: true
      }
    }
  };
};

@acfatah

  1. Can you please copy your configuration here like JSON ?
  2. Please specify what Mongo database version you are using ?

I think you should setup configuration as follow:

export default async () => {
  return {
    mongodb: {
      url: `mongodb://<username>:<somepassword>@<ip number>:27017`,
      databaseName: 'development',
      options: {
        useNewUrlParser: true,
      },
    },
  };
};

Have you tried this way ?

I will try to reproduce it on my local setup. If you can please provide some example repostory.

Regards,
Kristiyan Tachev (@Stradivario )

If I remove /development from the url and follow like then JSON, I'll get error as below:

�️  Database: development

�  DBCollection: migrations

�️  LoggerDir: ./migrations-log

�  MigrationsDir: migrations

�  Script: xmigrate status

(node:1264) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.


�  Status: Operation executed with error
�  Error: {"name":"MongoNetworkError","errorLabels":["TransientTransactionError"]}
�  Message: failed to connect to server [167.71.216.187:27017] on first connect [MongoError: Authentication failed.
    at Function._getError (C:\Users\acfatah\AppData\Roaming\npm\node_modules\@rxdi\xmigrate\node_modules\mongodb\lib\core\auth\scram.js:125:14)
    at C:\Users\acfatah\AppData\Roaming\npm\node_modules\@rxdi\xmigrate\node_modules\mongodb\lib\core\auth\scram.js:175:31
    at Connection.messageHandler (C:\Users\acfatah\AppData\Roaming\npm\node_modules\@rxdi\xmigrate\node_modules\mongodb\lib\core\connection\connect.js:334:5)
    at Connection.emit (events.js:200:13)
    at Connection.EventEmitter.emit (domain.js:471:20)
    at processMessage (C:\Users\acfatah\AppData\Roaming\npm\node_modules\@rxdi\xmigrate\node_modules\mongodb\lib\core\connection\connection.js:364:10)
    at Socket.<anonymous> (C:\Users\acfatah\AppData\Roaming\npm\node_modules\@rxdi\xmigrate\node_modules\mongodb\lib\core\connection\connection.js:533:15)
    at Socket.emit (events.js:200:13)
    at Socket.EventEmitter.emit (domain.js:471:20)
    at addChunk (_stream_readable.js:294:12)
    at readableAddChunk (_stream_readable.js:275:11)
    at Socket.Readable.push (_stream_readable.js:210:10)
    at TCP.onStreamRead (internal/stream_base_commons.js:166:17) {
  name: 'MongoError',
  [Symbol(mongoErrorContextSymbol)]: {}
}]

undefined

I'm using dokku-mongo plugin for the MongoDb connection. The url obtained from mongo:info development command and it looks like below:

$ dokku mongo:info development
=====> Container Information
       Config dir:          /var/lib/dokku/services/mongo/development/config
       Data dir:            /var/lib/dokku/services/mongo/development/data
       Dsn:                 mongodb://development:<somerandomstring>@dokku-mongo-development:27017/development
       Exposed ports:       27017->27017 27018->27018 27019->27019 28017->28017
       Id:                  <somerandomstring>
       Internal ip:         172.17.0.3
       Links:               -
       Service root:        /var/lib/dokku/services/mongo/development
       Status:              running
       Version:             mongo:3.6.13

The url is the Dsn string with dokku-mongo-development replaced by a public host ip. I have to append the /development to connect using MongoClient successfully.

This is sample source. I'm using feathersjs:

// @ts-ignore
import { parseConnectionString as parse } from 'mongodb-core'
import { MongoClient } from 'mongodb'
import { Application } from './declarations'
import logger from './logger'

export default function (app: Application) {
  const config = app.get('mongodb') // The line that uses the url. Need to append /development to work.
  const options = { useNewUrlParser: true, useUnifiedTopology: true }
  const promise = MongoClient.connect(config, options).then(client => {
    let dbName: string | undefined
    parse(config, (error: any, result: any) => { dbName = !!result.auth && result.auth.db })
    return client.db(dbName) // dbName obtained by parsing the connection url
  }).catch(error => {
    logger.error(error)
  })

  app.set('mongoClient', promise)
}

Thank you very much for your response.

Hey @acfatah this week i will have time to take a look at this peace of code. Please let me know if you figure it out. I think to make this work i need to create Parsers for URL and take appropriate data from url provided "url: mongodb://<username>:<somepassword>@<ip number>:27017,"

I will encourage you to parse configuration and provide it with appropriate format like in the description.

Any other ideas ?

I am really sorry for the late response but i was having a nightmare 3 months with a lot of things to do and my mind was blown. Now everything is perfect and i am back to business.

I think this issue stays opened for more than a year till now and thus i think no resolution is made till that day.

Please write me to reopen this issue if it persist!

@acfatah feel free to contact me at telegram https://t.me/dependency

Regards,
Kristiyan Tachev

Just to point out here that i am using this configuration which works flawless.

If we are using it with localhost (dev mode) we will migrate to 182.10.0.6:27017 if we are in environment which enables connection string we can do it as follow. I am sure that there is an even more elegant solution but even with that ugly look it works as expected.

{
  mongodb: {
    url: process.env.MONGO_ENABLE_CONNECTION_STRING
      ? [
          'mongodb+srv://',
          process.env.MONGO_USERNAME,
          ':',
          process.env.MONGO_PASSWORD,
          '@',
          process.env.MONGO_HOST,
          '/',
          process.env.MONGO_DATABASE,
          '?retryWrites=true&w=majority',
        ].join('')
      : 'mongodb://182.10.0.6:27017',
    databaseName: process.env.MONGO_DATABASE
      ? process.env.MONGO_DATABASE
      : 'graphql-server',
    options: {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    },
  },
}

Regards