plain.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. "use strict";
  2. var f = require('util').format
  3. , crypto = require('crypto')
  4. , Binary = require('bson').Binary
  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 Plain authentication mechanism
  18. * @class
  19. * @return {Plain} A cursor instance
  20. */
  21. var Plain = function() {
  22. this.authStore = [];
  23. }
  24. /**
  25. * Authenticate
  26. * @method
  27. * @param {{Server}|{ReplSet}|{Mongos}} server Topology the authentication method is being called on
  28. * @param {Pool} pool Connection pool for this topology
  29. * @param {string} db Name of the database
  30. * @param {string} username Username
  31. * @param {string} password Password
  32. * @param {authResultCallback} callback The callback to return the result from the authentication
  33. * @return {object}
  34. */
  35. Plain.prototype.auth = function(server, pool, db, username, password, callback) {
  36. var self = this;
  37. // Get all the connections
  38. var connections = pool.getAll();
  39. // Total connections
  40. var count = connections.length;
  41. if(count == 0) return callback(null, null);
  42. // Valid connections
  43. var numberOfValidConnections = 0;
  44. var credentialsValid = false;
  45. var errorObject = null;
  46. // For each connection we need to authenticate
  47. while(connections.length > 0) {
  48. // Execute MongoCR
  49. var execute = function(connection) {
  50. // Create payload
  51. var payload = new Binary(f("\x00%s\x00%s", username, password));
  52. // Let's start the sasl process
  53. var command = {
  54. saslStart: 1
  55. , mechanism: 'PLAIN'
  56. , payload: payload
  57. , autoAuthorize: 1
  58. };
  59. // Let's start the process
  60. server.command("$external.$cmd"
  61. , command
  62. , { connection: connection }, function(err, r) {
  63. // Adjust count
  64. count = count - 1;
  65. // If we have an error
  66. if(err) {
  67. errorObject = err;
  68. } else if(r.result['$err']) {
  69. errorObject = r.result;
  70. } else if(r.result['errmsg']) {
  71. errorObject = r.result;
  72. } else {
  73. credentialsValid = true;
  74. numberOfValidConnections = numberOfValidConnections + 1;
  75. }
  76. // We have authenticated all connections
  77. if(count == 0 && numberOfValidConnections > 0) {
  78. // Store the auth details
  79. addAuthSession(self.authStore, new AuthSession(db, username, password));
  80. // Return correct authentication
  81. callback(null, true);
  82. } else if(count == 0) {
  83. if(errorObject == null) errorObject = new MongoError(f("failed to authenticate using mongocr"));
  84. callback(errorObject, false);
  85. }
  86. });
  87. }
  88. // Get the connection
  89. execute(connections.shift());
  90. }
  91. }
  92. // Add to store only if it does not exist
  93. var addAuthSession = function(authStore, session) {
  94. var found = false;
  95. for(var i = 0; i < authStore.length; i++) {
  96. if(authStore[i].equal(session)) {
  97. found = true;
  98. break;
  99. }
  100. }
  101. if(!found) authStore.push(session);
  102. }
  103. /**
  104. * Re authenticate pool
  105. * @method
  106. * @param {{Server}|{ReplSet}|{Mongos}} server Topology the authentication method is being called on
  107. * @param {Pool} pool Connection pool for this topology
  108. * @param {authResultCallback} callback The callback to return the result from the authentication
  109. * @return {object}
  110. */
  111. Plain.prototype.reauthenticate = function(server, pool, callback) {
  112. var count = this.authStore.length;
  113. if(count == 0) return callback(null, null);
  114. // Iterate over all the auth details stored
  115. for(var i = 0; i < this.authStore.length; i++) {
  116. this.auth(server, pool, this.authStore[i].db, this.authStore[i].username, this.authStore[i].password, function(err, r) {
  117. count = count - 1;
  118. // Done re-authenticating
  119. if(count == 0) {
  120. callback(null, null);
  121. }
  122. });
  123. }
  124. }
  125. /**
  126. * This is a result from a authentication strategy
  127. *
  128. * @callback authResultCallback
  129. * @param {error} error An error object. Set to null if no error present
  130. * @param {boolean} result The result of the authentication process
  131. */
  132. module.exports = Plain;