keycloak-uncached
Changes
core/src/main/java/org/keycloak/representations/idm/RequiredActionProviderSimpleRepresentation.java 9(+9 -0)
services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java 46(+42 -4)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java 22(+19 -3)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AuthenticatorConfigTest.java 21(+11 -10)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ExecutionTest.java 36(+24 -12)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/FlowTest.java 14(+8 -6)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RegistrationFlowTest.java 17(+8 -9)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RequiredActionsTest.java 6(+6 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ShiftExecutionTest.java 5(+5 -0)
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>\"");
+ }
+
+ };
+ }
+
}