Skip to content
This repository
Browse code

Add magical auth command.

Authentication is now remembered by the client and will be automatically sent to the server
on every connection, including any reconnections.
  • Loading branch information...
commit 1a14e24faa130c561ce75d138a54f1ecddb45c6e 1 parent 2534f74
Matt Ranney authored February 27, 2011
7  README.md
Source Rendered
@@ -181,6 +181,13 @@ objects instead of JavaScript Strings.
181 181
 
182 182
 `createClient()` returns a `RedisClient` object that is named `client` in all of the examples here.
183 183
 
  184
+## client.auth(password, callback)
  185
+
  186
+When connecting to Redis servers that require authentication, the `AUTH` command must be sent as the
  187
+first command after connecting.  This can be tricky to coordinate with reconnections, the ready check,
  188
+etc.  To make this easier, `client.auth()` stashes `password` and will send it after each connection,
  189
+including reconnections.  `callback` is invoked only once, after the response to the very first
  190
+`AUTH` command sent.
184 191
 
185 192
 ## client.end()
186 193
 
7  changelog.md
Source Rendered
... ...
@@ -1,6 +1,13 @@
1 1
 Changelog
2 2
 =========
3 3
 
  4
+## v0.5.7 - February 27, 2011
  5
+
  6
+Add magical auth command.
  7
+
  8
+Authentication is now remembered by the client and will be automatically sent to the server
  9
+on every connection, including any reconnections.
  10
+
4 11
 ## v0.5.6 - February 22, 2011
5 12
 
6 13
 Fix bug in ready check with `return_buffers` set to `true`.
10  examples/auth.js
... ...
@@ -1,13 +1,5 @@
1  
-// Note - Eventually this functionality will be built in to the client library
2  
-
3 1
 var redis  = require("redis"),
4 2
     client = redis.createClient();
5 3
 
6  
-// whenever the client connects, make sure to auth
7  
-client.on("connect", function () {
8  
-    client.auth("somepass", redis.print);
9  
-});
10  
-
  4
+// This command is magical.  Client stashes the password and will issue on every connect.
11 5
 client.auth("somepass");
12  
-
13  
-// then do whatever you want
3  examples/pub_sub.js
@@ -30,10 +30,9 @@ client1.on("message", function (channel, message) {
30 30
     }
31 31
 });
32 32
 
33  
-client1.incr("did a thing");
34  
-
35 33
 client1.on("ready", function () {
36 34
     // if you need auth, do it here
  35
+    client1.incr("did a thing");
37 36
     client1.subscribe("a nice channel", "another one");
38 37
 });
39 38
 
100  index.js
@@ -50,6 +50,7 @@ function RedisClient(stream, options) {
50 50
     this.subscriptions = false;
51 51
     this.closing = false;
52 52
     this.server_info = {};
  53
+    this.auth_pass = null;
53 54
 
54 55
     var parser_module, self = this;
55 56
 
@@ -90,30 +91,9 @@ function RedisClient(stream, options) {
90 91
     });
91 92
 
92 93
     this.stream.on("connect", function () {
93  
-        if (exports.debug_mode) {
94  
-            console.log("Stream connected fd " + self.stream.fd);
95  
-        }
96  
-        self.connected = true;
97  
-        self.ready = false;
98  
-        self.connections += 1;
99  
-        self.command_queue = new Queue();
100  
-        self.emitted_end = false;
101  
-
102  
-        self.retry_timer = null;
103  
-        self.retry_delay = 250;
104  
-        self.stream.setNoDelay();
105  
-        self.stream.setTimeout(0);
106  
-
107  
-        self.emit("connect");
108  
-
109  
-        if (self.options.no_ready_check) {
110  
-            self.ready = true;
111  
-            self.send_offline_queue();
112  
-        } else {
113  
-            self.ready_check();
114  
-        }
  94
+        self.on_connect();
115 95
     });
116  
-    
  96
+
117 97
     this.stream.on("data", function (buffer_from_socket) {
118 98
         self.on_data(buffer_from_socket);
119 99
     });
@@ -164,6 +144,55 @@ function RedisClient(stream, options) {
164 144
 util.inherits(RedisClient, events.EventEmitter);
165 145
 exports.RedisClient = RedisClient;
166 146
 
  147
+RedisClient.prototype.on_connect = function () {
  148
+    if (exports.debug_mode) {
  149
+        console.log("Stream connected " + this.host + ":" + this.port + " fd " + this.stream.fd);
  150
+    }
  151
+    var self = this;
  152
+
  153
+    this.connected = true;
  154
+    this.ready = false;
  155
+    this.connections += 1;
  156
+    this.command_queue = new Queue();
  157
+    this.emitted_end = false;
  158
+    this.retry_timer = null;
  159
+    this.retry_delay = 250;
  160
+    this.stream.setNoDelay();
  161
+    this.stream.setTimeout(0);
  162
+
  163
+    if (this.auth_pass) {
  164
+        if (exports.debug_mode) {
  165
+            console.log("Sending auth to " + this.host + ":" + this.port + " fd " + this.stream.fd);
  166
+        }
  167
+        self.send_anyway = true;
  168
+        self.send_command("auth", this.auth_pass, function (err, res) {
  169
+            if (err) {
  170
+                return self.emit("error", "Auth error: " + err);
  171
+            }
  172
+            if (res.toString() !== "OK") {
  173
+                return self.emit("error", "Auth failed: " + res.toString());
  174
+            }
  175
+            if (exports.debug_mode) {
  176
+                console.log("Auth succeeded " + self.host + ":" + self.port + " fd " + self.stream.fd);
  177
+            }
  178
+            if (self.auth_callback) {
  179
+                self.auth_callback(err, res);
  180
+                self.auth_callback = null;
  181
+            }
  182
+        });
  183
+        self.send_anyway = false;
  184
+    }
  185
+
  186
+    this.emit("connect");
  187
+
  188
+    if (this.options.no_ready_check) {
  189
+        this.ready = true;
  190
+        this.send_offline_queue();
  191
+    } else {
  192
+        this.ready_check();
  193
+    }
  194
+};
  195
+
167 196
 RedisClient.prototype.ready_check = function () {
168 197
     var self = this;
169 198
 
@@ -175,8 +204,7 @@ RedisClient.prototype.ready_check = function () {
175 204
         self.send_anyway = true;  // secret flag to send_command to send something even if not "ready"
176 205
         self.info(function (err, res) {
177 206
             if (err) {
178  
-                self.emit("error", "Ready check failed: " + err);
179  
-                return;
  207
+                return self.emit("error", "Ready check failed: " + err);
180 208
             }
181 209
 
182 210
             var lines = res.toString().split("\r\n"), obj = {}, retry_time;
@@ -291,7 +319,7 @@ RedisClient.prototype.connection_gone = function (why) {
291 319
 
292 320
 RedisClient.prototype.on_data = function (data) {
293 321
     if (exports.debug_mode) {
294  
-        console.log("net read fd " + this.stream.fd + ": " + data.toString());
  322
+        console.log("net read " + this.host + ":" + this.port + " fd " + this.stream.fd + ": " + data.toString());
295 323
     }
296 324
     
297 325
     try {
@@ -480,7 +508,7 @@ RedisClient.prototype.send_command = function () {
480 508
             command_str += "$" + Buffer.byteLength(arg) + "\r\n" + arg + "\r\n";
481 509
         }
482 510
         if (exports.debug_mode) {
483  
-            console.log("send fd " + this.stream.fd + ": " + command_str);
  511
+            console.log("send " + this.host + ":" + this.port + " fd " + this.stream.fd + ": " + command_str);
484 512
         }
485 513
         stream.write(command_str);
486 514
     } else {
@@ -547,7 +575,7 @@ function Multi(client, args) {
547 575
     //bit commands
548 576
     "getbit", "setbit", "getrange", "setrange",
549 577
     // misc
550  
-    "getset", "mset", "msetnx", "randomkey", "select", "move", "rename", "renamenx", "expire", "expireat", "keys", "dbsize", "auth", "ping", "echo",
  578
+    "getset", "mset", "msetnx", "randomkey", "select", "move", "rename", "renamenx", "expire", "expireat", "keys", "dbsize", "ping", "echo",
551 579
     "save", "bgsave", "bgwriteaof", "shutdown", "lastsave", "type", "sync", "flushdb", "flushall", "sort", "info", 
552 580
     "monitor", "ttl", "persist", "slaveof", "debug", "config", "subscribe", "unsubscribe", "psubscribe", "punsubscribe", "publish", "watch", "unwatch",
553 581
     "quit"
@@ -568,6 +596,22 @@ function Multi(client, args) {
568 596
     Multi.prototype[command.toUpperCase()] = Multi.prototype[command];
569 597
 });
570 598
 
  599
+// Stash auth for connect and reconnect.  Send immediately if already connected.
  600
+RedisClient.prototype.auth = function () {
  601
+    var args = to_array(arguments);
  602
+    this.auth_pass = args[0];
  603
+    this.auth_callback = args[1];
  604
+    if (exports.debug_mode) {
  605
+        console.log("Saving auth as " + this.auth_pass);
  606
+    }
  607
+
  608
+    if (this.connected) {
  609
+        args.unshift("auth");
  610
+        this.send_command.apply(this, args);
  611
+    }
  612
+};
  613
+RedisClient.prototype.AUTH = RedisClient.prototype.auth;
  614
+
571 615
 RedisClient.prototype.hmset = function () {
572 616
     var args = to_array(arguments), tmp_args;
573 617
     if (args.length >= 2 && typeof args[0] === "string" && typeof args[1] === "object") {
2  package.json
... ...
@@ -1,5 +1,5 @@
1 1
 {   "name" : "redis",
2  
-    "version" : "0.5.6",
  2
+    "version" : "0.5.7",
3 3
     "description" : "Redis client library",
4 4
     "author": "Matt Ranney <mjr@ranney.com>",
5 5
     "contributors": [
10  test.js
@@ -3,6 +3,7 @@ var redis = require("./index"),
3 3
     client = redis.createClient(),
4 4
     client2 = redis.createClient(),
5 5
     client3 = redis.createClient(),
  6
+    client4 = redis.createClient(9006, "filefish.redistogo.com"),
6 7
     assert = require("assert"),
7 8
     util = require("./lib/util").util,
8 9
     test_db_num = 15, // this DB will be flushed and used for testing
@@ -1049,6 +1050,7 @@ function run_next_test() {
1049 1050
         console.log('\n  completed \x1b[32m%d\x1b[0m tests in \x1b[33m%d\x1b[0m ms\n', test_count, new Date() - all_start);
1050 1051
         client.quit();
1051 1052
         client2.quit();
  1053
+        client4.quit();
1052 1054
     }
1053 1055
 }
1054 1056
 
@@ -1066,6 +1068,14 @@ client.on('end', function () {
1066 1068
   ended = true;
1067 1069
 });
1068 1070
 
  1071
+// TODO - need a better way to test auth, maybe auto-config a local Redis server?
  1072
+client4.auth("664b1b6aaf134e1ec281945a8de702a9", function (err, res) {
  1073
+    if (err) {
  1074
+        assert.fail(err, name);
  1075
+    }
  1076
+    assert.strictEqual("OK", res.toString(), "auth");
  1077
+});
  1078
+
1069 1079
 // Exit immediately on connection failure, which triggers "exit", below, which fails the test
1070 1080
 client.on("error", function (err) {
1071 1081
     console.error("client: " + err.stack);

0 notes on commit 1a14e24

Please sign in to comment.
Something went wrong with that request. Please try again.