Skip to content

Commit

Permalink
Adding support for Redis 6 ACL - Issue #2035 (#2077)
Browse files Browse the repository at this point in the history
Co-authored-by: M Sazzadul Hoque <[email protected]>
Co-authored-by: Guy Korland <[email protected]>
  • Loading branch information
3 people authored Mar 14, 2020
1 parent 3289d69 commit 6457908
Show file tree
Hide file tree
Showing 31 changed files with 3,020 additions and 26 deletions.
53 changes: 53 additions & 0 deletions src/main/java/redis/clients/jedis/AccessControlUser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package redis.clients.jedis;

import java.util.ArrayList;
import java.util.List;

public class AccessControlUser {

private final List<String> flags = new ArrayList<String>();
private final List<String> keys = new ArrayList<String>();
private final List<String> passwords = new ArrayList<String>();
private String commands;

public AccessControlUser() {
}

public void addFlag(String flag) {
flags.add(flag);
}

public List<String> getFlags() {
return flags;
}

public void addKey(String key) {
keys.add(key);
}

public List<String> getKeys() {
return keys;
}

public void addPassword(String password) {
passwords.add(password);
}

public List<String> getPassword() {
return passwords;
}

public String getCommands() {
return commands;
}

public void setCommands(String commands) {
this.commands = commands;
}

@Override
public String toString() {
return "AccessControlUser{" + "flags=" + flags + ", keys=" + keys + ", passwords=" + passwords
+ ", commands='" + commands + '\'' + '}';
}
}
44 changes: 43 additions & 1 deletion src/main/java/redis/clients/jedis/BinaryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class BinaryClient extends Connection {

private boolean isInMulti;

private String user;
private String password;

private int db;
Expand Down Expand Up @@ -86,6 +87,8 @@ private byte[][] joinParameters(byte[] first, byte[] second, byte[][] rest) {
return result;
}

public void setUser(final String user) { this.user = user; }

public void setPassword(final String password) {
this.password = password;
}
Expand All @@ -98,7 +101,10 @@ public void setDb(int db) {
public void connect() {
if (!isConnected()) {
super.connect();
if (password != null) {
if (user != null) {
auth(user, password);
getStatusCodeReply();
} else if (password != null) {
auth(password);
getStatusCodeReply();
}
Expand Down Expand Up @@ -601,6 +607,12 @@ public void auth(final String password) {
sendCommand(AUTH, password);
}

public void auth(final String user, final String password) {
setUser(user);
setPassword(password);
sendCommand(AUTH, user, password);
}

public void subscribe(final byte[]... channels) {
sendCommand(SUBSCRIBE, channels);
}
Expand Down Expand Up @@ -1260,6 +1272,36 @@ private ArrayList<byte[]> convertScoreMembersToByteArrays(final Map<byte[], Doub
return args;
}

public void aclWhoAmI() { sendCommand(ACL, Keyword.WHOAMI.raw); }

public void aclGenPass() { sendCommand(ACL, Keyword.GENPASS.raw); }

public void aclList() { sendCommand(ACL, Keyword.LIST.raw); }

public void aclUsers() { sendCommand(ACL, Keyword.USERS.raw); }

public void aclCat() { sendCommand(ACL, Keyword.CAT.raw); }

public void aclCat(final byte[] category) {
sendCommand(ACL, Keyword.CAT.raw, category);
}

public void aclSetUser(final byte[] name) {
sendCommand(ACL, Keyword.SETUSER.raw, name);
}

public void aclGetUser(final byte[] name) {
sendCommand(ACL, Keyword.GETUSER.raw, name);
}

public void aclSetUser(final byte[] name, byte[][] parameters) {
sendCommand(ACL, joinParameters(Keyword.SETUSER.raw,name, parameters));
}

public void aclDelUser(final byte[] name) {
sendCommand(ACL, Keyword.DELUSER.raw, name);
}

private List<byte[]> convertGeoCoordinateMapToByteArrays(
final Map<byte[], GeoCoordinate> memberCoordinateMap) {
List<byte[]> args = new ArrayList<>(memberCoordinateMap.size() * 3);
Expand Down
93 changes: 92 additions & 1 deletion src/main/java/redis/clients/jedis/BinaryJedis.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public BinaryJedis(final JedisShardInfo shardInfo) {
shardInfo.getHostnameVerifier());
client.setConnectionTimeout(shardInfo.getConnectionTimeout());
client.setSoTimeout(shardInfo.getSoTimeout());
client.setUser(shardInfo.getUser());
client.setPassword(shardInfo.getPassword());
client.setDb(shardInfo.getDb());
}
Expand Down Expand Up @@ -170,7 +171,12 @@ private void initializeClientFromURI(URI uri, final SSLSocketFactory sslSocketFa

String password = JedisURIHelper.getPassword(uri);
if (password != null) {
client.auth(password);
String user = JedisURIHelper.getUser(uri);
if (user == null) {
client.auth(password);
} else {
client.auth(user, password);
}
client.getStatusCodeReply();
}

Expand Down Expand Up @@ -2259,6 +2265,21 @@ public String auth(final String password) {
return client.getStatusCodeReply();
}

/**
* Request for authentication with a Redis Server that is using ACL where user are authenticated with
* username and password.
* See https://redis.io/topics/acl
* @param user
* @param password
* @return
*/
@Override
public String auth(final String user, final String password) {
checkIsInMultiOrPipeline();
client.auth(user, password);
return client.getStatusCodeReply();
}

public Pipeline pipelined() {
pipeline = new Pipeline();
pipeline.setClient(client);
Expand Down Expand Up @@ -3567,6 +3588,76 @@ public byte[] memoryDoctorBinary() {
return client.getBinaryBulkReply();
}

@Override
public byte[] aclWhoAmIBinary() {
checkIsInMultiOrPipeline();
client.aclWhoAmI();
return client.getBinaryBulkReply();
}

@Override
public byte[] aclGenPassBinary() {
checkIsInMultiOrPipeline();
client.aclGenPass();
return client.getBinaryBulkReply();
}

@Override
public List<byte[]> aclListBinary() {
checkIsInMultiOrPipeline();
client.aclList();
return client.getBinaryMultiBulkReply();
}

@Override
public List<byte[]> aclUsersBinary() {
checkIsInMultiOrPipeline();
client.aclUsers();
return client.getBinaryMultiBulkReply();
}

@Override
public AccessControlUser aclGetUser(byte[] name) {
checkIsInMultiOrPipeline();
client.aclGetUser(name);
return BuilderFactory.ACCESS_CONTROL_USER.build(client.getObjectMultiBulkReply());
}

@Override
public String aclSetUser(byte[] name) {
checkIsInMultiOrPipeline();
client.aclSetUser(name);
return client.getStatusCodeReply();
}

@Override
public String aclSetUser(byte[] name, byte[]... keys) {
checkIsInMultiOrPipeline();
client.aclSetUser(name, keys);
return client.getStatusCodeReply();
}

@Override
public Long aclDelUser(byte[] name) {
checkIsInMultiOrPipeline();
client.aclDelUser(name);
return client.getIntegerReply();
}

@Override
public List<byte[]> aclCatBinary() {
checkIsInMultiOrPipeline();
client.aclCat();
return client.getBinaryMultiBulkReply();
}

@Override
public List<byte[]> aclCat(byte[] category) {
checkIsInMultiOrPipeline();
client.aclCat(category);
return client.getBinaryMultiBulkReply();
}

@Override
public String clientKill(final byte[] ipPort) {
checkIsInMultiOrPipeline();
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/redis/clients/jedis/BinaryJedisCluster.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,38 @@ public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeo
this.maxAttempts = maxAttempts;
}

public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout, int maxAttempts, String user, String password, String clientName, GenericObjectPoolConfig poolConfig) {
this.connectionHandler = new JedisSlotBasedConnectionHandler(jedisClusterNode, poolConfig,
connectionTimeout, soTimeout, user, password, clientName);
this.maxAttempts = maxAttempts;
}

public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout, int maxAttempts, String password, String clientName, GenericObjectPoolConfig poolConfig,
boolean ssl) {
this(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig, ssl, null, null, null, null);
}

public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout, int maxAttempts,
String user, String password, String clientName, GenericObjectPoolConfig poolConfig, boolean ssl) {
this(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, user, password, clientName, poolConfig, ssl, null, null, null, null);
}

public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout, int maxAttempts, String password, String clientName, GenericObjectPoolConfig poolConfig,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, HostnameVerifier hostnameVerifier, JedisClusterHostAndPortMap hostAndPortMap) {
this.connectionHandler = new JedisSlotBasedConnectionHandler(jedisClusterNode, poolConfig,
connectionTimeout, soTimeout, password, clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMap);
this.maxAttempts = maxAttempts;
}

public BinaryJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout, int maxAttempts,
String user, String password, String clientName, GenericObjectPoolConfig poolConfig,
boolean ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters,
HostnameVerifier hostnameVerifier, JedisClusterHostAndPortMap hostAndPortMap) {
this.connectionHandler = new JedisSlotBasedConnectionHandler(jedisClusterNode, poolConfig,
connectionTimeout, soTimeout, user, password, clientName, ssl, sslSocketFactory, sslParameters, hostnameVerifier, hostAndPortMap);
this.maxAttempts = maxAttempts;
}

@Override
public void close() {
if (connectionHandler != null) {
Expand Down
46 changes: 46 additions & 0 deletions src/main/java/redis/clients/jedis/BuilderFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,52 @@ public String toString() {
}
};

/**
* Create a AccessControlUser object from the ACL GETUSER < > result
*/
public static final Builder<AccessControlUser> ACCESS_CONTROL_USER = new Builder<AccessControlUser>() {
@Override
public AccessControlUser build(Object data) {
if (data == null) {
return null;
}

List<List<Object>> objectList = (List<List<Object>>) data;
if (objectList.isEmpty()) { return null; }

AccessControlUser accessControlUser = new AccessControlUser();

// flags
List<Object> flags = objectList.get(1);
for (Object f : flags) {
accessControlUser.addFlag(SafeEncoder.encode((byte[]) f));
};

// passwords
List<Object> passwords = objectList.get(3);
for (Object p : passwords) {
accessControlUser.addPassword(SafeEncoder.encode((byte[]) p));
};

// commands
accessControlUser.setCommands(SafeEncoder.encode((byte[]) (Object) objectList.get(5)));

// keys
List<Object> keys = objectList.get(7);
for (Object k : keys) {
accessControlUser.addKey(SafeEncoder.encode((byte[]) k));
};

return accessControlUser;
}

@Override
public String toString() {
return "AccessControlUser";
}

};

public static final Builder<List<Long>> LONG_LIST = new Builder<List<Long>>() {
@Override
@SuppressWarnings("unchecked")
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/redis/clients/jedis/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -1151,6 +1151,26 @@ public void moduleUnload(final String name) {
moduleUnload(SafeEncoder.encode(name));
}

public void aclGetUser(final String name) {
aclGetUser(SafeEncoder.encode(name));
}

public void aclSetUser(final String name) {
aclSetUser(SafeEncoder.encode(name));
}

public void aclSetUser(String name, String... parameters) {
aclSetUser(SafeEncoder.encode(name), SafeEncoder.encodeMany(parameters));
}

public void aclCat(final String category) {
aclCat(SafeEncoder.encode(category));
}

public void aclDelUser(final String name) {
aclDelUser(SafeEncoder.encode(name));
}

private HashMap<byte[], Double> convertScoreMembersToBinary(final Map<String, Double> scoreMembers) {
HashMap<byte[], Double> binaryScoreMembers = new HashMap<>();
for (Entry<String, Double> entry : scoreMembers.entrySet()) {
Expand Down
Loading

0 comments on commit 6457908

Please sign in to comment.