Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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
@mranney authored
View
7 README.md
@@ -181,6 +181,13 @@ objects instead of JavaScript Strings.
`createClient()` returns a `RedisClient` object that is named `client` in all of the examples here.
+## client.auth(password, callback)
+
+When connecting to Redis servers that require authentication, the `AUTH` command must be sent as the
+first command after connecting. This can be tricky to coordinate with reconnections, the ready check,
+etc. To make this easier, `client.auth()` stashes `password` and will send it after each connection,
+including reconnections. `callback` is invoked only once, after the response to the very first
+`AUTH` command sent.
## client.end()
View
7 changelog.md
@@ -1,6 +1,13 @@
Changelog
=========
+## v0.5.7 - February 27, 2011
+
+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.
+
## v0.5.6 - February 22, 2011
Fix bug in ready check with `return_buffers` set to `true`.
View
10 examples/auth.js
@@ -1,13 +1,5 @@
-// Note - Eventually this functionality will be built in to the client library
-
var redis = require("redis"),
client = redis.createClient();
-// whenever the client connects, make sure to auth
-client.on("connect", function () {
- client.auth("somepass", redis.print);
-});
-
+// This command is magical. Client stashes the password and will issue on every connect.
client.auth("somepass");
-
-// then do whatever you want
View
3  examples/pub_sub.js
@@ -30,10 +30,9 @@ client1.on("message", function (channel, message) {
}
});
-client1.incr("did a thing");
-
client1.on("ready", function () {
// if you need auth, do it here
+ client1.incr("did a thing");
client1.subscribe("a nice channel", "another one");
});
View
100 index.js
@@ -50,6 +50,7 @@ function RedisClient(stream, options) {
this.subscriptions = false;
this.closing = false;
this.server_info = {};
+ this.auth_pass = null;
var parser_module, self = this;
@@ -90,30 +91,9 @@ function RedisClient(stream, options) {
});
this.stream.on("connect", function () {
- if (exports.debug_mode) {
- console.log("Stream connected fd " + self.stream.fd);
- }
- self.connected = true;
- self.ready = false;
- self.connections += 1;
- self.command_queue = new Queue();
- self.emitted_end = false;
-
- self.retry_timer = null;
- self.retry_delay = 250;
- self.stream.setNoDelay();
- self.stream.setTimeout(0);
-
- self.emit("connect");
-
- if (self.options.no_ready_check) {
- self.ready = true;
- self.send_offline_queue();
- } else {
- self.ready_check();
- }
+ self.on_connect();
});
-
+
this.stream.on("data", function (buffer_from_socket) {
self.on_data(buffer_from_socket);
});
@@ -164,6 +144,55 @@ function RedisClient(stream, options) {
util.inherits(RedisClient, events.EventEmitter);
exports.RedisClient = RedisClient;
+RedisClient.prototype.on_connect = function () {
+ if (exports.debug_mode) {
+ console.log("Stream connected " + this.host + ":" + this.port + " fd " + this.stream.fd);
+ }
+ var self = this;
+
+ this.connected = true;
+ this.ready = false;
+ this.connections += 1;
+ this.command_queue = new Queue();
+ this.emitted_end = false;
+ this.retry_timer = null;
+ this.retry_delay = 250;
+ this.stream.setNoDelay();
+ this.stream.setTimeout(0);
+
+ if (this.auth_pass) {
+ if (exports.debug_mode) {
+ console.log("Sending auth to " + this.host + ":" + this.port + " fd " + this.stream.fd);
+ }
+ self.send_anyway = true;
+ self.send_command("auth", this.auth_pass, function (err, res) {
+ if (err) {
+ return self.emit("error", "Auth error: " + err);
+ }
+ if (res.toString() !== "OK") {
+ return self.emit("error", "Auth failed: " + res.toString());
+ }
+ if (exports.debug_mode) {
+ console.log("Auth succeeded " + self.host + ":" + self.port + " fd " + self.stream.fd);
+ }
+ if (self.auth_callback) {
+ self.auth_callback(err, res);
+ self.auth_callback = null;
+ }
+ });
+ self.send_anyway = false;
+ }
+
+ this.emit("connect");
+
+ if (this.options.no_ready_check) {
+ this.ready = true;
+ this.send_offline_queue();
+ } else {
+ this.ready_check();
+ }
+};
+
RedisClient.prototype.ready_check = function () {
var self = this;
@@ -175,8 +204,7 @@ RedisClient.prototype.ready_check = function () {
self.send_anyway = true; // secret flag to send_command to send something even if not "ready"
self.info(function (err, res) {
if (err) {
- self.emit("error", "Ready check failed: " + err);
- return;
+ return self.emit("error", "Ready check failed: " + err);
}
var lines = res.toString().split("\r\n"), obj = {}, retry_time;
@@ -291,7 +319,7 @@ RedisClient.prototype.connection_gone = function (why) {
RedisClient.prototype.on_data = function (data) {
if (exports.debug_mode) {
- console.log("net read fd " + this.stream.fd + ": " + data.toString());
+ console.log("net read " + this.host + ":" + this.port + " fd " + this.stream.fd + ": " + data.toString());
}
try {
@@ -480,7 +508,7 @@ RedisClient.prototype.send_command = function () {
command_str += "$" + Buffer.byteLength(arg) + "\r\n" + arg + "\r\n";
}
if (exports.debug_mode) {
- console.log("send fd " + this.stream.fd + ": " + command_str);
+ console.log("send " + this.host + ":" + this.port + " fd " + this.stream.fd + ": " + command_str);
}
stream.write(command_str);
} else {
@@ -547,7 +575,7 @@ function Multi(client, args) {
//bit commands
"getbit", "setbit", "getrange", "setrange",
// misc
- "getset", "mset", "msetnx", "randomkey", "select", "move", "rename", "renamenx", "expire", "expireat", "keys", "dbsize", "auth", "ping", "echo",
+ "getset", "mset", "msetnx", "randomkey", "select", "move", "rename", "renamenx", "expire", "expireat", "keys", "dbsize", "ping", "echo",
"save", "bgsave", "bgwriteaof", "shutdown", "lastsave", "type", "sync", "flushdb", "flushall", "sort", "info",
"monitor", "ttl", "persist", "slaveof", "debug", "config", "subscribe", "unsubscribe", "psubscribe", "punsubscribe", "publish", "watch", "unwatch",
"quit"
@@ -568,6 +596,22 @@ function Multi(client, args) {
Multi.prototype[command.toUpperCase()] = Multi.prototype[command];
});
+// Stash auth for connect and reconnect. Send immediately if already connected.
+RedisClient.prototype.auth = function () {
+ var args = to_array(arguments);
+ this.auth_pass = args[0];
+ this.auth_callback = args[1];
+ if (exports.debug_mode) {
+ console.log("Saving auth as " + this.auth_pass);
+ }
+
+ if (this.connected) {
+ args.unshift("auth");
+ this.send_command.apply(this, args);
+ }
+};
+RedisClient.prototype.AUTH = RedisClient.prototype.auth;
+
RedisClient.prototype.hmset = function () {
var args = to_array(arguments), tmp_args;
if (args.length >= 2 && typeof args[0] === "string" && typeof args[1] === "object") {
View
2  package.json
@@ -1,5 +1,5 @@
{ "name" : "redis",
- "version" : "0.5.6",
+ "version" : "0.5.7",
"description" : "Redis client library",
"author": "Matt Ranney <mjr@ranney.com>",
"contributors": [
View
10 test.js
@@ -3,6 +3,7 @@ var redis = require("./index"),
client = redis.createClient(),
client2 = redis.createClient(),
client3 = redis.createClient(),
+ client4 = redis.createClient(9006, "filefish.redistogo.com"),
assert = require("assert"),
util = require("./lib/util").util,
test_db_num = 15, // this DB will be flushed and used for testing
@@ -1049,6 +1050,7 @@ function run_next_test() {
console.log('\n completed \x1b[32m%d\x1b[0m tests in \x1b[33m%d\x1b[0m ms\n', test_count, new Date() - all_start);
client.quit();
client2.quit();
+ client4.quit();
}
}
@@ -1066,6 +1068,14 @@ client.on('end', function () {
ended = true;
});
+// TODO - need a better way to test auth, maybe auto-config a local Redis server?
+client4.auth("664b1b6aaf134e1ec281945a8de702a9", function (err, res) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.strictEqual("OK", res.toString(), "auth");
+});
+
// Exit immediately on connection failure, which triggers "exit", below, which fails the test
client.on("error", function (err) {
console.error("client: " + err.stack);
Please sign in to comment.
Something went wrong with that request. Please try again.