keycloak-uncached

Details

diff --git a/core/src/main/java/org/keycloak/representations/idm/RequiredActionProviderSimpleRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RequiredActionProviderSimpleRepresentation.java
index 1e0a60d..492204d 100644
--- a/core/src/main/java/org/keycloak/representations/idm/RequiredActionProviderSimpleRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RequiredActionProviderSimpleRepresentation.java
@@ -25,9 +25,18 @@ package org.keycloak.representations.idm;
  */
 public class RequiredActionProviderSimpleRepresentation {
 
+    private String id;
     private String name;
     private String providerId;
 
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
     public String getName() {
         return name;
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
index a720a32..b481a75 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
@@ -28,6 +28,7 @@ import org.keycloak.authentication.FormAction;
 import org.keycloak.authentication.FormAuthenticator;
 import org.keycloak.authentication.RequiredActionFactory;
 import org.keycloak.authentication.RequiredActionProvider;
+import org.keycloak.events.admin.OperationType;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.AuthenticatorConfigModel;
@@ -212,7 +213,10 @@ public class AuthenticationManagementResource {
             return ErrorResponse.exists("Flow " + flow.getAlias() + " already exists");
         }
 
-        realm.addAuthenticationFlow(RepresentationToModel.toModel(flow));
+        AuthenticationFlowModel createdModel = realm.addAuthenticationFlow(RepresentationToModel.toModel(flow));
+
+        flow.setId(createdModel.getId());
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, createdModel.getId()).representation(flow).success();
         return Response.status(201).build();
     }
 
@@ -263,6 +267,9 @@ public class AuthenticationManagementResource {
         	realm.removeAuthenticatorExecution(execution);
         }
         realm.removeAuthenticationFlow(flow);
+
+        // Use just one event for top-level flow. Using separate events won't work properly for flows of depth 2 or bigger
+        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
     }
 
     /**
@@ -299,6 +306,9 @@ public class AuthenticationManagementResource {
         copy = realm.addAuthenticationFlow(copy);
         copy(newName, flow, copy);
 
+        data.put("id", copy.getId());
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(data).success();
+
         return Response.status(201).build();
 
     }
@@ -362,8 +372,10 @@ public class AuthenticationManagementResource {
         execution.setAuthenticatorFlow(true);
         execution.setAuthenticator(provider);
         execution.setPriority(getNextPriority(parentFlow));
+        execution = realm.addAuthenticatorExecution(execution);
 
-        realm.addAuthenticatorExecution(execution);
+        data.put("id", execution.getId());
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(data).success();
     }
 
     private int getNextPriority(AuthenticationFlowModel parentFlow) {
@@ -413,7 +425,10 @@ public class AuthenticationManagementResource {
         execution.setAuthenticator(provider);
         execution.setPriority(getNextPriority(parentFlow));
 
-        realm.addAuthenticatorExecution(execution);
+        execution = realm.addAuthenticatorExecution(execution);
+
+        data.put("id", execution.getId());
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(data).success();
     }
 
     /**
@@ -519,6 +534,7 @@ public class AuthenticationManagementResource {
         if (!model.getRequirement().name().equals(rep.getRequirement())) {
             model.setRequirement(AuthenticationExecutionModel.Requirement.valueOf(rep.getRequirement()));
             realm.updateAuthenticatorExecution(model);
+            adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
         }
     }
 
@@ -541,6 +557,8 @@ public class AuthenticationManagementResource {
         }
         model.setPriority(getNextPriority(parentFlow));
         model = realm.addAuthenticatorExecution(model);
+
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId()).representation(execution).success();
         return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
     }
 
@@ -592,6 +610,8 @@ public class AuthenticationManagementResource {
         realm.updateAuthenticatorExecution(previous);
         model.setPriority(tmp);
         realm.updateAuthenticatorExecution(model);
+
+        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).success();
     }
 
     public List<AuthenticationExecutionModel> getSortedExecutions(AuthenticationFlowModel parentFlow) {
@@ -635,6 +655,8 @@ public class AuthenticationManagementResource {
         realm.updateAuthenticatorExecution(model);
         next.setPriority(tmp);
         realm.updateAuthenticatorExecution(next);
+
+        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).success();
     }
 
 
@@ -666,6 +688,8 @@ public class AuthenticationManagementResource {
         }
 
         realm.removeAuthenticatorExecution(model);
+
+        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
     }
 
 
@@ -693,6 +717,9 @@ public class AuthenticationManagementResource {
         config = realm.addAuthenticatorConfig(config);
         model.setAuthenticatorConfig(config.getId());
         realm.updateAuthenticatorExecution(model);
+
+        json.setId(config.getId());
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(json).success();
         return Response.created(uriInfo.getAbsolutePathBuilder().path(config.getId()).build()).build();
     }
 
@@ -772,7 +799,10 @@ public class AuthenticationManagementResource {
         requiredAction.setProviderId(providerId);
         requiredAction.setDefaultAction(false);
         requiredAction.setEnabled(true);
-        realm.addRequiredActionProvider(requiredAction);
+        requiredAction = realm.addRequiredActionProvider(requiredAction);
+
+        data.put("id", requiredAction.getId());
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(data).success();
     }
 
 
@@ -850,6 +880,8 @@ public class AuthenticationManagementResource {
         update.setEnabled(rep.isEnabled());
         update.setConfig(rep.getConfig());
         realm.updateRequiredActionProvider(update);
+
+        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
     }
 
     /**
@@ -866,6 +898,8 @@ public class AuthenticationManagementResource {
             throw new NotFoundException("Failed to find required action.");
         }
         realm.removeRequiredActionProvider(model);
+
+        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
     }
 
     /**
@@ -947,6 +981,7 @@ public class AuthenticationManagementResource {
         auth.requireManage();
 
         AuthenticatorConfigModel config = realm.addAuthenticatorConfig(RepresentationToModel.toModel(rep));
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, config.getId()).representation(rep).success();
         return Response.created(uriInfo.getAbsolutePathBuilder().path(config.getId()).build()).build();
     }
 
@@ -995,6 +1030,8 @@ public class AuthenticationManagementResource {
         }
 
         realm.removeAuthenticatorConfig(config);
+
+        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
     }
 
     /**
@@ -1017,5 +1054,6 @@ public class AuthenticationManagementResource {
         exists.setAlias(rep.getAlias());
         exists.setConfig(rep.getConfig());
         realm.updateAuthenticatorConfig(exists);
+        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
     }
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java
index 50b11ac..d77c76c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java
@@ -19,19 +19,26 @@ package org.keycloak.testsuite.admin.authentication;
 
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.keycloak.admin.client.resource.AuthenticationManagementResource;
 import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.events.admin.OperationType;
 import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
 import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
 import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.util.AdminEventPaths;
+import org.keycloak.testsuite.util.AssertAdminEvents;
+import org.keycloak.testsuite.util.RealmBuilder;
 
 import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.List;
 
+import javax.ws.rs.core.Response;
+
 
 /**
  * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
@@ -48,6 +55,9 @@ public abstract class AbstractAuthenticationTest extends AbstractKeycloakTest {
     RealmResource realmResource;
     AuthenticationManagementResource authMgmtResource;
 
+    @Rule
+    public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this);
+
     @Before
     public void before() {
         realmResource = adminClient.realms().realm(REALM_NAME);
@@ -56,9 +66,8 @@ public abstract class AbstractAuthenticationTest extends AbstractKeycloakTest {
 
     @Override
     public void addTestRealms(List<RealmRepresentation> testRealms) {
-        RealmRepresentation testRealmRep = new RealmRepresentation();
-        testRealmRep.setRealm(REALM_NAME);
-        testRealmRep.setEnabled(true);
+        RealmRepresentation testRealmRep = RealmBuilder.create().name(REALM_NAME).testEventListener().build();
+        testRealmRep.setId(REALM_NAME);
         testRealms.add(testRealmRep);
     }
 
@@ -182,4 +191,11 @@ public abstract class AbstractAuthenticationTest extends AbstractKeycloakTest {
         config.setConfig(params);
         return config;
     }
+
+    void createFlow(AuthenticationFlowRepresentation flowRep) {
+        Response response = authMgmtResource.createFlow(flowRep);
+        org.keycloak.testsuite.Assert.assertEquals(201, response.getStatus());
+        response.close();
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AssertAdminEvents.isExpectedPrefixFollowedByUuid(AdminEventPaths.authFlowsPath()), flowRep);
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AuthenticatorConfigTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AuthenticatorConfigTest.java
index c5f7ed1..eb1cda5 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AuthenticatorConfigTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AuthenticatorConfigTest.java
@@ -28,11 +28,14 @@ import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticator;
 import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory;
+import org.keycloak.events.admin.OperationType;
 import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
 import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.util.AdminEventPaths;
+import org.keycloak.testsuite.util.AssertAdminEvents;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -43,13 +46,13 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
 
     @Before
     public void beforeConfigTest() {
-        Response response = authMgmtResource.createFlow(newFlow("firstBrokerLogin2", "firstBrokerLogin2", "basic-flow", true, false));
-        Assert.assertEquals(201, response.getStatus());
-        response.close();
+        AuthenticationFlowRepresentation flowRep = newFlow("firstBrokerLogin2", "firstBrokerLogin2", "basic-flow", true, false);
+        createFlow(flowRep);
 
         HashMap<String, String> params = new HashMap<>();
         params.put("provider", IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID);
         authMgmtResource.addExecution("firstBrokerLogin2", params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("firstBrokerLogin2"), params);
 
         List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("firstBrokerLogin2");
         AuthenticationExecutionInfoRepresentation exec = findExecutionByProvider(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, executionReps);
@@ -57,12 +60,6 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
         executionId = exec.getId();
     }
 
-    @Override
-    public void afterAbstractKeycloakTest() {
-        AuthenticationFlowRepresentation flowRep = findFlowByAlias("firstBrokerLogin2", authMgmtResource.getFlows());
-        authMgmtResource.deleteFlow(flowRep.getId());
-    }
-
 
     @Test
     public void testCreateConfig() {
@@ -82,6 +79,7 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
 
         // Cleanup
         authMgmtResource.removeAuthenticatorConfig(cfgId);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionConfigPath(cfgId));
     }
 
 
@@ -107,6 +105,7 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
         cfgRep.setAlias("foo2");
         cfgRep.getConfig().put("configKey2", "configValue2");
         authMgmtResource.updateAuthenticatorConfig(cfgRep.getId(), cfgRep);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authExecutionConfigPath(cfgId), cfgRep);
 
         // Assert updated
         cfgRep = authMgmtResource.getAuthenticatorConfig(cfgRep.getId());
@@ -137,7 +136,8 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
         }
 
         // Test remove our config
-        authMgmtResource.removeAuthenticatorConfig(cfgRep.getId());
+        authMgmtResource.removeAuthenticatorConfig(cfgId);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionConfigPath(cfgId));
 
         // Assert config not found
         try {
@@ -159,6 +159,7 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
         Assert.assertEquals(201, resp.getStatus());
         String cfgId = ApiUtil.getCreatedId(resp);
         Assert.assertNotNull(cfgId);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionConfigPath(executionId), cfg);
         return cfgId;
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ExecutionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ExecutionTest.java
index be0b9c4..ae19ff6 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ExecutionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ExecutionTest.java
@@ -21,10 +21,12 @@ import org.junit.Assert;
 import org.junit.Test;
 import org.keycloak.authentication.AuthenticationFlow;
 import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
-import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.events.admin.OperationType;
 import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
 import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
+import org.keycloak.testsuite.util.AdminEventPaths;
+import org.keycloak.testsuite.util.AssertAdminEvents;
 
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.NotFoundException;
@@ -60,8 +62,9 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         }
 
         // copy built-in flow so we get a new editable flow
-        params.put("newName", "Copy of browser");
+        params.put("newName", "Copy-of-browser");
         Response response = authMgmtResource.copy("browser", params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params);
         try {
             Assert.assertEquals("Copy flow", 201, response.getStatus());
         } finally {
@@ -71,17 +74,19 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         // add execution using inexistent provider
         params.put("provider", "test-execution");
         try {
-            authMgmtResource.addExecution("Copy of browser", params);
+            authMgmtResource.addExecution("CopyOfBrowser", params);
             Assert.fail("add execution with inexistent provider should fail");
         } catch(BadRequestException expected) {
+            // Expected
         }
 
         // add execution - should succeed
         params.put("provider", "idp-review-profile");
-        authMgmtResource.addExecution("Copy of browser", params);
+        authMgmtResource.addExecution("Copy-of-browser", params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("Copy-of-browser"), params);
 
         // check execution was added
-        List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("Copy of browser");
+        List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("Copy-of-browser");
         AuthenticationExecutionInfoRepresentation exec = findExecutionByProvider("idp-review-profile", executionReps);
         Assert.assertNotNull("idp-review-profile added", exec);
 
@@ -92,9 +97,10 @@ public class ExecutionTest extends AbstractAuthenticationTest {
 
         // remove execution
         authMgmtResource.removeExecution(exec.getId());
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionPath(exec.getId()));
 
         // check execution was removed
-        executionReps = authMgmtResource.getExecutions("Copy of browser");
+        executionReps = authMgmtResource.getExecutions("Copy-of-browser");
         exec = findExecutionByProvider("idp-review-profile", executionReps);
         Assert.assertNull("idp-review-profile removed", exec);
 
@@ -102,6 +108,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
 
         // delete auth-cookie
         authMgmtResource.removeExecution(authCookieExec.getId());
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionPath(authCookieExec.getId()));
 
         AuthenticationExecutionRepresentation rep = new AuthenticationExecutionRepresentation();
         rep.setPriority(10);
@@ -135,13 +142,14 @@ public class ExecutionTest extends AbstractAuthenticationTest {
             response.close();
         }
 
-        // get Copy of browser flow id, and set it on execution
+        // get Copy-of-browser flow id, and set it on execution
         List<AuthenticationFlowRepresentation> flows = authMgmtResource.getFlows();
-        AuthenticationFlowRepresentation flow = findFlowByAlias("Copy of browser", flows);
+        AuthenticationFlowRepresentation flow = findFlowByAlias("Copy-of-browser", flows);
         rep.setParentFlow(flow.getId());
 
         // add execution - should succeed
         response = authMgmtResource.addExecution(rep);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AssertAdminEvents.isExpectedPrefixFollowedByUuid(AdminEventPaths.authMgmtBasePath() + "/executions"), rep);
         try {
             Assert.assertEquals("added execution", 201, response.getStatus());
         } finally {
@@ -149,7 +157,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         }
 
         // check execution was added
-        List<AuthenticationExecutionInfoRepresentation> executions = authMgmtResource.getExecutions("Copy of browser");
+        List<AuthenticationExecutionInfoRepresentation> executions = authMgmtResource.getExecutions("Copy-of-browser");
         exec = findExecutionByProvider("auth-cookie", executions);
         Assert.assertNotNull("auth-cookie added", exec);
 
@@ -170,6 +178,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         // switch from DISABLED to ALTERNATIVE
         exec.setRequirement(DISABLED);
         authMgmtResource.updateExecutions("browser", exec);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), exec);
 
         // make sure the change is visible
         executionReps = authMgmtResource.getExecutions("browser");
@@ -183,14 +192,13 @@ public class ExecutionTest extends AbstractAuthenticationTest {
     public void testClientFlowExecutions() {
         // Create client flow
         AuthenticationFlowRepresentation clientFlow = newFlow("new-client-flow", "desc", AuthenticationFlow.CLIENT_FLOW, true, false);
-        Response response = authMgmtResource.createFlow(clientFlow);
-        Assert.assertEquals(201, response.getStatus());
-        response.close();
+        createFlow(clientFlow);
 
         // Add execution to it
         Map<String, String> executionData = new HashMap<>();
         executionData.put("provider", ClientIdAndSecretAuthenticator.PROVIDER_ID);
         authMgmtResource.addExecution("new-client-flow", executionData);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("new-client-flow"), executionData);
 
         // Check executions of not-existent flow - SHOULD FAIL
         try {
@@ -226,6 +234,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         // Update success
         executionRep.setRequirement(ALTERNATIVE);
         authMgmtResource.updateExecutions("new-client-flow", executionRep);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("new-client-flow"), executionRep);
 
         // Check updated
         executionRep = findExecutionByProvider(ClientIdAndSecretAuthenticator.PROVIDER_ID, authMgmtResource.getExecutions("new-client-flow"));
@@ -241,7 +250,10 @@ public class ExecutionTest extends AbstractAuthenticationTest {
 
         // Successfuly remove execution and flow
         authMgmtResource.removeExecution(executionRep.getId());
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionPath(executionRep.getId()));
+
         AuthenticationFlowRepresentation rep = findFlowByAlias("new-client-flow", authMgmtResource.getFlows());
         authMgmtResource.deleteFlow(rep.getId());
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authFlowPath(rep.getId()));
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/FlowTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/FlowTest.java
index 80d17bb..7e2f4a8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/FlowTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/FlowTest.java
@@ -19,8 +19,10 @@ package org.keycloak.testsuite.admin.authentication;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.keycloak.events.admin.OperationType;
 import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
+import org.keycloak.testsuite.util.AdminEventPaths;
 
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.NotFoundException;
@@ -67,12 +69,7 @@ public class FlowTest extends AbstractAuthenticationTest {
 
         // create new flow that should succeed
         AuthenticationFlowRepresentation newFlow = newFlow("browser-2", "Browser flow", "basic-flow", true, false);
-        response = authMgmtResource.createFlow(newFlow);
-        try {
-            Assert.assertEquals("createFlow success", 201, response.getStatus());
-        } finally {
-            response.close();
-        }
+        createFlow(newFlow);
 
         // check that new flow is returned in a children list
         flows = authMgmtResource.getFlows();
@@ -122,6 +119,7 @@ public class FlowTest extends AbstractAuthenticationTest {
         // Successfully add flow
         data.put("alias", "SomeFlow");
         authMgmtResource.addExecutionFlow("browser-2", data);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("browser-2"), data);
 
         // check that new flow is returned in a children list
         flows = authMgmtResource.getFlows();
@@ -143,6 +141,7 @@ public class FlowTest extends AbstractAuthenticationTest {
 
         // delete non-built-in flow
         authMgmtResource.deleteFlow(found.getId());
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authFlowPath(found.getId()));
 
         // check the deleted flow is no longer returned
         flows = authMgmtResource.getFlows();
@@ -185,6 +184,7 @@ public class FlowTest extends AbstractAuthenticationTest {
         // copy that should succeed
         params.put("newName", "Copy of browser");
         response = authMgmtResource.copy("browser", params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params);
         try {
             Assert.assertEquals("Copy flow", 201, response.getStatus());
         } finally {
@@ -219,6 +219,7 @@ public class FlowTest extends AbstractAuthenticationTest {
         Response response = authMgmtResource.copy("browser", params);
         Assert.assertEquals(201, response.getStatus());
         response.close();
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params);
 
         params = new HashMap<>();
         params.put("alias", "child");
@@ -227,6 +228,7 @@ public class FlowTest extends AbstractAuthenticationTest {
         params.put("type", "basic-flow");
 
         authMgmtResource.addExecutionFlow("parent", params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("parent"), params);
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RegistrationFlowTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RegistrationFlowTest.java
index bf2babe..d7e25b6 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RegistrationFlowTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RegistrationFlowTest.java
@@ -25,6 +25,9 @@ import javax.ws.rs.core.Response;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
+import org.keycloak.testsuite.util.AdminEventPaths;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -34,13 +37,8 @@ public class RegistrationFlowTest extends AbstractAuthenticationTest {
     @Test
     public void testAddExecution() {
         // Add registration flow 2
-        Response response = authMgmtResource.createFlow(newFlow("registration2", "RegistrationFlow2", "basic-flow", true, false));
-        try {
-            Assert.assertEquals("createFlow success", 201, response.getStatus());
-        } finally {
-            response.close();
-        }
-
+        AuthenticationFlowRepresentation flowRep = newFlow("registration2", "RegistrationFlow2", "basic-flow", true, false);
+        createFlow(flowRep);
 
         // add registration execution form flow
         Map<String, String> data = new HashMap<>();
@@ -49,6 +47,7 @@ public class RegistrationFlowTest extends AbstractAuthenticationTest {
         data.put("description", "registrationForm2 flow");
         data.put("provider", "registration-page-form");
         authMgmtResource.addExecutionFlow("registration2", data);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("registration2"), data);
 
         // Should fail to add execution under top level flow
         Map<String, String> data2 = new HashMap<>();
@@ -63,9 +62,9 @@ public class RegistrationFlowTest extends AbstractAuthenticationTest {
 
         // Should success to add execution under form flow
         authMgmtResource.addExecution("registrationForm2", data2);
-
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("registrationForm2"), data2);
     }
 
-    // TODO: More coverage... And hopefully more type-safety instead of passing generic maps
+    // TODO: More type-safety instead of passing generic maps
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RequiredActionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RequiredActionsTest.java
index 7418cb1..8d45830 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RequiredActionsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RequiredActionsTest.java
@@ -19,9 +19,11 @@ package org.keycloak.testsuite.admin.authentication;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.keycloak.events.admin.OperationType;
 import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
 import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation;
 import org.keycloak.testsuite.actions.DummyRequiredActionFactory;
+import org.keycloak.testsuite.util.AdminEventPaths;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -59,6 +61,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
 
         forUpdate.setConfig(Collections.<String, String>emptyMap());
         authMgmtResource.updateRequiredAction(forUpdate.getAlias(), forUpdate);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(forUpdate.getAlias()));
 
         result = authMgmtResource.getRequiredActions();
         RequiredActionProviderRepresentation updated = findRequiredActionByAlias(forUpdate.getAlias(), result);
@@ -78,6 +81,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
 
         // Register it
         authMgmtResource.registerRequiredAction(action);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authMgmtBasePath() + "/register-required-action", action);
 
         // Try to find not-existent action - should fail
         try {
@@ -103,6 +107,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
         // Update (set it as defaultAction)
         rep.setDefaultAction(true);
         authMgmtResource.updateRequiredAction(DummyRequiredActionFactory.PROVIDER_ID, rep);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), rep);
         compareRequiredAction(rep, newRequiredAction(DummyRequiredActionFactory.PROVIDER_ID, "Dummy Action",
                 true, true, Collections.emptyMap()));
 
@@ -116,6 +121,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
 
         // Remove success
         authMgmtResource.removeRequiredAction(DummyRequiredActionFactory.PROVIDER_ID);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authRequiredActionPath(rep.getAlias()));
 
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ShiftExecutionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ShiftExecutionTest.java
index 9ce4f53..ba8ae09 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ShiftExecutionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ShiftExecutionTest.java
@@ -19,7 +19,9 @@ package org.keycloak.testsuite.admin.authentication;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.keycloak.events.admin.OperationType;
 import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
+import org.keycloak.testsuite.util.AdminEventPaths;
 
 import javax.ws.rs.NotFoundException;
 import javax.ws.rs.BadRequestException;
@@ -39,6 +41,7 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
         HashMap<String, String> params = new HashMap<>();
         params.put("newName", "Copy of browser");
         Response response = authMgmtResource.copy("browser", params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params);
         try {
             Assert.assertEquals("Copy flow", 201, response.getStatus());
         } finally {
@@ -61,6 +64,7 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
 
         // shift last execution up
         authMgmtResource.raisePriority(last.getId());
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRaiseExecutionPath(last.getId()));
 
         List<AuthenticationExecutionInfoRepresentation> executions2 = authMgmtResource.getExecutions("Copy of browser");
 
@@ -80,6 +84,7 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
 
         // shift one before last down
         authMgmtResource.lowerPriority(oneButLast2.getId());
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authLowerExecutionPath(oneButLast2.getId()));
 
         executions2 = authMgmtResource.getExecutions("Copy of browser");
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AdminEventPaths.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AdminEventPaths.java
index 7ff548a..1b15400 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AdminEventPaths.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AdminEventPaths.java
@@ -21,6 +21,7 @@ import java.net.URI;
 
 import javax.ws.rs.core.UriBuilder;
 
+import org.keycloak.admin.client.resource.AuthenticationManagementResource;
 import org.keycloak.admin.client.resource.ClientAttributeCertificateResource;
 import org.keycloak.admin.client.resource.ClientInitialAccessResource;
 import org.keycloak.admin.client.resource.ClientResource;
@@ -353,4 +354,83 @@ public class AdminEventPaths {
     }
 
 
+    // AUTHENTICATION FLOWS
+
+    public static String authMgmtBasePath() {
+        URI uri = UriBuilder.fromUri("").path(RealmResource.class, "flows")
+                .build();
+        return uri.toString();
+    }
+
+    public static String authFlowsPath() {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "getFlows")
+                .build();
+        return uri.toString();
+    }
+
+    public static String authFlowPath(String flowId) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "getFlow")
+                .build(flowId);
+        return uri.toString();
+    }
+
+    public static String authCopyFlowPath(String flowAlias) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "copy")
+                .build(flowAlias);
+        return uri.toString();
+    }
+
+    public static String authAddExecutionFlowPath(String flowAlias) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "addExecutionFlow")
+                .build(flowAlias);
+        return uri.toString();
+    }
+
+    public static String authAddExecutionPath(String flowAlias) {
+        return authFlowPath(flowAlias) + "/executions/execution";
+    }
+
+    public static String authUpdateExecutionPath(String flowAlias) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "updateExecutions")
+                .build(flowAlias);
+        return uri.toString();
+    }
+
+    public static String authExecutionPath(String executionId) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "removeExecution")
+                .build(executionId);
+        return uri.toString();
+    }
+
+    public static String authAddExecutionConfigPath(String executionId) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "newExecutionConfig")
+                .build(executionId);
+        return uri.toString();
+    }
+
+    public static String authExecutionConfigPath(String configId) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "getAuthenticatorConfig")
+                .build(configId);
+        return uri.toString();
+    }
+
+    public static String authRaiseExecutionPath(String executionId) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "raisePriority")
+                .build(executionId);
+        return uri.toString();
+    }
+
+    public static String authLowerExecutionPath(String executionId) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "lowerPriority")
+                .build(executionId);
+        return uri.toString();
+    }
+
+    public static String authRequiredActionPath(String requiredActionAlias) {
+        URI uri = UriBuilder.fromUri(authMgmtBasePath()).path(AuthenticationManagementResource.class, "getRequiredAction")
+                .build(requiredActionAlias);
+        return uri.toString();
+    }
+
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AssertAdminEvents.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AssertAdminEvents.java
index 0383a45..83b6f14 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AssertAdminEvents.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AssertAdminEvents.java
@@ -19,11 +19,14 @@ package org.keycloak.testsuite.util;
 
 import java.io.IOException;
 import java.lang.reflect.Method;
+import java.util.Map;
 
 import javax.ws.rs.core.Response;
 
+import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.Matchers;
+import org.hamcrest.TypeSafeMatcher;
 import org.junit.rules.TestRule;
 import org.junit.runners.model.Statement;
 import org.keycloak.common.util.ObjectUtil;
@@ -205,12 +208,27 @@ public class AssertAdminEvents implements TestRule {
                     try {
                         Object actualRep = JsonSerialization.readValue(actual.getRepresentation(), expectedRep.getClass());
 
-                        for (Method method : Reflections.getAllDeclaredMethods(expectedRep.getClass())) {
-                            if (method.getName().startsWith("get") || method.getName().startsWith("is")) {
-                                Object expectedValue = Reflections.invokeMethod(method, expectedRep);
+                        if (expectedRep instanceof Map) {
+                            // Special comparing of representations of type map. All of "expected" must be available on "actual"
+                            Map<?, ?> expectedRepMap = (Map) expectedRep;
+                            Map<?, ?> actualRepMap = (Map) actualRep;
+
+                            for (Map.Entry entry : expectedRepMap.entrySet()) {
+                                Object expectedValue = entry.getValue();
                                 if (expectedValue != null) {
-                                    Object actualValue = Reflections.invokeMethod(method, actualRep);
-                                    Assert.assertEquals("Property " + method.getName() + " of representation not equal.", expectedValue, actualValue);
+                                    Object actualValue = actualRepMap.get(entry.getKey());
+                                    Assert.assertEquals("Map item with key '" + entry.getKey() + "' not equal.", expectedValue, actualValue);
+                                }
+                            }
+                        } else {
+                            // Reflection-baseed comparing for other types
+                            for (Method method : Reflections.getAllDeclaredMethods(expectedRep.getClass())) {
+                                if (method.getName().startsWith("get") || method.getName().startsWith("is")) {
+                                    Object expectedValue = Reflections.invokeMethod(method, expectedRep);
+                                    if (expectedValue != null) {
+                                        Object actualValue = Reflections.invokeMethod(method, actualRep);
+                                        Assert.assertEquals("Property method '" + method.getName() + "' of representation not equal.", expectedValue, actualValue);
+                                    }
                                 }
                             }
                         }
@@ -241,5 +259,22 @@ public class AssertAdminEvents implements TestRule {
         }
     }
 
+    public static Matcher<String> isExpectedPrefixFollowedByUuid(final String prefix) {
+        return new TypeSafeMatcher<String>() {
+
+            @Override
+            protected boolean matchesSafely(String item) {
+                int expectedLength = prefix.length() + 1 + org.keycloak.models.utils.KeycloakModelUtils.generateId().length();
+                return item.startsWith(prefix) && expectedLength == item.length();
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("resourcePath in the format like \"" + prefix + "/<UUID>\"");
+            }
+
+        };
+    }
+
 
 }