Skip to content

Commit 76dc72c

Browse files
committed
make qos, retained and cleanSession configurable
refactor and make qos, retained and cleanSession configurable Change-Id: I6760d9222199d7fcf184aa5ff128afe8e827d251
1 parent d2f13ea commit 76dc72c

File tree

5 files changed

+102
-135
lines changed

5 files changed

+102
-135
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target/

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
A Keycloak SPI that publishes events to a MQTT broker.
44

5-
This SPI has been deployed successfully on a containerized Keycloak 15.0.2
5+
This SPI has been deployed successfully on a containerized Keycloak 19.0.2
66
and on a Keycloak 19.0 server on a kubernetes cluster. It should therefore
7-
work properly on any version of Keycloak above 15.0.2.
7+
work properly on any version of Keycloak above 19.0.2.
88

99
# Build
1010

@@ -36,6 +36,9 @@ And add below:
3636
<property name="password" value="mqtt_password"/>
3737
<property name="topic" value="my_topic"/>
3838
<property name="usePersistence" value="true">
39+
<property name="retained" value="true">
40+
<property name="cleanSession" value="true">
41+
<property name="qos" value="0">
3942
</properties>
4043
</provider>
4144
</spi>
@@ -58,6 +61,9 @@ kc.sh start
5861
--spi-events-listener-mqtt-password mqtt_password \
5962
--spi-events-listener-mqtt-topic my_topic
6063
--spi-events-listener-mqtt-use-persistence true
64+
--spi-events-listener-mqtt-retained true
65+
--spi-events-listener-mqtt-clean-session true
66+
--spi-events-listener-mqtt-qos 0
6167
```
6268

6369
# Trying it out
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.softwarefactory.keycloak.providers.events.models;
2+
3+
import java.util.Set;
4+
5+
import org.keycloak.events.EventType;
6+
import org.keycloak.events.admin.OperationType;
7+
8+
public class Configuration {
9+
public Set<EventType> excludedEvents;
10+
public Set<OperationType> excludedAdminOperations;
11+
public String serverUri;
12+
public String username;
13+
public String password;
14+
public String topic;
15+
public boolean usePersistence;
16+
public boolean retained;
17+
public boolean cleanSession;
18+
public int qos;
19+
}

src/main/java/org/softwarefactory/keycloak/providers/events/mqtt/MQTTEventListenerProvider.java

Lines changed: 53 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -17,136 +17,86 @@
1717

1818
package org.softwarefactory.keycloak.providers.events.mqtt;
1919

20-
import org.keycloak.events.Event;
21-
import org.keycloak.events.EventListenerProvider;
22-
import org.keycloak.events.EventType;
23-
import org.keycloak.events.admin.AdminEvent;
24-
import org.keycloak.events.admin.OperationType;
20+
import java.util.Map;
21+
import java.util.logging.Level;
22+
import java.util.logging.Logger;
2523

2624
import org.eclipse.paho.client.mqttv3.IMqttClient;
27-
import org.eclipse.paho.client.mqttv3.MqttMessage;
2825
import org.eclipse.paho.client.mqttv3.MqttClient;
2926
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
27+
import org.eclipse.paho.client.mqttv3.MqttMessage;
3028
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
31-
3229
import org.json.simple.JSONObject;
33-
34-
import java.util.Map;
35-
import java.util.Set;
36-
import java.lang.Exception;
30+
import org.keycloak.events.Event;
31+
import org.keycloak.events.EventListenerProvider;
32+
import org.keycloak.events.admin.AdminEvent;
33+
import org.softwarefactory.keycloak.providers.events.models.Configuration;
3734

3835
/**
3936
* @author <a href="mailto:[email protected]">Matthieu Huin</a>
4037
*/
4138
public class MQTTEventListenerProvider implements EventListenerProvider {
39+
private static final Logger logger = Logger.getLogger(MQTTEventListenerProvider.class.getName());
40+
41+
private Configuration configuration;
42+
public static final String PUBLISHER_ID = "keycloak";
4243

43-
private Set<EventType> excludedEvents;
44-
private Set<OperationType> excludedAdminOperations;
45-
private String serverUri;
46-
private String username;
47-
private String password;
48-
public static final String publisherId = "keycloak";
49-
public String TOPIC;
50-
public boolean usePersistence;
51-
52-
public MQTTEventListenerProvider(Set<EventType> excludedEvents, Set<OperationType> excludedAdminOperations, String serverUri, String username, String password, String topic, boolean usePersistence) {
53-
this.excludedEvents = excludedEvents;
54-
this.excludedAdminOperations = excludedAdminOperations;
55-
this.serverUri = serverUri;
56-
this.username = username;
57-
this.password = password;
58-
this.TOPIC = topic;
59-
this.usePersistence = usePersistence;
44+
public MQTTEventListenerProvider(Configuration configuration) {
45+
this.configuration = configuration;
6046
}
6147

6248
@Override
6349
public void onEvent(Event event) {
6450
// Ignore excluded events
65-
if (excludedEvents != null && excludedEvents.contains(event.getType())) {
66-
return;
67-
} else {
68-
String stringEvent = toString(event);
69-
try {
70-
MemoryPersistence persistence = null;
71-
if (this.usePersistence == true) {
72-
persistence = new MemoryPersistence();
73-
}
74-
MqttClient client = new MqttClient(this.serverUri ,publisherId, persistence);
75-
MqttConnectOptions options = new MqttConnectOptions();
76-
options.setAutomaticReconnect(true);
77-
options.setCleanSession(true);
78-
options.setConnectionTimeout(10);
79-
if (this.username != null && this.password != null) {
80-
options.setUserName(this.username);
81-
options.setPassword(this.password.toCharArray());
82-
}
83-
client.connect(options);
84-
System.out.println("EVENT: " + stringEvent);
85-
MqttMessage payload = toPayload(stringEvent);
86-
payload.setQos(0);
87-
payload.setRetained(true);
88-
client.publish(this.TOPIC, payload);
89-
client.disconnect();
90-
} catch(Exception e) {
91-
// ?
92-
System.out.println("Caught the following error: " + e.toString());
93-
e.printStackTrace();
94-
return;
95-
}
51+
if (configuration.excludedEvents == null || !configuration.excludedEvents.contains(event.getType())) {
52+
sendMqttMessage(convertEvent(event));
9653
}
9754
}
9855

9956
@Override
10057
public void onEvent(AdminEvent event, boolean includeRepresentation) {
10158
// Ignore excluded operations
102-
if (excludedAdminOperations != null && excludedAdminOperations.contains(event.getOperationType())) {
103-
return;
104-
} else {
105-
String stringEvent = toString(event);
106-
try {
107-
MemoryPersistence persistence = null;
108-
if (this.usePersistence == true) {
109-
persistence = new MemoryPersistence();
110-
}
111-
MqttClient client = new MqttClient(this.serverUri ,publisherId, persistence);
112-
MqttConnectOptions options = new MqttConnectOptions();
113-
options.setAutomaticReconnect(true);
114-
options.setCleanSession(true);
115-
options.setConnectionTimeout(10);
116-
if (this.username != null && this.password != null) {
117-
options.setUserName(this.username);
118-
options.setPassword(this.password.toCharArray());
119-
}
120-
client.connect(options);
121-
// System.out.println("EVENT: " + stringEvent);
122-
MqttMessage payload = toPayload(stringEvent);
123-
payload.setQos(0);
124-
payload.setRetained(true);
125-
client.publish(this.TOPIC, payload);
126-
client.disconnect();
127-
} catch(Exception e) {
128-
// ?
129-
System.out.println("Caught the following error: " + e.toString());
130-
e.printStackTrace();
131-
return;
132-
}
59+
if (configuration.excludedAdminOperations == null
60+
|| !configuration.excludedAdminOperations.contains(event.getOperationType())) {
61+
sendMqttMessage(convertAdminEvent(event));
13362
}
13463
}
13564

65+
private void sendMqttMessage(String event) {
66+
MemoryPersistence persistence = null;
67+
if (configuration.usePersistence) {
68+
persistence = new MemoryPersistence();
69+
}
70+
71+
try (IMqttClient client = new MqttClient(configuration.serverUri, PUBLISHER_ID, persistence)) {
72+
MqttConnectOptions options = new MqttConnectOptions();
73+
options.setAutomaticReconnect(true);
74+
options.setCleanSession(configuration.cleanSession);
75+
options.setConnectionTimeout(10);
13676

77+
if (configuration.username != null && configuration.password != null) {
78+
options.setUserName(configuration.username);
79+
options.setPassword(configuration.password.toCharArray());
80+
}
81+
82+
client.connect(options);
83+
logger.log(Level.FINE, "Event: {0}", event);
84+
MqttMessage payload = toPayload(event);
85+
payload.setQos(configuration.qos);
86+
payload.setRetained(configuration.retained);
87+
client.publish(configuration.topic, payload);
88+
client.disconnect();
89+
} catch (Exception e) {
90+
logger.log(Level.SEVERE, "Event: {0}", e.getStackTrace());
91+
}
92+
}
13793

13894
private MqttMessage toPayload(String s) {
13995
byte[] payload = s.getBytes();
14096
return new MqttMessage(payload);
14197
}
14298

143-
private String toString(Event event) {
144-
JSONObject obj = toJSON(event);
145-
return obj.toString();
146-
147-
}
148-
149-
private JSONObject toJSON(Event event) {
99+
private String convertEvent(Event event) {
150100
JSONObject ev = new JSONObject();
151101

152102
ev.put("type", event.getType().toString());
@@ -157,7 +107,7 @@ private JSONObject toJSON(Event event) {
157107
ev.put("time", event.getTime());
158108

159109
ev.put("error", event.getError());
160-
110+
161111
JSONObject evDetails = new JSONObject();
162112
if (event.getDetails() != null) {
163113
for (Map.Entry<String, String> e : event.getDetails().entrySet()) {
@@ -166,19 +116,13 @@ private JSONObject toJSON(Event event) {
166116
}
167117
ev.put("details", evDetails);
168118

169-
return ev;
170-
}
171-
172-
private String toString(AdminEvent adminEvent) {
173-
JSONObject obj = toJSON(adminEvent);
174-
return obj.toString();
175-
119+
return ev.toString();
176120
}
177121

178-
private JSONObject toJSON(AdminEvent adminEvent) {
122+
private String convertAdminEvent(AdminEvent adminEvent) {
179123
JSONObject ev = new JSONObject();
180124

181-
ev.put("type",adminEvent.getOperationType().toString());
125+
ev.put("type", adminEvent.getOperationType().toString());
182126
ev.put("realmId", adminEvent.getAuthDetails().getRealmId());
183127
ev.put("clientId", adminEvent.getAuthDetails().getClientId());
184128
ev.put("userId", adminEvent.getAuthDetails().getUserId());
@@ -189,11 +133,11 @@ private JSONObject toJSON(AdminEvent adminEvent) {
189133

190134
ev.put("error", adminEvent.getError());
191135

192-
return ev;
136+
return ev.toString();
193137
}
194138

195139
@Override
196140
public void close() {
197141
}
198142

199-
}
143+
}

src/main/java/org/softwarefactory/keycloak/providers/events/mqtt/MQTTEventListenerProviderFactory.java

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,72 +17,69 @@
1717

1818
package org.softwarefactory.keycloak.providers.events.mqtt;
1919

20+
import java.util.HashSet;
2021
import org.keycloak.Config;
2122
import org.keycloak.events.EventListenerProvider;
2223
import org.keycloak.events.EventListenerProviderFactory;
2324
import org.keycloak.events.EventType;
2425
import org.keycloak.events.admin.OperationType;
2526
import org.keycloak.models.KeycloakSession;
2627
import org.keycloak.models.KeycloakSessionFactory;
27-
28-
import java.util.HashSet;
29-
import java.util.Set;
30-
import java.lang.Exception;
28+
import org.softwarefactory.keycloak.providers.events.models.Configuration;
3129

3230
/**
3331
* @author <a href="mailto:[email protected]">Matthieu Huin</a>
3432
*/
3533
public class MQTTEventListenerProviderFactory implements EventListenerProviderFactory {
3634

37-
private Set<EventType> excludedEvents;
38-
private Set<OperationType> excludedAdminOperations;
39-
private String serverUri;
40-
private String username;
41-
private String password;
42-
private String topic;
43-
private boolean usePersistence;
35+
private Configuration configuration;
4436

4537
@Override
4638
public EventListenerProvider create(KeycloakSession session) {
47-
return new MQTTEventListenerProvider(excludedEvents, excludedAdminOperations, serverUri, username, password, topic, usePersistence);
39+
return new MQTTEventListenerProvider(configuration);
4840
}
4941

5042
@Override
5143
public void init(Config.Scope config) {
44+
configuration = new Configuration();
5245
String[] excludes = config.getArray("exclude-events");
5346
if (excludes != null) {
54-
excludedEvents = new HashSet<>();
47+
configuration.excludedEvents = new HashSet<>();
5548
for (String e : excludes) {
56-
excludedEvents.add(EventType.valueOf(e));
49+
configuration.excludedEvents.add(EventType.valueOf(e));
5750
}
5851
}
5952

6053
String[] excludesOperations = config.getArray("excludesOperations");
6154
if (excludesOperations != null) {
62-
excludedAdminOperations = new HashSet<>();
55+
configuration.excludedAdminOperations = new HashSet<>();
6356
for (String e : excludesOperations) {
64-
excludedAdminOperations.add(OperationType.valueOf(e));
57+
configuration.excludedAdminOperations.add(OperationType.valueOf(e));
6558
}
6659
}
6760

68-
serverUri = config.get("serverUri", "tcp://localhost:1883");
69-
username = config.get("username", null);
70-
password = config.get("password", null);
71-
topic = config.get("topic", "keycloak/events");
72-
usePersistence = config.getBoolean("usePersistence", false);
61+
configuration.serverUri = config.get("serverUri", "tcp://localhost:1883");
62+
configuration.username = config.get("username", null);
63+
configuration.password = config.get("password", null);
64+
configuration.topic = config.get("topic", "keycloak/events");
65+
configuration.usePersistence = config.getBoolean("usePersistence", false);
66+
configuration.retained = config.getBoolean("retained", true);
67+
configuration.cleanSession = config.getBoolean("cleanSession", true);
68+
configuration.qos = config.getInt("qos", 0);
7369
}
7470

7571
@Override
7672
public void postInit(KeycloakSessionFactory factory) {
77-
73+
// not needed
7874
}
75+
7976
@Override
8077
public void close() {
78+
// not needed
8179
}
8280

8381
@Override
8482
public String getId() {
8583
return "mqtt";
8684
}
87-
88-
}
85+
}

0 commit comments

Comments
 (0)