123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- 'use strict';
- const MongoError = require('../error').MongoError;
- /**
- * Creates a new AuthProvider, which dictates how to authenticate for a given
- * mechanism.
- * @class
- */
- class AuthProvider {
- constructor(bson) {
- this.bson = bson;
- this.authStore = [];
- }
- /**
- * Authenticate
- * @method
- * @param {SendAuthCommand} sendAuthCommand Writes an auth command directly to a specific connection
- * @param {Connection[]} connections Connections to authenticate using this authenticator
- * @param {MongoCredentials} credentials Authentication credentials
- * @param {authResultCallback} callback The callback to return the result from the authentication
- */
- auth(sendAuthCommand, connections, credentials, callback) {
- // Total connections
- let count = connections.length;
- if (count === 0) {
- callback(null, null);
- return;
- }
- // Valid connections
- let numberOfValidConnections = 0;
- let errorObject = null;
- const execute = connection => {
- this._authenticateSingleConnection(sendAuthCommand, connection, credentials, (err, r) => {
- // Adjust count
- count = count - 1;
- // If we have an error
- if (err) {
- errorObject = new MongoError(err);
- } else if (r && (r.$err || r.errmsg)) {
- errorObject = new MongoError(r);
- } else {
- numberOfValidConnections = numberOfValidConnections + 1;
- }
- // Still authenticating against other connections.
- if (count !== 0) {
- return;
- }
- // We have authenticated all connections
- if (numberOfValidConnections > 0) {
- // Store the auth details
- this.addCredentials(credentials);
- // Return correct authentication
- callback(null, true);
- } else {
- if (errorObject == null) {
- errorObject = new MongoError(`failed to authenticate using ${credentials.mechanism}`);
- }
- callback(errorObject, false);
- }
- });
- };
- const executeInNextTick = _connection => process.nextTick(() => execute(_connection));
- // For each connection we need to authenticate
- while (connections.length > 0) {
- executeInNextTick(connections.shift());
- }
- }
- /**
- * Implementation of a single connection authenticating. Is meant to be overridden.
- * Will error if called directly
- * @ignore
- */
- _authenticateSingleConnection(/*sendAuthCommand, connection, credentials, callback*/) {
- throw new Error('_authenticateSingleConnection must be overridden');
- }
- /**
- * Adds credentials to store only if it does not exist
- * @param {MongoCredentials} credentials credentials to add to store
- */
- addCredentials(credentials) {
- const found = this.authStore.some(cred => cred.equals(credentials));
- if (!found) {
- this.authStore.push(credentials);
- }
- }
- /**
- * Re authenticate pool
- * @method
- * @param {SendAuthCommand} sendAuthCommand Writes an auth command directly to a specific connection
- * @param {Connection[]} connections Connections to authenticate using this authenticator
- * @param {authResultCallback} callback The callback to return the result from the authentication
- */
- reauthenticate(sendAuthCommand, connections, callback) {
- const authStore = this.authStore.slice(0);
- let count = authStore.length;
- if (count === 0) {
- return callback(null, null);
- }
- for (let i = 0; i < authStore.length; i++) {
- this.auth(sendAuthCommand, connections, authStore[i], function(err) {
- count = count - 1;
- if (count === 0) {
- callback(err, null);
- }
- });
- }
- }
- /**
- * Remove credentials that have been previously stored in the auth provider
- * @method
- * @param {string} source Name of database we are removing authStore details about
- * @return {object}
- */
- logout(source) {
- this.authStore = this.authStore.filter(credentials => credentials.source !== source);
- }
- }
- /**
- * A function that writes authentication commands to a specific connection
- * @callback SendAuthCommand
- * @param {Connection} connection The connection to write to
- * @param {Command} command A command with a toBin method that can be written to a connection
- * @param {AuthWriteCallback} callback Callback called when command response is received
- */
- /**
- * A callback for a specific auth command
- * @callback AuthWriteCallback
- * @param {Error} err If command failed, an error from the server
- * @param {object} r The response from the server
- */
- /**
- * This is a result from an authentication strategy
- *
- * @callback authResultCallback
- * @param {error} error An error object. Set to null if no error present
- * @param {boolean} result The result of the authentication process
- */
- module.exports = { AuthProvider };
|