Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for ACL LOG command #2302

Merged
merged 4 commits into from
Dec 7, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions src/main/java/redis/clients/jedis/AccessControlLogEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package redis.clients.jedis;

import java.io.Serializable;
import java.util.*;

/**
* This class holds information about an Access Control Log entry (returned by ACL LOG command)
* They can be access via getters.
* For future purpose there is also {@link #getlogEntry} method
* that returns a generic {@code Map} - in case where more info is returned from a server
*
*/
public class AccessControlLogEntry implements Serializable {

private static final long serialVersionUID = 1L;

public static final String COUNT = "count";
public static final String REASON = "reason";
public static final String CONTEXT = "context";
public static final String OBJECT = "object";
public static final String USERNAME = "username";
public static final String AGE_SECONDS = "age-seconds";
public static final String CLIENT_INFO = "client-info";

private long count;
private final String reason;
private final String context;
private final String object;
private final String username;
private final String ageSeconds;
private final Map<String,String> clientInfo;
private final Map<String,Object> logEntry;


public AccessControlLogEntry(Map<String, Object> map) {
count = (long)map.get(COUNT);
reason = (String)map.get(REASON);
context = (String)map.get(CONTEXT);
object = (String)map.get(OBJECT);
username = (String)map.get(USERNAME);
ageSeconds = (String)map.get(AGE_SECONDS);
clientInfo = getMapFromRawClientInfo((String)map.get(CLIENT_INFO));
logEntry = map;
}

public long getCount() {
return count;
}

public String getReason() {
return reason;
}

public String getContext() {
return context;
}

public String getObject() {
return object;
}

public String getUsername() {
return username;
}

public String getAgeSeconds() {
return ageSeconds;
}

public Map<String, String> getClientInfo() {
return clientInfo;
}

/**
* @return Generic map containing all key-value pairs returned by the server
*/
public Map<String,Object> getlogEntry() {
return logEntry;
}

/**
* Convert the client-info string into a Map of String.
* When the value is empty, the value in the map is set to an empty string
* The key order is maintained to reflect the string return by Redis
* @param clientInfo
* @return A Map with all client info
*/
private Map<String,String> getMapFromRawClientInfo( String clientInfo) {
String[] entries = clientInfo.split(" ");
Map<String,String> clientInfoMap = new LinkedHashMap<>(entries.length);
for (String entry : entries) {
String[] kvArray = entry.split("=");
clientInfoMap.put(kvArray[0], (kvArray.length ==2)?kvArray[1]:"" );
}
return clientInfoMap;
}

@Override
public String toString() {
return "AccessControlLogEntry{" +
"count=" + count +
", reason='" + reason + '\'' +
", context='" + context + '\'' +
", object='" + object + '\'' +
", username='" + username + '\'' +
", ageSeconds='" + ageSeconds + '\'' +
", clientInfo=" + clientInfo +
'}';
}
}
12 changes: 12 additions & 0 deletions src/main/java/redis/clients/jedis/BinaryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,18 @@ public void aclCat(final byte[] category) {
sendCommand(ACL, Keyword.CAT.raw, category);
}

public void aclLog() {
sendCommand(ACL, Keyword.LOG.raw);
}

public void aclLog(int limit) {
sendCommand(ACL, Keyword.LOG.raw, toByteArray(limit));
}

public void aclLog(final byte[] option) {
sendCommand(ACL, Keyword.LOG.raw, option);
}

public void aclSetUser(final byte[] name) {
sendCommand(ACL, Keyword.SETUSER.raw, name);
}
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/redis/clients/jedis/BinaryJedis.java
Original file line number Diff line number Diff line change
Expand Up @@ -3747,6 +3747,26 @@ public List<byte[]> aclCat(byte[] category) {
return client.getBinaryMultiBulkReply();
}

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

@Override
public List<byte[]> aclLogBinary(int limit) {
checkIsInMultiOrPipeline();
client.aclLog(limit);
return client.getBinaryMultiBulkReply();
}
@Override
public byte[] aclLog(byte[] options) {
checkIsInMultiOrPipeline();
client.aclLog(options);
return client.getBinaryBulkReply();
}

@Override
public String clientKill(final byte[] ipPort) {
checkIsInMultiOrPipeline();
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 @@ -522,6 +522,52 @@ public String toString() {

};

/**
* Create an Access Control Log Entry
* Result of ACL LOG command
*/
public static final Builder<List<AccessControlLogEntry>> ACCESS_CONTROL_LOG_ENTRY_LIST = new Builder<List<AccessControlLogEntry>>() {

private final Map<String,Builder> mappingFunctions = createDecoderMap();

private Map<String, Builder> createDecoderMap() {

Map<String,Builder> tempMappingFunctions = new HashMap<>();
tempMappingFunctions.put(AccessControlLogEntry.COUNT ,LONG);
tempMappingFunctions.put(AccessControlLogEntry.REASON ,STRING);
tempMappingFunctions.put(AccessControlLogEntry.CONTEXT ,STRING);
tempMappingFunctions.put(AccessControlLogEntry.OBJECT ,STRING);
tempMappingFunctions.put(AccessControlLogEntry.USERNAME,STRING);
tempMappingFunctions.put(AccessControlLogEntry.AGE_SECONDS,STRING);
tempMappingFunctions.put(AccessControlLogEntry.CLIENT_INFO,STRING);

return tempMappingFunctions;
}

@Override
public List<AccessControlLogEntry> build(Object data) {

if (null == data) {
return null;
}

List<AccessControlLogEntry> list = new ArrayList<>();
List<List<Object>> logEntries = (List<List<Object>>)data;
for (List<Object> logEntryData : logEntries) {
Iterator<Object> logEntryDataIterator = logEntryData.iterator();
AccessControlLogEntry accessControlLogEntry = new AccessControlLogEntry(
createMapFromDecodingFunctions(logEntryDataIterator,mappingFunctions));
list.add(accessControlLogEntry);
}
return list;
}

@Override
public String toString() {
return "List<AccessControlLogEntry>";
}
};

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

public void aclLog(final String options) {
aclLog(SafeEncoder.encode(options));
}

public void aclDelUser(final String name) {
aclDelUser(SafeEncoder.encode(name));
}
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/redis/clients/jedis/Jedis.java
Original file line number Diff line number Diff line change
Expand Up @@ -3772,6 +3772,24 @@ public List<String> aclCat(String category) {
return BuilderFactory.STRING_LIST.build(client.getObjectMultiBulkReply());
}

@Override
public List<AccessControlLogEntry> aclLog() {
client.aclLog();
return BuilderFactory.ACCESS_CONTROL_LOG_ENTRY_LIST.build(client.getObjectMultiBulkReply());
}

@Override
public List<AccessControlLogEntry> aclLog(int limit) {
client.aclLog(limit);
return BuilderFactory.ACCESS_CONTROL_LOG_ENTRY_LIST.build(client.getObjectMultiBulkReply());
}

@Override
public String aclLog(String options) {
client.aclLog(options);
return client.getStatusCodeReply();
}

@Override
public String aclGenPass() {
client.aclGenPass();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/redis/clients/jedis/Protocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ public static enum Keyword {
GETNAME, SETNAME, LIST, MATCH, COUNT, PING, PONG, UNLOAD, REPLACE, KEYS, PAUSE, DOCTOR,
BLOCK, NOACK, STREAMS, KEY, CREATE, MKSTREAM, SETID, DESTROY, DELCONSUMER, MAXLEN, GROUP,
ID, IDLE, TIME, RETRYCOUNT, FORCE, USAGE, SAMPLES, STREAM, GROUPS, CONSUMERS, HELP, FREQ,
SETUSER, GETUSER, DELUSER, WHOAMI, CAT, GENPASS, USERS;
SETUSER, GETUSER, DELUSER, WHOAMI, CAT, GENPASS, USERS, LOG;

/**
* @deprecated This will be private in future. Use {@link #getRaw()}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;

import redis.clients.jedis.AccessControlLogEntry;
import redis.clients.jedis.AccessControlUser;
import redis.clients.jedis.params.MigrateParams;
import redis.clients.jedis.params.ClientKillParams;
Expand Down Expand Up @@ -74,5 +75,11 @@ public interface AdvancedBinaryJedisCommands {

List<byte[]> aclCat(byte[] category);

List<byte[]> aclLogBinary();

List<byte[]> aclLogBinary(int limit);

byte[] aclLog(byte[] options);

// TODO: Implements ACL LOAD/SAVE commands
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package redis.clients.jedis.commands;

import java.util.List;
import java.util.Map;

import redis.clients.jedis.AccessControlLogEntry;
import redis.clients.jedis.AccessControlUser;
import redis.clients.jedis.params.MigrateParams;
import redis.clients.jedis.params.ClientKillParams;
Expand Down Expand Up @@ -74,5 +76,11 @@ public interface AdvancedJedisCommands {

List<String> aclCat(String category);

List<AccessControlLogEntry> aclLog();

List<AccessControlLogEntry> aclLog(int limit);

String aclLog(String options);

// TODO: Implements ACL LOAD/SAVE commands
}
Loading