keycloak-uncached

Details

diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java
index 39be678..2d5ca2a 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java
@@ -34,15 +34,16 @@ import org.keycloak.util.JsonSerialization;
 
 import javax.ws.rs.core.UriInfo;
 import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 public class AdminEventBuilder {
 
     protected static final Logger logger = Logger.getLogger(AdminEventBuilder.class);
 
     private EventStoreProvider store;
-    private List<EventListenerProvider> listeners;
+    private Map<String, EventListenerProvider> listeners;
     private RealmModel realm;
     private AdminEvent adminEvent;
 
@@ -50,26 +51,9 @@ public class AdminEventBuilder {
         this.realm = realm;
         adminEvent = new AdminEvent();
 
-        if (realm.isAdminEventsEnabled()) {
-            EventStoreProvider store = session.getProvider(EventStoreProvider.class);
-            if (store != null) {
-                this.store = store;
-            } else {
-                ServicesLogger.LOGGER.noEventStoreProvider();
-            }
-        }
-
-        if (realm.getEventsListeners() != null && !realm.getEventsListeners().isEmpty()) {
-            this.listeners = new LinkedList<>();
-            for (String id : realm.getEventsListeners()) {
-                EventListenerProvider listener = session.getProvider(EventListenerProvider.class, id);
-                if (listener != null) {
-                    listeners.add(listener);
-                } else {
-                    ServicesLogger.LOGGER.providerNotFound(id);
-                }
-            }
-        }
+        this.listeners = new HashMap<>();
+        updateStore(session);
+        addListeners(session);
 
         authRealm(auth.getRealm());
         authClient(auth.getClient());
@@ -87,6 +71,45 @@ public class AdminEventBuilder {
         return this;
     }
 
+    /**
+     * Refreshes the builder assuming that the realm event information has 
+     * changed. Thought to be used when the updateRealmEventsConfig has
+     * modified the events configuration. Now the store and the listeners are 
+     * updated to have previous and new setup.
+     * @param session The session
+     * @return The same builder
+     */
+    public AdminEventBuilder refreshRealmEventsConfig(KeycloakSession session) {
+        return this.updateStore(session).addListeners(session);
+    }
+    
+    private AdminEventBuilder updateStore(KeycloakSession session) {
+        if (realm.isAdminEventsEnabled() && store == null) {
+            this.store = session.getProvider(EventStoreProvider.class);
+            if (store == null) {
+                ServicesLogger.LOGGER.noEventStoreProvider();
+            }
+        }
+        return this;
+    }
+    
+    private AdminEventBuilder addListeners(KeycloakSession session) {
+        Set<String> extraListeners = realm.getEventsListeners();
+        if (extraListeners != null && !extraListeners.isEmpty()) {
+            for (String id : extraListeners) {
+                if (!listeners.containsKey(id)) {
+                    EventListenerProvider listener = session.getProvider(EventListenerProvider.class, id);
+                    if (listener != null) {
+                        listeners.put(id, listener);
+                    } else {
+                        ServicesLogger.LOGGER.providerNotFound(id);
+                    }
+                }
+            }
+        }
+        return this;
+    }
+
     public AdminEventBuilder operation(OperationType operationType) {
         adminEvent.setOperationType(operationType);
         return this;
@@ -220,7 +243,7 @@ public class AdminEventBuilder {
         }
 
         if (listeners != null) {
-            for (EventListenerProvider l : listeners) {
+            for (EventListenerProvider l : listeners.values()) {
                 try {
                     l.onEvent(adminEvent, includeRepresentation);
                 } catch (Throwable t) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 585e287..683b44a 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -680,6 +680,11 @@ public class RealmAdminResource {
 
         logger.debug("updating realm events config: " + realm.getName());
         new RealmManager(session).updateRealmEventsConfig(rep, realm);
+        adminEvent.operation(OperationType.UPDATE).resource(ResourceType.REALM).realm(realm)
+                .resourcePath(session.getContext().getUri()).representation(rep)
+                // refresh the builder to consider old and new config
+                .refreshRealmEventsConfig(session)
+                .success();
     }
 
     /**
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AdminEventTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AdminEventTest.java
index ce23308..90e5125 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AdminEventTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AdminEventTest.java
@@ -39,6 +39,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 
 /**
  * Test getting and filtering admin events.
@@ -153,4 +154,37 @@ public class AdminEventTest extends AbstractEventTest {
         assertTrue(realm.getAdminEvents(null, null, null, null, null, null, null, null, 0, 1000).size() >= 110);
     }
 
+    private void checkupdateRealmEventsConfigEvent(int size) {
+        List<AdminEventRepresentation> events = events();
+        assertEquals(size, events.size());
+        AdminEventRepresentation event = events().get(0);assertEquals("UPDATE", event.getOperationType());
+        assertEquals(realmName(), event.getRealmId());
+        assertEquals("events/config", event.getResourcePath());
+        assertEquals("master", event.getAuthDetails().getRealmId());
+        assertNotNull(event.getRepresentation());
+    }
+    
+    @Test
+    public void updateRealmEventsConfig() {
+        // change from OFF to ON should be stored
+        configRep.setAdminEventsDetailsEnabled(Boolean.TRUE);
+        configRep.setAdminEventsEnabled(Boolean.TRUE);
+        saveConfig();
+        checkupdateRealmEventsConfigEvent(1);
+        
+        // any other change should be store too
+        configRep.setEventsEnabled(Boolean.TRUE);
+        saveConfig();
+        checkupdateRealmEventsConfigEvent(2);
+        
+        // change from ON to OFF should be stored too
+        configRep.setAdminEventsEnabled(Boolean.FALSE);
+        saveConfig();
+        checkupdateRealmEventsConfigEvent(3);
+        
+        // another change should not be stored cos it was OFF already
+        configRep.setAdminEventsDetailsEnabled(Boolean.FALSE);
+        saveConfig();
+        assertEquals(3, events().size());
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
index 56d2bee..b9c43a6 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
@@ -75,6 +75,10 @@ import java.util.Map;
 import javax.ws.rs.BadRequestException;
 
 import static org.junit.Assert.*;
+import org.keycloak.events.EventType;
+import org.keycloak.events.log.JBossLoggingEventListenerProviderFactory;
+import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
+import org.keycloak.testsuite.events.EventsListenerProviderFactory;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -282,6 +286,64 @@ public class RealmTest extends AbstractAdminTest {
         adminClient.realms().realm("test-immutable").remove();
     }
 
+    private RealmEventsConfigRepresentation copyRealmEventsConfigRepresentation(RealmEventsConfigRepresentation rep) {
+        RealmEventsConfigRepresentation recr = new RealmEventsConfigRepresentation();
+        recr.setEnabledEventTypes(rep.getEnabledEventTypes());
+        recr.setEventsListeners(rep.getEventsListeners());
+        recr.setEventsExpiration(rep.getEventsExpiration());
+        recr.setEventsEnabled(rep.isEventsEnabled());
+        recr.setAdminEventsEnabled(rep.isAdminEventsEnabled());
+        recr.setAdminEventsDetailsEnabled(rep.isAdminEventsDetailsEnabled());
+        return recr;
+    }
+    
+    private void checkRealmEventsConfigRepresentation(RealmEventsConfigRepresentation expected,
+            RealmEventsConfigRepresentation actual) {
+        assertEquals(expected.getEnabledEventTypes().size(), actual.getEnabledEventTypes().size());
+        assertTrue(actual.getEnabledEventTypes().containsAll(expected.getEnabledEventTypes()));
+        assertEquals(expected.getEventsListeners().size(), actual.getEventsListeners().size());
+        assertTrue(actual.getEventsListeners().containsAll(expected.getEventsListeners()));
+        assertEquals(expected.getEventsExpiration(), actual.getEventsExpiration());
+        assertEquals(expected.isEventsEnabled(), actual.isEventsEnabled());
+        assertEquals(expected.isAdminEventsEnabled(), actual.isAdminEventsEnabled());
+        assertEquals(expected.isAdminEventsDetailsEnabled(), actual.isAdminEventsDetailsEnabled());
+    }
+    
+    @Test
+    public void updateRealmEventsConfig() {
+        RealmEventsConfigRepresentation rep = realm.getRealmEventsConfig();
+        RealmEventsConfigRepresentation repOrig = copyRealmEventsConfigRepresentation(rep);
+        
+        // the "event-queue" listener should be enabled by default
+        assertTrue("event-queue should be enabled initially", rep.getEventsListeners().contains(EventsListenerProviderFactory.PROVIDER_ID));
+        
+        // first modification => remove "event-queue", should be sent to the queue
+        rep.setEnabledEventTypes(Arrays.asList(EventType.LOGIN.name(), EventType.LOGIN_ERROR.name()));
+        rep.setEventsListeners(Arrays.asList(JBossLoggingEventListenerProviderFactory.ID));
+        rep.setEventsExpiration(36000L);
+        rep.setEventsEnabled(true);
+        rep.setAdminEventsEnabled(true);
+        rep.setAdminEventsDetailsEnabled(true);
+        adminClient.realms().realm(REALM_NAME).updateRealmEventsConfig(rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, "events/config", rep, ResourceType.REALM);
+        RealmEventsConfigRepresentation actual = realm.getRealmEventsConfig();
+        checkRealmEventsConfigRepresentation(rep, actual);
+        
+        // second modification => should not be sent cos event-queue was removed in the first mod
+        rep.setEnabledEventTypes(Arrays.asList(EventType.LOGIN.name(), 
+                EventType.LOGIN_ERROR.name(), EventType.CLIENT_LOGIN.name()));
+        adminClient.realms().realm(REALM_NAME).updateRealmEventsConfig(rep);
+        assertAdminEvents.assertEmpty();
+        actual = realm.getRealmEventsConfig();
+        checkRealmEventsConfigRepresentation(rep, actual);
+        
+        // third modification => restore queue => should be sent and recovered
+        adminClient.realms().realm(REALM_NAME).updateRealmEventsConfig(repOrig);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, "events/config", repOrig, ResourceType.REALM);
+        actual = realm.getRealmEventsConfig();
+        checkRealmEventsConfigRepresentation(repOrig, actual);
+    }
+
     @Test
     public void updateRealm() {
         // first change