Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpredis/phpredis.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavlo Yatsukhnenko <yatsukhnenko@gmail.com>2019-01-15 11:07:30 +0300
committerPavel Yatsukhnenko <p.yatsukhnenko@digitalscreens.com.ua>2019-01-18 00:05:52 +0300
commitc5994f2a42b8a348af92d3acb4edff1328ad8ce1 (patch)
treeb2f4cdc3d7986860ef4bf5e311001820cb57bd2b
parente145f8582ab9aa5bb6e986298be2e47d8063c8a0 (diff)
RedisCluster auth
-rw-r--r--cluster.markdown7
-rw-r--r--cluster_library.c31
-rw-r--r--cluster_library.h4
-rw-r--r--common.h2
-rw-r--r--library.c6
-rw-r--r--library.h1
-rw-r--r--redis.c1
-rw-r--r--redis_cluster.c44
-rw-r--r--redis_session.c19
9 files changed, 90 insertions, 25 deletions
diff --git a/cluster.markdown b/cluster.markdown
index 4dcbc2ba..3260bb79 100644
--- a/cluster.markdown
+++ b/cluster.markdown
@@ -19,6 +19,9 @@ $obj_cluster = new RedisCluster(NULL, Array("host:7000", "host:7001"), 1.5, 1.5)
// persistent connections to each node.
$obj_cluster = new RedisCluster(NULL, Array("host:7000", "host:7001"), 1.5, 1.5, true);
+// Connect with cluster using password.
+$obj_cluster = new RedisCluster(NULL, Array("host:7000", "host:7001"), 1.5, 1.5, true, "password");
+
</pre>
#### Loading a cluster configuration by name
@@ -29,6 +32,7 @@ In order to load a named array, one must first define the seed nodes in redis.in
redis.clusters.seeds = "mycluster[]=localhost:7000&test[]=localhost:7001"
redis.clusters.timeout = "mycluster=5"
redis.clusters.read_timeout = "mycluster=10"
+redis.clusters.auth = "mycluster=password"
</pre>
Then, this cluster can be loaded by doing the following
@@ -161,7 +165,7 @@ To do this, you must configure your `session.save_handler` and `session.save_pat
~~~
session.save_handler = rediscluster
-session.save_path = "seed[]=host1:port1&seed[]=host2:port2&seed[]=hostN:portN&timeout=2&read_timeout=2&failover=error&persistent=1"
+session.save_path = "seed[]=host1:port1&seed[]=host2:port2&seed[]=hostN:portN&timeout=2&read_timeout=2&failover=error&persistent=1&auth=password"
~~~
### session.session_handler
@@ -175,5 +179,6 @@ The save path for cluster based session storage takes the form of a PHP GET requ
* _persistent_: Tells phpredis whether persistent connections should be used.
* _distribute_: phpredis will randomly distribute session reads between masters and any attached slaves (load balancing).
* _failover (string)_: How phpredis should distribute session reads between master and slave nodes.
+* _auth (string, empty by default)_: The password used to authenticate with the server prior to sending commands.
* * _none_ : phpredis will only communicate with master nodes
* * _error_: phpredis will communicate with master nodes unless one failes, in which case an attempt will be made to read session information from a slave.
diff --git a/cluster_library.c b/cluster_library.c
index 1f6d4160..b0f7b53a 100644
--- a/cluster_library.c
+++ b/cluster_library.c
@@ -259,6 +259,17 @@ cluster_read_sock_resp(RedisSock *redis_sock, REDIS_REPLY_TYPE type,
return r;
}
+/* Helper to open connection and send AUTH if necessary */
+static zend_always_inline int
+cluster_sock_open(RedisSock *redis_sock TSRMLS_DC)
+{
+ zend_bool need_auth = (redis_sock->auth && redis_sock->status != REDIS_SOCK_STATUS_CONNECTED);
+ if (!redis_sock_server_open(redis_sock TSRMLS_CC) && (!need_auth || !redis_sock_auth(redis_sock TSRMLS_CC))) {
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+
/*
* Helpers to send various 'control type commands to a specific node, e.g.
* MULTI, ASKING, READONLY, READWRITE, etc
@@ -654,6 +665,10 @@ cluster_node_create(redisCluster *c, char *host, size_t host_len,
node->sock = redis_sock_create(host, host_len, port, c->timeout,
c->read_timeout, c->persistent, NULL, 0);
+ if (c->auth) {
+ node->sock->auth = zend_string_copy(c->auth);
+ }
+
return node;
}
@@ -824,6 +839,7 @@ PHP_REDIS_API redisCluster *cluster_create(double timeout, double read_timeout,
c->read_timeout = read_timeout;
c->failover = failover;
c->persistent = persistent;
+ c->auth = NULL;
c->err = NULL;
/* Set up our waitms based on timeout */
@@ -858,6 +874,9 @@ cluster_free(redisCluster *c, int free_ctx TSRMLS_DC)
efree(c->seeds);
efree(c->nodes);
+ /* Free auth info we've got */
+ if (c->auth) zend_string_release(c->auth);
+
/* Free any error we've got */
if (c->err) zend_string_release(c->err);
@@ -925,6 +944,11 @@ cluster_init_seeds(redisCluster *cluster, HashTable *ht_seeds) {
(unsigned short)atoi(psep+1), cluster->timeout,
cluster->read_timeout, cluster->persistent, NULL, 0);
+ // Set auth information if specified
+ if (cluster->auth) {
+ redis_sock->auth = zend_string_copy(cluster->auth);
+ }
+
// Index this seed by host/port
key_len = snprintf(key, sizeof(key), "%s:%u", ZSTR_VAL(redis_sock->host),
redis_sock->port);
@@ -948,7 +972,7 @@ PHP_REDIS_API int cluster_map_keyspace(redisCluster *c TSRMLS_DC) {
// Iterate over seeds until we can get slots
ZEND_HASH_FOREACH_PTR(c->seeds, seed) {
// Attempt to connect to this seed node
- if (seed == NULL || redis_sock_connect(seed TSRMLS_CC) != 0) {
+ if (seed == NULL || cluster_sock_open(seed TSRMLS_CC) != 0) {
continue;
}
@@ -1119,11 +1143,6 @@ static int cluster_dist_write(redisCluster *c, const char *cmd, size_t sz,
redis_sock = cluster_slot_sock(c, c->cmd_slot, nodes[i]);
if (!redis_sock) continue;
- /* Connect to this node if we haven't already */
- if(redis_sock_server_open(redis_sock TSRMLS_CC)) {
- continue;
- }
-
/* If we're not on the master, attempt to send the READONLY command to
* this slave, and skip it if that fails */
if (nodes[i] == 0 || redis_sock->readonly ||
diff --git a/cluster_library.h b/cluster_library.h
index 979b228d..366b395a 100644
--- a/cluster_library.h
+++ b/cluster_library.h
@@ -62,7 +62,7 @@
/* Protected sending of data down the wire to a RedisSock->stream */
#define CLUSTER_SEND_PAYLOAD(sock, buf, len) \
- (sock && !redis_sock_server_open(sock TSRMLS_CC) && sock->stream && !redis_check_eof(sock, 1 TSRMLS_CC) && \
+ (sock && !cluster_sock_open(sock TSRMLS_CC) && sock->stream && !redis_check_eof(sock, 1 TSRMLS_CC) && \
php_stream_write(sock->stream, buf, len)==len)
/* Macro to read our reply type character */
@@ -170,6 +170,8 @@ typedef struct redisCluster {
zend_object std;
#endif
+ zend_string *auth;
+
/* Timeout and read timeout (for normal operations) */
double timeout;
double read_timeout;
diff --git a/common.h b/common.h
index 9642fdd4..e17d760f 100644
--- a/common.h
+++ b/common.h
@@ -68,6 +68,8 @@ zend_string_realloc(zend_string *s, size_t len, int persistent)
return zstr;
}
+#define zend_string_copy(s) zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), 0)
+
#define zend_string_equal_val(s1, s2) !memcmp(ZSTR_VAL(s1), ZSTR_VAL(s2), ZSTR_LEN(s1))
#define zend_string_equal_content(s1, s2) (ZSTR_LEN(s1) == ZSTR_LEN(s2) && zend_string_equal_val(s1, s2))
#define zend_string_equals(s1, s2) (s1 == s2 || zend_string_equal_content(s1, s2))
diff --git a/library.c b/library.c
index 79015d4b..93a44600 100644
--- a/library.c
+++ b/library.c
@@ -90,7 +90,9 @@ static int reselect_db(RedisSock *redis_sock TSRMLS_DC) {
}
/* Helper to resend AUTH <password> in the case of a reconnect */
-static int resend_auth(RedisSock *redis_sock TSRMLS_DC) {
+PHP_REDIS_API int
+redis_sock_auth(RedisSock *redis_sock TSRMLS_DC)
+{
char *cmd, *response;
int cmd_len, response_len;
@@ -205,7 +207,7 @@ redis_check_eof(RedisSock *redis_sock, int no_throw TSRMLS_DC)
errno = 0;
if (php_stream_eof(redis_sock->stream) == 0) {
/* If we're using a password, attempt a reauthorization */
- if (redis_sock->auth && resend_auth(redis_sock TSRMLS_CC) != 0) {
+ if (redis_sock->auth && redis_sock_auth(redis_sock TSRMLS_CC) != 0) {
errmsg = "AUTH failed while reconnecting";
break;
}
diff --git a/library.h b/library.h
index 381a63bc..8e82081e 100644
--- a/library.h
+++ b/library.h
@@ -45,6 +45,7 @@ PHP_REDIS_API void redis_type_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *
PHP_REDIS_API RedisSock* redis_sock_create(char *host, int host_len, unsigned short port, double timeout, double read_timeout, int persistent, char *persistent_id, long retry_interval);
PHP_REDIS_API int redis_sock_connect(RedisSock *redis_sock TSRMLS_DC);
PHP_REDIS_API int redis_sock_server_open(RedisSock *redis_sock TSRMLS_DC);
+PHP_REDIS_API int redis_sock_auth(RedisSock *redis_sock TSRMLS_DC);
PHP_REDIS_API int redis_sock_disconnect(RedisSock *redis_sock, int force TSRMLS_DC);
PHP_REDIS_API zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab);
PHP_REDIS_API int redis_sock_read_single_line(RedisSock *redis_sock, char *buffer,
diff --git a/redis.c b/redis.c
index 42cdbc6c..e88eb572 100644
--- a/redis.c
+++ b/redis.c
@@ -69,6 +69,7 @@ PHP_INI_BEGIN()
PHP_INI_ENTRY("redis.arrays.retryinterval", "0", PHP_INI_ALL, NULL)
/* redis cluster */
+ PHP_INI_ENTRY("redis.clusters.auth", "", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.clusters.persistent", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.clusters.read_timeout", "0", PHP_INI_ALL, NULL)
PHP_INI_ENTRY("redis.clusters.seeds", "", PHP_INI_ALL, NULL)
diff --git a/redis_cluster.c b/redis_cluster.c
index e8cd4038..9bc42547 100644
--- a/redis_cluster.c
+++ b/redis_cluster.c
@@ -46,6 +46,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ctor, 0, 0, 1)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, read_timeout)
ZEND_ARG_INFO(0, persistent)
+ ZEND_ARG_INFO(0, auth)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_del, 0, 0, 1)
@@ -397,8 +398,10 @@ free_cluster_context(zend_object *object)
#endif
/* Attempt to connect to a Redis cluster provided seeds and timeout options */
-void redis_cluster_init(redisCluster *c, HashTable *ht_seeds, double timeout,
- double read_timeout, int persistent TSRMLS_DC)
+static void
+redis_cluster_init(redisCluster *c, HashTable *ht_seeds,
+ double timeout, double read_timeout, int persistent,
+ char *auth, strlen_t auth_len TSRMLS_DC)
{
// Validate timeout
if (timeout < 0L || timeout > INT_MAX) {
@@ -417,6 +420,11 @@ void redis_cluster_init(redisCluster *c, HashTable *ht_seeds, double timeout,
zend_throw_exception(redis_cluster_exception_ce,
"Must pass seeds", 0 TSRMLS_CC);
}
+
+ if (auth && auth_len > 0) {
+ c->auth = zend_string_init(auth, auth_len, 0);
+ }
+
/* Set our timeout and read_timeout which we'll pass through to the
* socket type operations */
c->timeout = timeout;
@@ -438,8 +446,9 @@ void redis_cluster_init(redisCluster *c, HashTable *ht_seeds, double timeout,
/* Attempt to load a named cluster configured in php.ini */
void redis_cluster_load(redisCluster *c, char *name, int name_len TSRMLS_DC) {
- zval z_seeds, z_timeout, z_read_timeout, z_persistent, *z_value;
- char *iptr;
+ zval z_seeds, z_timeout, z_read_timeout, z_persistent, z_auth, *z_value;
+ char *iptr, *auth = NULL;
+ strlen_t auth_len = 0;
double timeout = 0, read_timeout = 0;
int persistent = 0;
HashTable *ht_seeds = NULL;
@@ -500,14 +509,27 @@ void redis_cluster_load(redisCluster *c, char *name, int name_len TSRMLS_DC) {
}
}
+ /* Cluster auth */
+ array_init(&z_auth);
+ if ((iptr = INI_STR("redis.clusters.auth")) != NULL) {
+ sapi_module.treat_data(PARSE_STRING, estrdup(iptr), &z_auth TSRMLS_CC);
+ }
+ if ((z_value = zend_hash_str_find(Z_ARRVAL(z_auth), name, name_len)) != NULL &&
+ Z_TYPE_P(z_value) == IS_STRING && Z_STRLEN_P(z_value) > 0
+ ) {
+ auth = Z_STRVAL_P(z_value);
+ auth_len = Z_STRLEN_P(z_value);
+ }
+
/* Attempt to create/connect to the cluster */
- redis_cluster_init(c, ht_seeds, timeout, read_timeout, persistent TSRMLS_CC);
+ redis_cluster_init(c, ht_seeds, timeout, read_timeout, persistent, auth, auth_len TSRMLS_CC);
/* Clean up our arrays */
zval_dtor(&z_seeds);
zval_dtor(&z_timeout);
zval_dtor(&z_read_timeout);
zval_dtor(&z_persistent);
+ zval_dtor(&z_auth);
}
/*
@@ -517,17 +539,17 @@ void redis_cluster_load(redisCluster *c, char *name, int name_len TSRMLS_DC) {
/* Create a RedisCluster Object */
PHP_METHOD(RedisCluster, __construct) {
zval *object, *z_seeds = NULL;
- char *name;
- strlen_t name_len;
+ char *name, *auth = NULL;
+ strlen_t name_len, auth_len = 0;
double timeout = 0.0, read_timeout = 0.0;
zend_bool persistent = 0;
redisCluster *context = GET_CONTEXT();
// Parse arguments
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
- "Os!|addb", &object, redis_cluster_ce, &name,
- &name_len, &z_seeds, &timeout,
- &read_timeout, &persistent) == FAILURE)
+ "Os!|addbs", &object, redis_cluster_ce, &name,
+ &name_len, &z_seeds, &timeout, &read_timeout,
+ &persistent, &auth, &auth_len) == FAILURE)
{
RETURN_FALSE;
}
@@ -543,7 +565,7 @@ PHP_METHOD(RedisCluster, __construct) {
* to a named cluster, stored in php.ini, otherwise we'll need manual seeds */
if (ZEND_NUM_ARGS() > 1) {
redis_cluster_init(context, Z_ARRVAL_P(z_seeds), timeout, read_timeout,
- persistent TSRMLS_CC);
+ persistent, auth, auth_len TSRMLS_CC);
} else {
redis_cluster_load(context, name, name_len TSRMLS_CC);
}
diff --git a/redis_session.c b/redis_session.c
index 2127f3e6..31f6b149 100644
--- a/redis_session.c
+++ b/redis_session.c
@@ -992,9 +992,9 @@ PS_OPEN_FUNC(rediscluster) {
zval z_conf, *z_val;
HashTable *ht_conf, *ht_seeds;
double timeout = 0, read_timeout = 0;
- int persistent = 0;
- int retval, prefix_len, failover = REDIS_FAILOVER_NONE;
- char *prefix;
+ int retval, persistent = 0, failover = REDIS_FAILOVER_NONE;
+ strlen_t prefix_len, auth_len = 0;
+ char *prefix, *auth = NULL;
/* Parse configuration for session handler */
array_init(&z_conf);
@@ -1041,7 +1041,7 @@ PS_OPEN_FUNC(rediscluster) {
/* Look for a specific failover setting */
if ((z_val = zend_hash_str_find(ht_conf, "failover", sizeof("failover") - 1)) != NULL &&
- Z_TYPE_P(z_val) == IS_STRING
+ Z_TYPE_P(z_val) == IS_STRING && Z_STRLEN_P(z_val) > 0
) {
if (!strcasecmp(Z_STRVAL_P(z_val), "error")) {
failover = REDIS_FAILOVER_ERROR;
@@ -1050,7 +1050,18 @@ PS_OPEN_FUNC(rediscluster) {
}
}
+ /* Look for a specific auth setting */
+ if ((z_val = zend_hash_str_find(ht_conf, "auth", sizeof("auth") - 1)) != NULL &&
+ Z_TYPE_P(z_val) == IS_STRING && Z_STRLEN_P(z_val) > 0
+ ) {
+ auth = Z_STRVAL_P(z_val);
+ auth_len = Z_STRLEN_P(z_val);
+ }
+
c = cluster_create(timeout, read_timeout, failover, persistent);
+ if (auth && auth_len > 0) {
+ c->auth = zend_string_init(auth, auth_len, 0);
+ }
if (!cluster_init_seeds(c, ht_seeds) && !cluster_map_keyspace(c TSRMLS_CC)) {
/* Set up our prefix */
c->flags->prefix = zend_string_init(prefix, prefix_len, 0);