Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- 27017:27017
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand Down Expand Up @@ -58,7 +58,7 @@ jobs:
MONGO_INITDB_ROOT_PASSWORD: example
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand All @@ -74,9 +74,7 @@ jobs:
cd test
npm test
env:
MONGODB_USERNAME: root
MONGODB_PASSWORD: example
MONGODB_AUTHSOURCE: admin
MONGODB_URL: mongodb://root:example@localhost:27017/bedrock_mongodb_test?authSource=admin

coverage:
needs: [test-node]
Expand All @@ -89,7 +87,7 @@ jobs:
- 27017:27017
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

### Changed
- **BREAKING**: Upgrade to `mongodb: ^4.9.0`
- **BREAKING**: Remove all defaults for `authSource`.
- **BREAKING**: Remove `config.mongodb.username`.
- **BREAKING**: Remove `config.mongodb.password`.
- **BREAKING**: Remove setting username, password, and or authSource from `urls.create`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add something here that says that all of these options, if needed, must be provided via the database url config option?


## 10.1.1 -

Expand Down
26 changes: 11 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,13 @@ bedrock.config.mongodb.name = 'my_project_dev'; // default: bedrock_dev
bedrock.config.mongodb.host = 'localhost'; // default: localhost
bedrock.config.mongodb.protocol = 'mongodb'; // default: mongodb
bedrock.config.mongodb.port = 27017; // default: 27017
bedrock.config.mongodb.username = 'my_project'; // default: bedrock
bedrock.config.mongodb.password = 'password'; // default: password

// the mongodb database 'my_project_dev' and the 'my_project' user will
// be created on start up following a prompt for the admin user credentials
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments need to be brought into sync with these changes.


// alternatively, use `mongodb` URL format:
bedrock.config.mongodb.url = 'mongodb://localhost:27017/my_project_dev';

// enable local collection if a local database is available
// the local database has similar options to primary database
// see lib/config.js for details
// bedrock.config.mongodb.local.enable = true; // default: false

// open some collections once the database is ready
bedrock.events.on('bedrock-mongodb.ready', async function() {
await database.openCollections(['collection1', 'collection2']);
Expand All @@ -61,34 +54,37 @@ For documentation on database configuration, see [config.js](./lib/config.js).
MongoDB's documentation offers tons of great examples on how to authenticate
using a myriad number of connection strings.

[Mongo Node 3.5 Driver connect docs](http://mongodb.github.io/node-mongodb-native/3.5/tutorials/connect/)
[Mongo Node 4.8 Driver connect docs](https://www.mongodb.com/docs/drivers/node/v4.8/fundamentals/connection/connect/)

[Mongo Node 3.5 Driver atlas docs](https://docs.mongodb.com/drivers/node#connect-to-mongodb-atlas)
[Mongo Node 4.8 Driver atlas docs](https://www.mongodb.com/docs/atlas/driver-connection/?tck=docs_driver_nodejs)

You can also connect to access-enabled mongo servers using some small changes to the
You can also connect to auth-enabled mongo servers using some small changes to the
`config.mongodb.connectOptions`:
```js
import {config} from '@bedrock/core';

config.mongodb.username = 'me';
config.mongodb.password = 'password';
config.mongodb.protocol = 'mongodb+srv';
const {connectOptions} = config.mongodb;
connectOptions.auth = {
username: 'me',
password: 'password'
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to support this, only url options, right?

// optional, only required if connecting to a replicaSet
connectOptions.replicaSet = 'my_provider_replica_set';
// optional, but required in production by many providers
connectOptions.ssl = true;
// optional, only required if your provider requires tls
connectOptions.tls = true;
// the `authSource` option replaces the older `authDB` option
// it should be specified or else it will be the `mongodb.name`
// the `authSource` is database to authenticate against
// it should be specified or it will default to the database
// you're connecting to
connectOptions.authSource = 'my_provider_auth_db';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be removed too, right? It looks like it can be done via the url. We want there to be just one way to do these things if possible.

```
MongoDB provides [excellent docs on their connection strings](https://docs.mongodb.com/manual/reference/connection-string/)

You can connect using a url by setting:
```js
config.mongodb.url = 'mongodb://myDBReader:D1fficultP%[email protected]:27017/?authSource=admin';
config.mongodb.url = 'mongodb://myDBReader:D1fficultP%[email protected]:27017/myDatabase?authSource=admin';
```

## Requirements
Expand Down
19 changes: 6 additions & 13 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import {config} from '@bedrock/core';
config.mongodb = {};
// Note: `config.mongodb.url` is not set by default. When it is not set, it
// will be assembled from from the `config.mongodb.name`, `config.mongodb.host`,
// and `config.mongodb.port`. When it is set, those values, any authentication
// credentials, and any server options will be parsed from the URL and override
// the broken-down configuration options set here.
// and `config.mongodb.port`. When it is set, those values and any server
// options will be parsed from the URL and override the broken-down
// configuration options set here.
//
// At a minimum, the URL must specify a host, port, and database name. It may
// omit a username and password if those are provided as
// `config.mongodb.username` and `config.mongodb.password`, otherwise those
// `config.mongodb.connnectOptions.auth.username` and
// `config.mongodb.connectOptions.auth.password`, otherwise those
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll want to bring these comments in sync after removing the extra options.

// values will be removed from the URL to prevent their logging and a
// separate authentication call will be made after connecting.
//
// `mongodb.connectOptions` will override any specified in the URL.
// `mongodb.connectOptions` may override any specified in the URL.
//
// format: mongodb://[username:password@]host1[:port1][,host2[:port2],
// ...[,hostN[:portN]]][/[database][?options]]
Expand All @@ -26,11 +27,6 @@ config.mongodb.name = 'bedrock_dev';
config.mongodb.host = 'localhost';
config.mongodb.port = 27017;
config.mongodb.protocol = 'mongodb';
config.mongodb.username = undefined;
config.mongodb.password = undefined;
config.mongodb.adminPrompt = true;
// always authenticate to mongodb even when auth is not required by mongodb
config.mongodb.forceAuthentication = false;
config.mongodb.authentication = {
// used by MongoDB >= 3.0
// authMechanism: 'SCRAM-SHA-1'
Expand All @@ -46,9 +42,6 @@ config.mongodb.connectOptions = {
// it is recommended to set either ssl or tls to true in production
// ssl: true
// tls: true
// authSource is the database you authenticate against
// it often needs to be set explicitly
// authSource: 'admin'
};

// this is used when writing to the database
Expand Down
54 changes: 0 additions & 54 deletions lib/authn.js → lib/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import * as bedrock from '@bedrock/core';
import * as urls from './urls.js';
import {logger} from './logger.js';
import {MDBE_AUTHZ_FAILED} from './exceptions.js';
import mongo from 'mongodb';
import semver from 'semver';
import {klona} from 'klona';
Expand All @@ -19,7 +18,6 @@ export async function openDatabase(options) {
const opts = {
database: config.name,
authentication: config.authentication,
// authSource should be set in connectOptions
connectOptions: config.connectOptions,
writeOptions: config.writeOptions,
...options
Expand All @@ -42,16 +40,6 @@ export async function openDatabase(options) {
`MongoDB server version "${stringVersion}" is unsupported.`,
'NotSupportedError');
}
// makes an unauthenticated call to the server
// to see if auth is required
const authRequired = await _isAuthnRequired({config, admin});

// if authRequired create an auth object for Mongo;
// otherwise `auth` will be passed as `null` and success will rely on other
// config options such as the url for the server
if(authRequired) {
_addAuthOptions({options: opts, config});
}

// connect to database and get server info
return _connect(opts);
Expand Down Expand Up @@ -96,48 +84,6 @@ function _usesRoles(serverInfo) {
(serverInfo.versionArray[0] > 2));
}

/**
* Determines if authn is required.
*
* @see
* https://mongodb.github.io/node-mongodb-native/3.7/api/Admin.html
* #listDatabases
* @private
* @param {object} options - Options to use.
* @param {object} options.config - The mongodb config.
* @param {object} options.admin - A Mongo driver Admin class.
*
* @returns {Promise<boolean>} Is authRequired?
*/
async function _isAuthnRequired({config, admin}) {
if(config.forceAuthentication) {
return true;
}
try {
// if listing databases fails on authz, then authentication is required
await admin.listDatabases();
} catch(e) {
if(e?.code === MDBE_AUTHZ_FAILED) {
return true;
}
// some other error, abort
throw e;
}
return false;
}

function _addAuthOptions({options, config}) {
options.connectOptions.auth = {
username: config.username,
password: config.password
};
// authSource is the database to authenticate against
// this is usually `admin` in dev and a specific db in production
options.connectOptions.authSource =
config.connectOptions.authSource || options.database;
return options;
}

/**
* Establishes an unauthenticated connection to the server.
*
Expand Down
3 changes: 3 additions & 0 deletions lib/exceptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ export const MDBE_ERRORS = [
BULK_WRITE_ERROR,
WRITE_CONCERN_ERROR
];
// authentication on the server failed
export const MDBE_AUTHN_FAILED = 18;
// authenticated but user is not authorized to perform
// the query or action such as insert
export const MDBE_AUTHZ_FAILED = 13;
export const MDBE_DUPLICATE = 11000;
export const MDBE_DUPLICATE_ON_UPDATE = 11001;
Expand Down
8 changes: 3 additions & 5 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as urls from './urls.js';
import {isAlreadyExistsError, isAuthenticationError} from './helpers.js';
import {logger} from './logger.js';
import mongo from 'mongodb';
import {openDatabase} from './authn.js';
import {openDatabase} from './connect.js';

const {util: {BedrockError}} = bedrock;

Expand Down Expand Up @@ -173,10 +173,8 @@ async function _initDatabase() {
} catch(e) {
if(isAuthenticationError(e)) {
// auth failed, either DB didn't exist or bad credentials
logger.info('database authentication failed:' +
' db=' + config.name +
' username=' + config.username +
' url=' + urls.sanitize(config.url));
logger.info(`database authentication failed: ` +
`url="urls.sanitize(${config.url})`);
}
throw new BedrockError(
'Could not initialize database.',
Expand Down
1 change: 0 additions & 1 deletion lib/test.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {config} from '@bedrock/core';
config.mongodb.name = 'bedrock_test';
config.mongodb.host = 'localhost';
config.mongodb.port = 27017;
config.mongodb.adminPrompt = true;

// these settings are only effective if `test` is specified on the command line
// when onInit = true, collections are dropped on initialization
Expand Down
7 changes: 0 additions & 7 deletions lib/urls.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,9 @@
*/
export function create(config) {
let url = `${config.protocol}://`;
if(config.username) {
url += `${config.username}:${config.password}@`;
}
url += config.host;
url += _addPort(config.port);
url += `/${config.name}`;
// this needs to come last
if(config.username) {
url += `?authSource=${config.connectOptions.authSource || 'admin'}`;
}
return url;
}

Expand Down
10 changes: 8 additions & 2 deletions test/test.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,16 @@ if(process.env.MONGODB_REPLICASET) {
connectOptions.replicaSet = process.env.MONGODB_REPLICASET;
}
if(process.env.MONGODB_USERNAME) {
config.mongodb.username = process.env.MONGODB_USERNAME;
if(!connectOptions.auth) {
connectOptions.auth = {};
}
connectOptions.auth.username = process.env.MONGODB_USERNAME;
}
if(process.env.MONGODB_PASSWORD) {
config.mongodb.password = process.env.MONGODB_PASSWORD;
if(!connectOptions.auth) {
connectOptions.auth = {};
}
connectOptions.auth.password = process.env.MONGODB_PASSWORD;
}

//config.mongodb.connectOptions.loggerLevel = 'debug';
Expand Down