/node_modules/mongodb-core/lib/auth/mongocr.js

https://bitbucket.org/coleman333/smartsite · JavaScript · 181 lines · 105 code · 20 blank · 56 comment · 32 complexity · df0bb4d96d67eed757dea8a58e1d1168 MD5 · raw file

  1. "use strict";
  2. var f = require('util').format
  3. , crypto = require('crypto')
  4. , Query = require('../connection/commands').Query
  5. , MongoError = require('../error');
  6. var AuthSession = function(db, username, password) {
  7. this.db = db;
  8. this.username = username;
  9. this.password = password;
  10. }
  11. AuthSession.prototype.equal = function(session) {
  12. return session.db == this.db
  13. && session.username == this.username
  14. && session.password == this.password;
  15. }
  16. /**
  17. * Creates a new MongoCR authentication mechanism
  18. * @class
  19. * @return {MongoCR} A cursor instance
  20. */
  21. var MongoCR = function(bson) {
  22. this.bson = bson;
  23. this.authStore = [];
  24. }
  25. // Add to store only if it does not exist
  26. var addAuthSession = function(authStore, session) {
  27. var found = false;
  28. for(var i = 0; i < authStore.length; i++) {
  29. if(authStore[i].equal(session)) {
  30. found = true;
  31. break;
  32. }
  33. }
  34. if(!found) authStore.push(session);
  35. }
  36. /**
  37. * Authenticate
  38. * @method
  39. * @param {{Server}|{ReplSet}|{Mongos}} server Topology the authentication method is being called on
  40. * @param {[]Connections} connections Connections to authenticate using this authenticator
  41. * @param {string} db Name of the database
  42. * @param {string} username Username
  43. * @param {string} password Password
  44. * @param {authResultCallback} callback The callback to return the result from the authentication
  45. * @return {object}
  46. */
  47. MongoCR.prototype.auth = function(server, connections, db, username, password, callback) {
  48. var self = this;
  49. // Total connections
  50. var count = connections.length;
  51. if(count == 0) return callback(null, null);
  52. // Valid connections
  53. var numberOfValidConnections = 0;
  54. var errorObject = null;
  55. // For each connection we need to authenticate
  56. while(connections.length > 0) {
  57. // Execute MongoCR
  58. var executeMongoCR = function(connection) {
  59. // Write the commmand on the connection
  60. server(connection, new Query(self.bson, f("%s.$cmd", db), {
  61. getnonce:1
  62. }, {
  63. numberToSkip: 0, numberToReturn: 1
  64. }), function(err, r) {
  65. var nonce = null;
  66. var key = null;
  67. // Adjust the number of connections left
  68. // Get nonce
  69. if(err == null) {
  70. nonce = r.result.nonce;
  71. // Use node md5 generator
  72. var md5 = crypto.createHash('md5');
  73. // Generate keys used for authentication
  74. md5.update(username + ":mongo:" + password, 'utf8');
  75. var hash_password = md5.digest('hex');
  76. // Final key
  77. md5 = crypto.createHash('md5');
  78. md5.update(nonce + username + hash_password, 'utf8');
  79. key = md5.digest('hex');
  80. }
  81. // Execute command
  82. // Write the commmand on the connection
  83. server(connection, new Query(self.bson, f("%s.$cmd", db), {
  84. authenticate: 1, user: username, nonce: nonce, key:key
  85. }, {
  86. numberToSkip: 0, numberToReturn: 1
  87. }), function(err, r) {
  88. count = count - 1;
  89. // If we have an error
  90. if(err) {
  91. errorObject = err;
  92. } else if(r.result['$err']) {
  93. errorObject = r.result;
  94. } else if(r.result['errmsg']) {
  95. errorObject = r.result;
  96. } else {
  97. numberOfValidConnections = numberOfValidConnections + 1;
  98. }
  99. // We have authenticated all connections
  100. if(count == 0 && numberOfValidConnections > 0) {
  101. // Store the auth details
  102. addAuthSession(self.authStore, new AuthSession(db, username, password));
  103. // Return correct authentication
  104. callback(null, true);
  105. } else if(count == 0) {
  106. if(errorObject == null) errorObject = new MongoError(f("failed to authenticate using mongocr"));
  107. callback(errorObject, false);
  108. }
  109. });
  110. });
  111. }
  112. var _execute = function(_connection) {
  113. process.nextTick(function() {
  114. executeMongoCR(_connection);
  115. });
  116. }
  117. _execute(connections.shift());
  118. }
  119. }
  120. /**
  121. * Remove authStore credentials
  122. * @method
  123. * @param {string} db Name of database we are removing authStore details about
  124. * @return {object}
  125. */
  126. MongoCR.prototype.logout = function(dbName) {
  127. this.authStore = this.authStore.filter(function(x) {
  128. return x.db != dbName;
  129. });
  130. }
  131. /**
  132. * Re authenticate pool
  133. * @method
  134. * @param {{Server}|{ReplSet}|{Mongos}} server Topology the authentication method is being called on
  135. * @param {[]Connections} connections Connections to authenticate using this authenticator
  136. * @param {authResultCallback} callback The callback to return the result from the authentication
  137. * @return {object}
  138. */
  139. MongoCR.prototype.reauthenticate = function(server, connections, callback) {
  140. var authStore = this.authStore.slice(0);
  141. var count = authStore.length;
  142. if(count == 0) return callback(null, null);
  143. // Iterate over all the auth details stored
  144. for(var i = 0; i < authStore.length; i++) {
  145. this.auth(server, connections, authStore[i].db, authStore[i].username, authStore[i].password, function(err) {
  146. count = count - 1;
  147. // Done re-authenticating
  148. if(count == 0) {
  149. callback(err, null);
  150. }
  151. });
  152. }
  153. }
  154. /**
  155. * This is a result from a authentication strategy
  156. *
  157. * @callback authResultCallback
  158. * @param {error} error An error object. Set to null if no error present
  159. * @param {boolean} result The result of the authentication process
  160. */
  161. module.exports = MongoCR;