authenticate.js 4.43 KB
Newer Older
jutatip's avatar
jutatip committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
'use strict';

var shallowClone = require('./utils').shallowClone,
  handleCallback = require('./utils').handleCallback,
  MongoError = require('mongodb-core').MongoError,
  f = require('util').format;

var authenticate = function(client, username, password, options, callback) {
  // Did the user destroy the topology
  if (client.topology && client.topology.isDestroyed())
    return callback(new MongoError('topology was destroyed'));

  // the default db to authenticate against is 'self'
  // if authententicate is called from a retry context, it may be another one, like admin
  var authdb = options.dbName;
  authdb = options.authdb ? options.authdb : authdb;
  authdb = options.authSource ? options.authSource : authdb;

  // Callback
  var _callback = function(err, result) {
    if (client.listeners('authenticated').length > 0) {
      client.emit('authenticated', err, result);
    }

    // Return to caller
    handleCallback(callback, err, result);
  };

  // authMechanism
  var authMechanism = options.authMechanism || '';
  authMechanism = authMechanism.toUpperCase();

  // If classic auth delegate to auth command
  if (authMechanism === 'MONGODB-CR') {
    client.topology.auth('mongocr', authdb, username, password, function(err) {
      if (err) return handleCallback(callback, err, false);
      _callback(null, true);
    });
  } else if (authMechanism === 'PLAIN') {
    client.topology.auth('plain', authdb, username, password, function(err) {
      if (err) return handleCallback(callback, err, false);
      _callback(null, true);
    });
  } else if (authMechanism === 'MONGODB-X509') {
    client.topology.auth('x509', authdb, username, password, function(err) {
      if (err) return handleCallback(callback, err, false);
      _callback(null, true);
    });
  } else if (authMechanism === 'SCRAM-SHA-1') {
    client.topology.auth('scram-sha-1', authdb, username, password, function(err) {
      if (err) return handleCallback(callback, err, false);
      _callback(null, true);
    });
  } else if (authMechanism === 'GSSAPI') {
    if (process.platform === 'win32') {
      client.topology.auth('sspi', authdb, username, password, options, function(err) {
        if (err) return handleCallback(callback, err, false);
        _callback(null, true);
      });
    } else {
      client.topology.auth('gssapi', authdb, username, password, options, function(err) {
        if (err) return handleCallback(callback, err, false);
        _callback(null, true);
      });
    }
  } else if (authMechanism === 'DEFAULT') {
    client.topology.auth('default', authdb, username, password, function(err) {
      if (err) return handleCallback(callback, err, false);
      _callback(null, true);
    });
  } else {
    handleCallback(
      callback,
      MongoError.create({
        message: f('authentication mechanism %s not supported', options.authMechanism),
        driver: true
      })
    );
  }
};

module.exports = function(self, username, password, options, callback) {
  if (typeof options === 'function') (callback = options), (options = {});
  options = options || {};

  // Shallow copy the options
  options = shallowClone(options);

  // Set default mechanism
  if (!options.authMechanism) {
    options.authMechanism = 'DEFAULT';
  } else if (
    options.authMechanism !== 'GSSAPI' &&
    options.authMechanism !== 'DEFAULT' &&
    options.authMechanism !== 'MONGODB-CR' &&
    options.authMechanism !== 'MONGODB-X509' &&
    options.authMechanism !== 'SCRAM-SHA-1' &&
    options.authMechanism !== 'PLAIN'
  ) {
    return handleCallback(
      callback,
      MongoError.create({
        message:
          'only DEFAULT, GSSAPI, PLAIN, MONGODB-X509, SCRAM-SHA-1 or MONGODB-CR is supported by authMechanism',
        driver: true
      })
    );
  }

  // If we have a callback fallback
  if (typeof callback === 'function')
    return authenticate(self, username, password, options, function(err, r) {
      // Support failed auth method
      if (err && err.message && err.message.indexOf('saslStart') !== -1) err.code = 59;
      // Reject error
      if (err) return callback(err, r);
      callback(null, r);
    });

  // Return a promise
  return new self.s.promiseLibrary(function(resolve, reject) {
    authenticate(self, username, password, options, function(err, r) {
      // Support failed auth method
      if (err && err.message && err.message.indexOf('saslStart') !== -1) err.code = 59;
      // Reject error
      if (err) return reject(err);
      resolve(r);
    });
  });
};