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