KEYCLOAK-1976: Add support for events into admin-rest-client. Also,

arquillian tests for events.
This commit is contained in:
Stan Silvert 2016-02-05 18:42:50 -05:00
parent 23e5357870
commit e89f511465
10 changed files with 798 additions and 14 deletions

View file

@ -0,0 +1,90 @@
/*
* Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.keycloak.representations.idm;
/**
*
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
*/
public class AdminEventRepresentation {
private long time;
private String realmId;
private AuthDetailsRepresentation authDetails;
private String operationType;
private String resourcePath;
private String representation;
private String error;
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public AuthDetailsRepresentation getAuthDetails() {
return authDetails;
}
public void setAuthDetails(AuthDetailsRepresentation authDetails) {
this.authDetails = authDetails;
}
public String getOperationType() {
return operationType;
}
public void setOperationType(String operationType) {
this.operationType = operationType;
}
public String getResourcePath() {
return resourcePath;
}
public void setResourcePath(String resourcePath) {
this.resourcePath = resourcePath;
}
public String getRepresentation() {
return representation;
}
public void setRepresentation(String representation) {
this.representation = representation;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.keycloak.representations.idm;
/**
*
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
*/
public class AuthDetailsRepresentation {
private String realmId;
private String clientId;
private String userId;
private String ipAddress;
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
}

View file

@ -0,0 +1,108 @@
/*
* Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.keycloak.representations.idm;
import java.util.Map;
/**
*
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
*/
public class EventRepresentation {
private long time;
private String type;
private String realmId;
private String clientId;
private String userId;
private String sessionId;
private String ipAddress;
private String error;
private Map<String, String> details;
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public Map<String, String> getDetails() {
return details;
}
public void setDetails(Map<String, String> details) {
this.details = details;
}
}

View file

@ -19,6 +19,7 @@ package org.keycloak.admin.client.resource;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.GroupRepresentation; import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
@ -26,6 +27,8 @@ import javax.ws.rs.*;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
/** /**
* @author rodrigo.sasaki@icarros.com.br * @author rodrigo.sasaki@icarros.com.br
@ -61,6 +64,52 @@ public interface RealmResource {
@Path("groups") @Path("groups")
GroupsResource groups(); GroupsResource groups();
@DELETE
@Path("events")
void clearEvents();
@GET
@Path("events")
@Produces(MediaType.APPLICATION_JSON)
List<EventRepresentation> getEvents();
@Path("events")
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public List<EventRepresentation> getEvents(@QueryParam("type") List<String> types, @QueryParam("client") String client,
@QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
@QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults);
@DELETE
@Path("admin-events")
void clearAdminEvents();
@GET
@Path("admin-events")
@Produces(MediaType.APPLICATION_JSON)
List<AdminEventRepresentation> getAdminEvents();
@GET
@Path("admin-events")
@Produces(MediaType.APPLICATION_JSON)
List<AdminEventRepresentation> getAdminEvents(@QueryParam("operationTypes") List<String> operationTypes, @QueryParam("authRealm") String authRealm, @QueryParam("authClient") String authClient,
@QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress,
@QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom,
@QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults);
@GET
@Path("events/config")
@Produces(MediaType.APPLICATION_JSON)
public RealmEventsConfigRepresentation getRealmEventsConfig();
@PUT
@Path("events/config")
@Consumes(MediaType.APPLICATION_JSON)
public void updateRealmEventsConfig(RealmEventsConfigRepresentation rep);
@GET @GET
@Path("group-by-path/{path: .*}") @Path("group-by-path/{path: .*}")
@NoCache @NoCache

View file

@ -17,6 +17,9 @@
package org.keycloak.models.utils; package org.keycloak.models.utils;
import org.keycloak.events.Event;
import org.keycloak.events.admin.AdminEvent;
import org.keycloak.events.admin.AuthDetails;
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.AuthenticatorConfigModel;
@ -41,12 +44,15 @@ import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.AuthDetailsRepresentation;
import org.keycloak.representations.idm.AuthenticationExecutionRepresentation; import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation; import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation; import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ClientTemplateRepresentation; import org.keycloak.representations.idm.ClientTemplateRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.FederatedIdentityRepresentation; import org.keycloak.representations.idm.FederatedIdentityRepresentation;
import org.keycloak.representations.idm.GroupRepresentation; import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
@ -167,6 +173,43 @@ public class ModelToRepresentation {
return rep; return rep;
} }
public static EventRepresentation toRepresentation(Event event) {
EventRepresentation rep = new EventRepresentation();
rep.setTime(event.getTime());
rep.setType(event.getType().toString());
rep.setRealmId(event.getRealmId());
rep.setClientId(event.getClientId());
rep.setUserId(event.getUserId());
rep.setSessionId(event.getSessionId());
rep.setError(event.getError());
rep.setDetails(event.getDetails());
return rep;
}
public static AdminEventRepresentation toRepresentation(AdminEvent adminEvent) {
AdminEventRepresentation rep = new AdminEventRepresentation();
rep.setTime(adminEvent.getTime());
rep.setRealmId(adminEvent.getRealmId());
if (adminEvent.getAuthDetails() != null) {
rep.setAuthDetails(toRepresentation(adminEvent.getAuthDetails()));
}
rep.setOperationType(adminEvent.getOperationType().toString());
rep.setResourcePath(adminEvent.getResourcePath());
rep.setRepresentation(adminEvent.getRepresentation());
rep.setError(adminEvent.getError());
return rep;
}
public static AuthDetailsRepresentation toRepresentation(AuthDetails authDetails) {
AuthDetailsRepresentation rep = new AuthDetailsRepresentation();
rep.setRealmId(authDetails.getRealmId());
rep.setClientId(authDetails.getClientId());
rep.setUserId(authDetails.getUserId());
rep.setIpAddress(authDetails.getIpAddress());
return rep;
}
public static RoleRepresentation toRepresentation(RoleModel role) { public static RoleRepresentation toRepresentation(RoleModel role) {
RoleRepresentation rep = new RoleRepresentation(); RoleRepresentation rep = new RoleRepresentation();
rep.setId(role.getId()); rep.setId(role.getId());
@ -383,15 +426,15 @@ public class ModelToRepresentation {
if (realm.getEventsListeners() != null) { if (realm.getEventsListeners() != null) {
rep.setEventsListeners(new LinkedList<>(realm.getEventsListeners())); rep.setEventsListeners(new LinkedList<>(realm.getEventsListeners()));
} }
if(realm.getEnabledEventTypes() != null) { if(realm.getEnabledEventTypes() != null) {
rep.setEnabledEventTypes(new LinkedList<>(realm.getEnabledEventTypes())); rep.setEnabledEventTypes(new LinkedList<>(realm.getEnabledEventTypes()));
} }
rep.setAdminEventsEnabled(realm.isAdminEventsEnabled()); rep.setAdminEventsEnabled(realm.isAdminEventsEnabled());
rep.setAdminEventsDetailsEnabled(realm.isAdminEventsDetailsEnabled()); rep.setAdminEventsDetailsEnabled(realm.isAdminEventsDetailsEnabled());
return rep; return rep;
} }

View file

@ -45,8 +45,11 @@ import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
import org.keycloak.representations.adapters.action.GlobalRequestResult; import org.keycloak.representations.adapters.action.GlobalRequestResult;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.GroupRepresentation; import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.PartialImportRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation; import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
@ -75,6 +78,7 @@ import javax.ws.rs.core.UriInfo;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
@ -82,7 +86,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
import org.keycloak.partialimport.PartialImportManager; import org.keycloak.partialimport.PartialImportManager;
import org.keycloak.representations.idm.PartialImportRepresentation;
/** /**
* Base resource class for the admin REST api of one realm * Base resource class for the admin REST api of one realm
@ -428,6 +431,7 @@ public class RealmAdminResource {
* *
* Returns all events, or filters them based on URL query parameters listed here * Returns all events, or filters them based on URL query parameters listed here
* *
* @param types The types of events to return
* @param client App or oauth client name * @param client App or oauth client name
* @param user User id * @param user User id
* @param ipAddress IP address * @param ipAddress IP address
@ -441,7 +445,7 @@ public class RealmAdminResource {
@GET @GET
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<Event> getEvents(@QueryParam("client") String client, public List<EventRepresentation> getEvents(@QueryParam("type") List<String> types, @QueryParam("client") String client,
@QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo, @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
@QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult, @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) { @QueryParam("max") Integer maxResults) {
@ -454,8 +458,7 @@ public class RealmAdminResource {
query.client(client); query.client(client);
} }
List<String> types = uriInfo.getQueryParameters().get("type"); if (types != null & !types.isEmpty()) {
if (types != null) {
EventType[] t = new EventType[types.size()]; EventType[] t = new EventType[types.size()];
for (int i = 0; i < t.length; i++) { for (int i = 0; i < t.length; i++) {
t[i] = EventType.valueOf(types.get(i)); t[i] = EventType.valueOf(types.get(i));
@ -499,7 +502,15 @@ public class RealmAdminResource {
query.maxResults(maxResults); query.maxResults(maxResults);
} }
return query.getResultList(); return toEventListRep(query.getResultList());
}
private List<EventRepresentation> toEventListRep(List<Event> events) {
List<EventRepresentation> reps = new ArrayList<>();
for (Event event : events) {
reps.add(ModelToRepresentation.toRepresentation(event));
}
return reps;
} }
/** /**
@ -507,6 +518,7 @@ public class RealmAdminResource {
* *
* Returns all admin events, or filters events based on URL query parameters listed here * Returns all admin events, or filters events based on URL query parameters listed here
* *
* @param operationTypes
* @param authRealm * @param authRealm
* @param authClient * @param authClient
* @param authUser user id * @param authUser user id
@ -514,7 +526,6 @@ public class RealmAdminResource {
* @param resourcePath * @param resourcePath
* @param dateTo * @param dateTo
* @param dateFrom * @param dateFrom
* @param resourcePath
* @param firstResult * @param firstResult
* @param maxResults * @param maxResults
* @return * @return
@ -523,7 +534,7 @@ public class RealmAdminResource {
@GET @GET
@NoCache @NoCache
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<AdminEvent> getEvents(@QueryParam("authRealm") String authRealm, @QueryParam("authClient") String authClient, public List<AdminEventRepresentation> getEvents(@QueryParam("operationTypes") List<String> operationTypes, @QueryParam("authRealm") String authRealm, @QueryParam("authClient") String authClient,
@QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress, @QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress,
@QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom, @QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom,
@QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult, @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
@ -553,8 +564,7 @@ public class RealmAdminResource {
query.resourcePath(resourcePath); query.resourcePath(resourcePath);
} }
List<String> operationTypes = uriInfo.getQueryParameters().get("operationTypes"); if (operationTypes != null && !operationTypes.isEmpty()) {
if (operationTypes != null) {
OperationType[] t = new OperationType[operationTypes.size()]; OperationType[] t = new OperationType[operationTypes.size()];
for (int i = 0; i < t.length; i++) { for (int i = 0; i < t.length; i++) {
t[i] = OperationType.valueOf(operationTypes.get(i)); t[i] = OperationType.valueOf(operationTypes.get(i));
@ -591,7 +601,16 @@ public class RealmAdminResource {
query.maxResults(maxResults); query.maxResults(maxResults);
} }
return query.getResultList(); return toAdminEventRep(query.getResultList());
}
private List<AdminEventRepresentation> toAdminEventRep(List<AdminEvent> events) {
List<AdminEventRepresentation> reps = new ArrayList<>();
for (AdminEvent event : events) {
reps.add(ModelToRepresentation.toRepresentation(event));
}
return reps;
} }
/** /**

View file

@ -0,0 +1,55 @@
/*
* Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.keycloak.testsuite.event;
import org.junit.Before;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.testsuite.AbstractAuthTest;
/**
*
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
*/
public abstract class AbstractEventTest extends AbstractAuthTest {
protected RealmEventsConfigRepresentation configRep;
@Before
public void setConfigRep() {
RealmResource testRsc = testRealmResource();
configRep = testRsc.getRealmEventsConfig();
configRep.setAdminEventsDetailsEnabled(false);
configRep.setAdminEventsEnabled(false);
configRep.setEventsEnabled(false);
saveConfig();
}
protected void saveConfig() {
RealmResource testRsc = testRealmResource();
testRsc.updateRealmEventsConfig(configRep);
configRep = testRsc.getRealmEventsConfig();
}
protected void enableEvents() {
configRep.setEventsEnabled(true);
configRep.setAdminEventsEnabled(Boolean.TRUE);
saveConfig();
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.keycloak.testsuite.event;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.admin.ApiUtil;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Test getting and filtering admin events.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
*/
public class AdminEventTest extends AbstractEventTest {
@Before
public void initConfig() {
enableEvents();
testRealmResource().clearAdminEvents();
}
private List<AdminEventRepresentation> events() {
return testRealmResource().getAdminEvents();
}
private void createUser(String username) {
UserRepresentation user = createUserRepresentation(username, username + "@foo.com", "foo", "bar", true);
ApiUtil.createUserWithAdminClient(testRealmResource(), user);
}
private void updateRealm() {
RealmRepresentation realm = testRealmResource().toRepresentation();
realm.setDisplayName("Fury Road");
testRealmResource().update(realm);
}
private String realmName() {
return testRealmResource().toRepresentation().getId();
}
@Test
public void clearAdminEventsTest() {
createUser("user0");
assertEquals(1, events().size());
testRealmResource().clearAdminEvents();
assertEquals(Collections.EMPTY_LIST, events());
}
@Test
public void retrieveAdminEventTest() {
createUser("user1");
List<AdminEventRepresentation> events = events();
assertEquals(1, events.size());
AdminEventRepresentation event = events().get(0);
assertEquals("CREATE", event.getOperationType());
assertEquals(realmName(), event.getRealmId());
assertEquals(realmName(), event.getAuthDetails().getRealmId());
assertNull(event.getRepresentation());
}
@Test
public void testGetRepresentation() {
configRep.setAdminEventsDetailsEnabled(Boolean.TRUE);
saveConfig();
createUser("user2");
AdminEventRepresentation event = events().get(0);
assertNotNull(event.getRepresentation());
assertTrue(event.getRepresentation().contains("foo"));
}
@Test
public void testFilterAdminEvents() {
// two CREATE and one UPDATE
createUser("user3");
createUser("user4");
updateRealm();
assertEquals(3, events().size());
List<AdminEventRepresentation> events = testRealmResource().getAdminEvents(Arrays.asList("CREATE"), realmName(), null, null, null, null, null, null, null, null);
assertEquals(2, events.size());
}
}

View file

@ -0,0 +1,126 @@
/*
* Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.keycloak.testsuite.event;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Test updates to the events configuration.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
*/
public class EventConfigTest extends AbstractEventTest {
@Test
public void defaultEventConfigTest() {
assertFalse(configRep.isAdminEventsDetailsEnabled());
assertFalse(configRep.isAdminEventsEnabled());
assertFalse(configRep.isEventsEnabled());
List<String> eventListeners = configRep.getEventsListeners();
assertEquals(1, eventListeners.size());
assertEquals("jboss-logging", eventListeners.get(0));
}
@Test
public void enableEventsTest() {
enableEvents();
assertTrue(configRep.isEventsEnabled());
assertTrue(configRep.isAdminEventsEnabled());
}
@Test
public void addRemoveListenerTest() {
configRep.setEventsListeners(Collections.EMPTY_LIST);
saveConfig();
assertEquals(0, configRep.getEventsListeners().size());
configRep.setEventsListeners(Arrays.asList("email"));
saveConfig();
List<String> eventListeners = configRep.getEventsListeners();
assertEquals(1, eventListeners.size());
assertEquals("email", eventListeners.get(0));
}
@Test
public void loginEventSettingsTest() {
enableEvents();
assertTrue(hasEventType("LOGIN"));
assertTrue(hasEventType("LOGOUT"));
assertTrue(hasEventType("CLIENT_DELETE_ERROR"));
int defaultEventCount = configRep.getEnabledEventTypes().size();
configRep.setEnabledEventTypes(Arrays.asList("CLIENT_DELETE", "CLEINT_DELETE_ERROR"));
saveConfig();
List<String> enabledEventTypes = configRep.getEnabledEventTypes();
assertEquals(2, enabledEventTypes.size());
// remove all event types
configRep.setEnabledEventTypes(Collections.EMPTY_LIST);
saveConfig();
// removing all event types restores default events
assertEquals(defaultEventCount, configRep.getEnabledEventTypes().size());
}
private boolean hasEventType(String eventType) {
for (String event : configRep.getEnabledEventTypes()) {
if (eventType.equals(event)) return true;
}
return false;
}
@Test
public void includeRepresentationTest() {
enableEvents();
assertTrue(configRep.isAdminEventsEnabled());
assertFalse(configRep.isAdminEventsDetailsEnabled());
configRep.setAdminEventsDetailsEnabled(Boolean.TRUE);
saveConfig();
assertTrue(configRep.isAdminEventsDetailsEnabled());
}
@Test
public void setLoginEventExpirationTest() {
enableEvents();
assertNull(configRep.getEventsExpiration());
Long oneHour = 3600L;
configRep.setEventsExpiration(oneHour);
saveConfig();
assertEquals(oneHour, configRep.getEventsExpiration());
}
}

View file

@ -0,0 +1,120 @@
/*
* Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.keycloak.testsuite.event;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.testsuite.console.page.events.LoginEvents;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
/**
* Test getting and filtering login-related events.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
*/
public class LoginEventsTest extends AbstractEventTest {
@Page
private LoginEvents loginEventsPage;
@Before
public void init() {
configRep.setEventsEnabled(true);
configRep.setEnabledEventTypes(Collections.EMPTY_LIST); // resets to all types
saveConfig();
testRealmResource().clearEvents();
}
private List<EventRepresentation> events() {
return testRealmResource().getEvents();
}
private void badLogin() {
loginEventsPage.navigateTo();
loginPage.form().login("bad", "user");
}
private void pause(int seconds) {
try {
Thread.sleep(seconds * 1000L);
} catch (InterruptedException e) {
fail(e.getMessage());
}
}
@Test
public void clearEventsTest() {
assertEquals(0, events().size());
badLogin();
badLogin();
assertEquals(2, events().size());
testRealmResource().clearEvents();
assertEquals(0, events().size());
}
@Test
public void loggingOfCertainTypeTest() {
assertEquals(0, events().size());
configRep.setEnabledEventTypes(Arrays.asList("REVOKE_GRANT"));
saveConfig();
badLogin();
assertEquals(0, events().size());
configRep.setEnabledEventTypes(Arrays.asList("LOGIN_ERROR"));
saveConfig();
badLogin();
assertEquals(1, events().size());
}
@Test
public void filterTest() {
badLogin();
badLogin();
assertEquals(2, events().size());
List<EventRepresentation> filteredEvents = testRealmResource().getEvents(Arrays.asList("REVOKE_GRANT"), null, null, null, null, null, null, null);
assertEquals(0, filteredEvents.size());
filteredEvents = testRealmResource().getEvents(Arrays.asList("LOGIN_ERROR"), null, null, null, null, null, null, null);
assertEquals(2, filteredEvents.size());
}
/*
Removed this test because it takes too long. The default interval for
event cleanup is 15 minutes (900 seconds). I don't have time to figure out
a way to set the cleanup thread to a lower interval for testing.
@Test
public void eventExpirationTest() {
configRep.setEventsExpiration(1L); // second
saveConfig();
badLogin();
assertEquals(1, events().size());
pause(900); // pause 900 seconds
assertEquals(0, events().size());
}**/
}