Add authentication to Lettuce conn factory and pool

DATAREDIS-202
This commit is contained in:
Jennifer Hickey
2013-06-28 16:50:14 -07:00
parent 29b68e2808
commit 7b75924c40
7 changed files with 392 additions and 113 deletions

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.connection.lettuce;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.codec.RedisCodec;
import com.lambdaworks.redis.pubsub.RedisPubSubConnection;
/**
* Extension of {@link RedisClient} that calls auth on all new connections using
* the supplied credentials
*
* @author Jennifer Hickey
*
*/
public class AuthenticatingRedisClient extends RedisClient {
private String password;
public AuthenticatingRedisClient(String host, int port, String password) {
super(host, port);
this.password = password;
}
public AuthenticatingRedisClient(String host, String password) {
super(host);
this.password = password;
}
@Override
public <K, V> RedisConnection<K, V> connect(RedisCodec<K, V> codec) {
RedisConnection<K, V> conn = super.connect(codec);
conn.auth(password);
return conn;
}
@Override
public <K, V> RedisAsyncConnection<K, V> connectAsync(RedisCodec<K, V> codec) {
RedisAsyncConnection<K, V> conn = super.connectAsync(codec);
conn.auth(password);
return conn;
}
@Override
public <K, V> RedisPubSubConnection<K, V> connectPubSub(RedisCodec<K, V> codec) {
RedisPubSubConnection<K, V> conn = super.connectPubSub(codec);
conn.auth(password);
return conn;
}
}

View File

@@ -20,7 +20,9 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool.Config;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.connection.PoolException;
import org.springframework.util.Assert;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisClient;
@@ -31,10 +33,22 @@ import com.lambdaworks.redis.RedisClient;
* @author Jennifer Hickey
*
*/
public class DefaultLettucePool implements LettucePool {
private final GenericObjectPool internalPool;
private static final int DEFAULT_TIMEOUT = (int) TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS);
public class DefaultLettucePool implements LettucePool, InitializingBean {
private GenericObjectPool internalPool;
private RedisClient client;
private int dbIndex = 0;
private Config poolConfig = new Config();
private String hostName = "localhost";
private int port = 6379;
private String password;
private long timeout = TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS);
/**
* Constructs a new <code>DefaultLettucePool</code> instance with
* default settings.
*/
public DefaultLettucePool() {
}
/**
* Uses the {@link Config} and {@link RedisClient} defaults for configuring
@@ -46,7 +60,8 @@ public class DefaultLettucePool implements LettucePool {
* The Redis port
*/
public DefaultLettucePool(String hostName, int port) {
this(hostName, port, 0, DEFAULT_TIMEOUT, new Config());
this.hostName = hostName;
this.port = port;
}
/**
@@ -60,84 +75,17 @@ public class DefaultLettucePool implements LettucePool {
* The pool {@link Config}
*/
public DefaultLettucePool(String hostName, int port, Config poolConfig) {
this(hostName, port, 0, DEFAULT_TIMEOUT, poolConfig);
this.hostName = hostName;
this.port = port;
this.poolConfig = poolConfig;
}
/**
*
* Uses the {@link Config} defaults for configuring the connection pool
*
* @param client
* The {@link RedisClient} for connecting to Redis
*
*/
public DefaultLettucePool(RedisClient client) {
this.client = client;
this.internalPool = new GenericObjectPool(new LettuceFactory(client, 0), new Config());
}
/**
*
* @param client
* The {@link RedisClient} for connecting to Redis
*
* @param poolConfig
* The pool {@link Config}
* @param dbIndex
* The index of the database all connections should use. The
* database will be selected when connections are activated.
*/
public DefaultLettucePool(RedisClient client, Config poolConfig, int dbIndex) {
this.client = client;
this.internalPool = new GenericObjectPool(new LettuceFactory(client, dbIndex), poolConfig);
}
/**
* Uses the {@link Config} defaults for configuring the connection pool
*
* @param hostName
* The Redis host
* @param port
* The Redis port
* @param dbIndex
* The index of the database all connections should use. The
* database will be selected when connections are activated.
* @param password
* The password used for authenticating with the Redis server or
* null if no password required
* @param timeout
* The socket timeout or 0 to use the default socket timeout
*/
public DefaultLettucePool(String hostName, int port, int dbIndex, int timeout) {
this(hostName, port, dbIndex, timeout, new Config());
}
/**
*
* @param hostName
* The Redis host
* @param port
* The Redis port
* @param dbIndex
* The index of the database all connections should use. The
* database will be selected when connections are activated.
* @param password
* The password used for authenticating with the Redis server or
* null if no password required
* @param timeout
* The socket timeout or 0 to use the default socket timeout
* @param poolConfig
* The pool {@link COnfig}
*/
public DefaultLettucePool(String hostName, int port, int dbIndex, int timeout, Config poolConfig) {
this.client = new RedisClient(hostName, port);
public void afterPropertiesSet() {
this.client = password != null ? new AuthenticatingRedisClient(hostName, port, password) :
new RedisClient(hostName, port);
client.setDefaultTimeout(timeout, TimeUnit.MILLISECONDS);
this.internalPool = new GenericObjectPool(new LettuceFactory(client, dbIndex), poolConfig);
}
public RedisClient getClient() {
return client;
}
@SuppressWarnings("unchecked")
public RedisAsyncConnection<byte[], byte[]> getResource() {
@@ -172,6 +120,122 @@ public class DefaultLettucePool implements LettucePool {
}
}
public RedisClient getClient() {
return client;
}
/**
*
* @return The pool configuration
*/
public Config getPoolConfig() {
return poolConfig;
}
/**
*
* @param poolConfig The pool configuration to use
*/
public void setPoolConfig(Config poolConfig) {
this.poolConfig = poolConfig;
}
/**
* Returns the index of the database.
*
* @return Returns the database index
*/
public int getDatabase() {
return dbIndex;
}
/**
* Sets the index of the database used by this connection pool. Default
* is 0.
*
* @param index
* database index
*/
public void setDatabase(int index) {
Assert.isTrue(index >= 0, "invalid DB index (a positive index required)");
this.dbIndex = index;
}
/**
* Returns the password used for authenticating with the Redis server.
*
* @return password for authentication
*/
public String getPassword() {
return password;
}
/**
* Sets the password used for authenticating with the Redis server.
*
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Returns the current host.
*
* @return the host
*/
public String getHostName() {
return hostName;
}
/**
* Sets the host.
*
* @param host
* the host to set
*/
public void setHostName(String host) {
this.hostName = host;
}
/**
* Returns the current port.
*
* @return the port
*/
public int getPort() {
return port;
}
/**
* Sets the port.
*
* @param port
* the port to set
*/
public void setPort(int port) {
this.port = port;
}
/**
* Returns the connection timeout (in milliseconds).
*
* @return connection timeout
*/
public long getTimeout() {
return timeout;
}
/**
* Sets the connection timeout (in milliseconds).
*
* @param timeout
* connection timeout
*/
public void setTimeout(long timeout) {
this.timeout = timeout;
}
private static class LettuceFactory extends BasePoolableObjectFactory {
private final RedisClient client;

View File

@@ -70,6 +70,7 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea
private int dbIndex = 0;
/** Synchronization monitor for the shared Connection */
private final Object connectionMonitor = new Object();
private String password;
/**
* Constructs a new <code>LettuceConnectionFactory</code> instance with
@@ -278,6 +279,24 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea
this.dbIndex = index;
}
/**
* Returns the password used for authenticating with the Redis server.
*
* @return password for authentication
*/
public String getPassword() {
return password;
}
/**
* Sets the password used for authenticating with the Redis server.
*
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
protected RedisAsyncConnection<byte[], byte[]> getSharedConnection() {
if (shareNativeConnection) {
synchronized (this.connectionMonitor) {
@@ -314,7 +333,8 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea
if(pool != null) {
return pool.getClient();
}
RedisClient client = new RedisClient(hostName, port);
RedisClient client = password != null ? new AuthenticatingRedisClient(hostName, port, password) :
new RedisClient(hostName, port);
client.setDefaultTimeout(timeout, TimeUnit.MILLISECONDS);
return client;
}