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