Skip to content

Commit 6b419d5

Browse files
authored
add support for ACL LOG command (#2302)
* add support for ACL LOG command - issue #2170 * fix code after first review of PR - issue #2170 * more binary method, and better loops after review of the for issue #2170 Authored-by: Tugdual Grall <[email protected]> Co-authored-by: M Sazzadul Hoque <[email protected]>
1 parent 5525669 commit 6b419d5

File tree

10 files changed

+332
-1
lines changed

10 files changed

+332
-1
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package redis.clients.jedis;
2+
3+
import java.io.Serializable;
4+
import java.util.*;
5+
6+
/**
7+
* This class holds information about an Access Control Log entry (returned by ACL LOG command)
8+
* They can be access via getters.
9+
* For future purpose there is also {@link #getlogEntry} method
10+
* that returns a generic {@code Map} - in case where more info is returned from a server
11+
*
12+
*/
13+
public class AccessControlLogEntry implements Serializable {
14+
15+
private static final long serialVersionUID = 1L;
16+
17+
public static final String COUNT = "count";
18+
public static final String REASON = "reason";
19+
public static final String CONTEXT = "context";
20+
public static final String OBJECT = "object";
21+
public static final String USERNAME = "username";
22+
public static final String AGE_SECONDS = "age-seconds";
23+
public static final String CLIENT_INFO = "client-info";
24+
25+
private long count;
26+
private final String reason;
27+
private final String context;
28+
private final String object;
29+
private final String username;
30+
private final String ageSeconds;
31+
private final Map<String,String> clientInfo;
32+
private final Map<String,Object> logEntry;
33+
34+
35+
public AccessControlLogEntry(Map<String, Object> map) {
36+
count = (long)map.get(COUNT);
37+
reason = (String)map.get(REASON);
38+
context = (String)map.get(CONTEXT);
39+
object = (String)map.get(OBJECT);
40+
username = (String)map.get(USERNAME);
41+
ageSeconds = (String)map.get(AGE_SECONDS);
42+
clientInfo = getMapFromRawClientInfo((String)map.get(CLIENT_INFO));
43+
logEntry = map;
44+
}
45+
46+
public long getCount() {
47+
return count;
48+
}
49+
50+
public String getReason() {
51+
return reason;
52+
}
53+
54+
public String getContext() {
55+
return context;
56+
}
57+
58+
public String getObject() {
59+
return object;
60+
}
61+
62+
public String getUsername() {
63+
return username;
64+
}
65+
66+
public String getAgeSeconds() {
67+
return ageSeconds;
68+
}
69+
70+
public Map<String, String> getClientInfo() {
71+
return clientInfo;
72+
}
73+
74+
/**
75+
* @return Generic map containing all key-value pairs returned by the server
76+
*/
77+
public Map<String,Object> getlogEntry() {
78+
return logEntry;
79+
}
80+
81+
/**
82+
* Convert the client-info string into a Map of String.
83+
* When the value is empty, the value in the map is set to an empty string
84+
* The key order is maintained to reflect the string return by Redis
85+
* @param clientInfo
86+
* @return A Map with all client info
87+
*/
88+
private Map<String,String> getMapFromRawClientInfo( String clientInfo) {
89+
String[] entries = clientInfo.split(" ");
90+
Map<String,String> clientInfoMap = new LinkedHashMap<>(entries.length);
91+
for (String entry : entries) {
92+
String[] kvArray = entry.split("=");
93+
clientInfoMap.put(kvArray[0], (kvArray.length ==2)?kvArray[1]:"" );
94+
}
95+
return clientInfoMap;
96+
}
97+
98+
@Override
99+
public String toString() {
100+
return "AccessControlLogEntry{" +
101+
"count=" + count +
102+
", reason='" + reason + '\'' +
103+
", context='" + context + '\'' +
104+
", object='" + object + '\'' +
105+
", username='" + username + '\'' +
106+
", ageSeconds='" + ageSeconds + '\'' +
107+
", clientInfo=" + clientInfo +
108+
'}';
109+
}
110+
}

src/main/java/redis/clients/jedis/BinaryClient.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,6 +1344,18 @@ public void aclCat(final byte[] category) {
13441344
sendCommand(ACL, Keyword.CAT.raw, category);
13451345
}
13461346

1347+
public void aclLog() {
1348+
sendCommand(ACL, Keyword.LOG.raw);
1349+
}
1350+
1351+
public void aclLog(int limit) {
1352+
sendCommand(ACL, Keyword.LOG.raw, toByteArray(limit));
1353+
}
1354+
1355+
public void aclLog(final byte[] option) {
1356+
sendCommand(ACL, Keyword.LOG.raw, option);
1357+
}
1358+
13471359
public void aclSetUser(final byte[] name) {
13481360
sendCommand(ACL, Keyword.SETUSER.raw, name);
13491361
}

src/main/java/redis/clients/jedis/BinaryJedis.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3779,6 +3779,26 @@ public List<byte[]> aclCat(byte[] category) {
37793779
return client.getBinaryMultiBulkReply();
37803780
}
37813781

3782+
@Override
3783+
public List<byte[]> aclLogBinary() {
3784+
checkIsInMultiOrPipeline();
3785+
client.aclLog();
3786+
return client.getBinaryMultiBulkReply();
3787+
}
3788+
3789+
@Override
3790+
public List<byte[]> aclLogBinary(int limit) {
3791+
checkIsInMultiOrPipeline();
3792+
client.aclLog(limit);
3793+
return client.getBinaryMultiBulkReply();
3794+
}
3795+
@Override
3796+
public byte[] aclLog(byte[] options) {
3797+
checkIsInMultiOrPipeline();
3798+
client.aclLog(options);
3799+
return client.getBinaryBulkReply();
3800+
}
3801+
37823802
@Override
37833803
public String clientKill(final byte[] ipPort) {
37843804
checkIsInMultiOrPipeline();

src/main/java/redis/clients/jedis/BuilderFactory.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,52 @@ public String toString() {
522522

523523
};
524524

525+
/**
526+
* Create an Access Control Log Entry
527+
* Result of ACL LOG command
528+
*/
529+
public static final Builder<List<AccessControlLogEntry>> ACCESS_CONTROL_LOG_ENTRY_LIST = new Builder<List<AccessControlLogEntry>>() {
530+
531+
private final Map<String,Builder> mappingFunctions = createDecoderMap();
532+
533+
private Map<String, Builder> createDecoderMap() {
534+
535+
Map<String,Builder> tempMappingFunctions = new HashMap<>();
536+
tempMappingFunctions.put(AccessControlLogEntry.COUNT ,LONG);
537+
tempMappingFunctions.put(AccessControlLogEntry.REASON ,STRING);
538+
tempMappingFunctions.put(AccessControlLogEntry.CONTEXT ,STRING);
539+
tempMappingFunctions.put(AccessControlLogEntry.OBJECT ,STRING);
540+
tempMappingFunctions.put(AccessControlLogEntry.USERNAME,STRING);
541+
tempMappingFunctions.put(AccessControlLogEntry.AGE_SECONDS,STRING);
542+
tempMappingFunctions.put(AccessControlLogEntry.CLIENT_INFO,STRING);
543+
544+
return tempMappingFunctions;
545+
}
546+
547+
@Override
548+
public List<AccessControlLogEntry> build(Object data) {
549+
550+
if (null == data) {
551+
return null;
552+
}
553+
554+
List<AccessControlLogEntry> list = new ArrayList<>();
555+
List<List<Object>> logEntries = (List<List<Object>>)data;
556+
for (List<Object> logEntryData : logEntries) {
557+
Iterator<Object> logEntryDataIterator = logEntryData.iterator();
558+
AccessControlLogEntry accessControlLogEntry = new AccessControlLogEntry(
559+
createMapFromDecodingFunctions(logEntryDataIterator,mappingFunctions));
560+
list.add(accessControlLogEntry);
561+
}
562+
return list;
563+
}
564+
565+
@Override
566+
public String toString() {
567+
return "List<AccessControlLogEntry>";
568+
}
569+
};
570+
525571
public static final Builder<List<Long>> LONG_LIST = new Builder<List<Long>>() {
526572
@Override
527573
@SuppressWarnings("unchecked")

src/main/java/redis/clients/jedis/Client.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,10 @@ public void aclCat(final String category) {
12201220
aclCat(SafeEncoder.encode(category));
12211221
}
12221222

1223+
public void aclLog(final String options) {
1224+
aclLog(SafeEncoder.encode(options));
1225+
}
1226+
12231227
public void aclDelUser(final String name) {
12241228
aclDelUser(SafeEncoder.encode(name));
12251229
}

src/main/java/redis/clients/jedis/Jedis.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3820,6 +3820,24 @@ public List<String> aclCat(String category) {
38203820
return BuilderFactory.STRING_LIST.build(client.getObjectMultiBulkReply());
38213821
}
38223822

3823+
@Override
3824+
public List<AccessControlLogEntry> aclLog() {
3825+
client.aclLog();
3826+
return BuilderFactory.ACCESS_CONTROL_LOG_ENTRY_LIST.build(client.getObjectMultiBulkReply());
3827+
}
3828+
3829+
@Override
3830+
public List<AccessControlLogEntry> aclLog(int limit) {
3831+
client.aclLog(limit);
3832+
return BuilderFactory.ACCESS_CONTROL_LOG_ENTRY_LIST.build(client.getObjectMultiBulkReply());
3833+
}
3834+
3835+
@Override
3836+
public String aclLog(String options) {
3837+
client.aclLog(options);
3838+
return client.getStatusCodeReply();
3839+
}
3840+
38233841
@Override
38243842
public String aclGenPass() {
38253843
client.aclGenPass();

src/main/java/redis/clients/jedis/Protocol.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ public static enum Keyword {
281281
GETNAME, SETNAME, LIST, MATCH, COUNT, PING, PONG, UNLOAD, REPLACE, KEYS, PAUSE, DOCTOR,
282282
BLOCK, NOACK, STREAMS, KEY, CREATE, MKSTREAM, SETID, DESTROY, DELCONSUMER, MAXLEN, GROUP,
283283
ID, IDLE, TIME, RETRYCOUNT, FORCE, USAGE, SAMPLES, STREAM, GROUPS, CONSUMERS, HELP, FREQ,
284-
SETUSER, GETUSER, DELUSER, WHOAMI, CAT, GENPASS, USERS;
284+
SETUSER, GETUSER, DELUSER, WHOAMI, CAT, GENPASS, USERS, LOG;
285285

286286
/**
287287
* @deprecated This will be private in future. Use {@link #getRaw()}.

src/main/java/redis/clients/jedis/commands/AdvancedBinaryJedisCommands.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.List;
44

5+
import redis.clients.jedis.AccessControlLogEntry;
56
import redis.clients.jedis.AccessControlUser;
67
import redis.clients.jedis.params.MigrateParams;
78
import redis.clients.jedis.params.ClientKillParams;
@@ -74,5 +75,11 @@ public interface AdvancedBinaryJedisCommands {
7475

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

78+
List<byte[]> aclLogBinary();
79+
80+
List<byte[]> aclLogBinary(int limit);
81+
82+
byte[] aclLog(byte[] options);
83+
7784
// TODO: Implements ACL LOAD/SAVE commands
7885
}

src/main/java/redis/clients/jedis/commands/AdvancedJedisCommands.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package redis.clients.jedis.commands;
22

33
import java.util.List;
4+
import java.util.Map;
45

6+
import redis.clients.jedis.AccessControlLogEntry;
57
import redis.clients.jedis.AccessControlUser;
68
import redis.clients.jedis.params.MigrateParams;
79
import redis.clients.jedis.params.ClientKillParams;
@@ -74,5 +76,11 @@ public interface AdvancedJedisCommands {
7476

7577
List<String> aclCat(String category);
7678

79+
List<AccessControlLogEntry> aclLog();
80+
81+
List<AccessControlLogEntry> aclLog(int limit);
82+
83+
String aclLog(String options);
84+
7785
// TODO: Implements ACL LOAD/SAVE commands
7886
}

0 commit comments

Comments
 (0)