keycloak-aplcache

Details

diff --git a/events/api/src/main/java/org/keycloak/events/EventQuery.java b/events/api/src/main/java/org/keycloak/events/EventQuery.java
index 00d9a4f..9a555ca 100644
--- a/events/api/src/main/java/org/keycloak/events/EventQuery.java
+++ b/events/api/src/main/java/org/keycloak/events/EventQuery.java
@@ -15,6 +15,10 @@ public interface EventQuery {
 
     public EventQuery user(String userId);
 
+    public EventQuery fromDate(String fromDate);
+
+    public EventQuery toDate(String toDate);
+
     public EventQuery ipAddress(String ipAddress);
 
     public EventQuery firstResult(int result);
diff --git a/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventQuery.java b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventQuery.java
index 4c7fbe5..5e39d17 100644
--- a/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventQuery.java
+++ b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventQuery.java
@@ -10,6 +10,9 @@ import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
@@ -65,6 +68,32 @@ public class JpaEventQuery implements EventQuery {
     }
 
     @Override
+    public EventQuery fromDate(String fromDate) {
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        Long from = null;
+        try {
+            from = df.parse(fromDate).getTime();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        predicates.add(cb.greaterThanOrEqualTo(root.<Long>get("time"), from));
+        return this;
+    }
+
+    @Override
+    public EventQuery toDate(String toDate) {
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        Long to = null;
+        try {
+            to = df.parse(toDate).getTime();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        predicates.add(cb.lessThanOrEqualTo(root.<Long>get("time"), to));
+        return this;
+    }
+    
+    @Override
     public EventQuery ipAddress(String ipAddress) {
         predicates.add(cb.equal(root.get("ipAddress"), ipAddress));
         return this;
diff --git a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventQuery.java b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventQuery.java
index fe08949..51d329b 100755
--- a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventQuery.java
+++ b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventQuery.java
@@ -1,12 +1,16 @@
 package org.keycloak.events.mongo;
 
 import com.mongodb.BasicDBObject;
+import com.mongodb.BasicDBObjectBuilder;
 import com.mongodb.DBCollection;
 import com.mongodb.DBCursor;
+
 import org.keycloak.events.Event;
 import org.keycloak.events.EventQuery;
 import org.keycloak.events.EventType;
 
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -54,6 +58,32 @@ public class MongoEventQuery implements EventQuery {
     }
 
     @Override
+    public EventQuery fromDate(String fromDate) {
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        Long from = null;
+        try {
+            from = df.parse(fromDate).getTime();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        query.put("time", BasicDBObjectBuilder.start("$gte", from).get());
+        return this;
+    }
+
+    @Override
+    public EventQuery toDate(String toDate) {
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        Long to = null;
+        try {
+            to = df.parse(toDate).getTime();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        query.put("time", BasicDBObjectBuilder.start("$lte", to).get());
+        return this;
+    }
+
+    @Override
     public EventQuery ipAddress(String ipAddress) {
         query.put("ipAddress", ipAddress);
         return this;
diff --git a/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventQuery.java b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventQuery.java
index 06038c7..e60b055 100644
--- a/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventQuery.java
+++ b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemEventQuery.java
@@ -4,6 +4,8 @@ import org.keycloak.events.Event;
 import org.keycloak.events.EventQuery;
 import org.keycloak.events.EventType;
 
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
@@ -73,7 +75,45 @@ public class MemEventQuery implements EventQuery {
         }
         return this;
     }
-
+    
+    @Override
+    public EventQuery fromDate(String fromDate) {
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        Long from = null;
+        try {
+            from = df.parse(fromDate).getTime();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        
+        Iterator<Event> itr = this.events.iterator();
+        while (itr.hasNext()) {
+            if (!(itr.next().getTime() >= from)) {
+                itr.remove();
+            }
+        }
+        return this;
+    }
+    
+    @Override
+    public EventQuery toDate(String toDate) {
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        Long to = null;
+        try {
+            to = df.parse(toDate).getTime();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        
+        Iterator<Event> itr = this.events.iterator();
+        while (itr.hasNext()) {
+            if (!(itr.next().getTime() <= to)) {
+                itr.remove();
+            }
+        }
+        return this;
+    }
+    
     @Override
     public EventQuery ipAddress(String ipAddress) {
         Iterator<Event> itr = this.events.iterator();
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
index 7c5090d..e132cb4 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
@@ -1154,7 +1154,12 @@ module.controller('RealmEventsConfigCtrl', function($scope, eventsConfig, RealmE
 module.controller('RealmEventsCtrl', function($scope, RealmEvents, realm) {
     $scope.realm = realm;
     $scope.page = 0;
-
+    
+    $scope.eventTypes = [{tag:'LOGIN'}, {tag:'REGISTER'}, {tag:'LOGOUT'}, {tag:'CODE_TO_TOKEN'}, {tag:'REFRESH_TOKEN'}, 
+                         {tag:'LOGIN_ERROR'}, {tag:'REGISTER_ERROR'}, {tag:'LOGOUT_ERROR'}, {tag:'CODE_TO_TOKEN_ERROR'}, {tag:'REFRESH_TOKEN_ERROR'},
+                         {tag:'VALIDATE_ACCESS_TOKEN'}, {tag:'VALIDATE_ACCESS_TOKEN_ERROR'}, {tag:'SOCIAL_LINK'}, {tag:'SOCIAL_LINK_ERROR'}, {tag:'REMOVE_FEDERATED_IDENTITY'},
+                         {tag:'REMOVE_SOCIAL_LINK_ERROR'}, {tag:'UPDATE_EMAIL'}, {tag:'UPDATE_PROFILE'}, {tag:'UPDATE_PASSWORD'}, {tag:'UPDATE_TOTP'}];
+    
     $scope.query = {
         id : realm.realm,
         max : 5,
@@ -1162,6 +1167,7 @@ module.controller('RealmEventsCtrl', function($scope, RealmEvents, realm) {
     }
 
     $scope.update = function() {
+    	$scope.query.first = 0;
         for (var i in $scope.query) {
             if ($scope.query[i] === '') {
                 delete $scope.query[i];
@@ -1169,13 +1175,31 @@ module.controller('RealmEventsCtrl', function($scope, RealmEvents, realm) {
         }
         $scope.events = RealmEvents.query($scope.query);
     }
-
+    
+    $scope.reset = function() {
+    	$scope.query.first = 0;
+    	$scope.query.max = 5;
+    	$scope.query.type = '';
+    	$scope.query.client = '';
+    	$scope.query.user = '';
+    	$scope.query.dateFrom = '';
+    	$scope.query.dateTo = '';
+    	
+    	$scope.update();
+    }
+    
+    $scope.queryUpdate = function() {
+        for (var i in $scope.query) {
+            if ($scope.query[i] === '') {
+                delete $scope.query[i];
+           }
+        }
+        $scope.events = RealmEvents.query($scope.query);
+    }
+    
     $scope.firstPage = function() {
         $scope.query.first = 0;
-        if ($scope.query.first < 0) {
-            $scope.query.first = 0;
-        }
-        $scope.update();
+        $scope.queryUpdate();
     }
 
     $scope.previousPage = function() {
@@ -1183,12 +1207,12 @@ module.controller('RealmEventsCtrl', function($scope, RealmEvents, realm) {
         if ($scope.query.first < 0) {
             $scope.query.first = 0;
         }
-        $scope.update();
+        $scope.queryUpdate();
     }
 
     $scope.nextPage = function() {
         $scope.query.first += parseInt($scope.query.max);
-        $scope.update();
+        $scope.queryUpdate();
     }
 
     $scope.update();
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-events.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-events.html
index 7a66013..e810717 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-events.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-events.html
@@ -27,14 +27,20 @@
                             Filter
                         </button>
                         <button class="btn btn-default btn-primary" data-ng-click="update()">Update</button>
+                        <button class="btn btn-default btn-primary" data-ng-click="reset()">Reset</button>
                     </div>
                     <form class="form-horizontal">
                         <div class="form-group" data-ng-show="filter">
-                            <label class="col-sm-2 control-label" for="type">Event Type</label>
-                            <div class="col-sm-4">
-                                <input class="form-control" type="text" id="type" name="event" data-ng-model="query.type">
-                            </div>
-                        </div>
+      			<label class="col-sm-2 control-label" for="eventType">Event Type</label>
+                    	    <div class="col-sm-5">
+                    	        <select style="width:230px" data-ui-select2 data-ng-model="query.type" data-placeholder="Select Event Type">
+				    <!-- empty option gets placeholder working -->
+				    <option value=""></option>
+				    <!-- ng-repeat to populate dynamic options -->
+				    <option data-ng-repeat="event in eventTypes">{{event.tag}}</option>
+				</select>
+			    </div>
+			</div>
                         <div class="form-group" data-ng-show="filter">
                             <label class="col-sm-2 control-label" for="client">Client</label>
                             <div class="col-sm-4">
@@ -47,6 +53,20 @@
                                 <input class="form-control" type="text" id="user" name="user" data-ng-model="query.user">
                             </div>
                         </div>
+                        
+                        <div class="form-group" data-ng-show="filter">
+                            <label class="col-sm-2 control-label" for="dateFrom">Date (From)</label>
+                            <div class="col-sm-4">
+                                <input class="form-control" type="date" id="dateFrom" name="dateFrom" data-ng-model="query.dateFrom">
+                            </div>
+                        </div>
+                        <div class="form-group" data-ng-show="filter">
+                            <label class="col-sm-2 control-label" for="toDate">Date (To)</label>
+                            <div class="col-sm-4">
+                                <input class="form-control" type="date" id="dateTo" name="dateTo" data-ng-model="query.dateTo">
+                            </div>
+                        </div>
+                        
                     </form>
                 </th>
             </tr>
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 5b807ca..bb6bedd 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -1,5 +1,24 @@
 package org.keycloak.services.resources.admin;
 
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
 import org.jboss.logging.Logger;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
@@ -12,7 +31,6 @@ import org.keycloak.exportimport.ApplicationImporter;
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserSessionModel;
@@ -20,12 +38,8 @@ import org.keycloak.models.cache.CacheRealmProvider;
 import org.keycloak.models.cache.CacheUserProvider;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.models.utils.RepresentationToModel;
-import org.keycloak.protocol.LoginProtocol;
-import org.keycloak.protocol.LoginProtocolFactory;
 import org.keycloak.protocol.oidc.TokenManager;
-import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.adapters.action.GlobalRequestResult;
-import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.services.managers.LDAPConnectionTestManager;
@@ -35,24 +49,6 @@ import org.keycloak.services.managers.UsersSyncManager;
 import org.keycloak.services.resources.flows.Flows;
 import org.keycloak.timer.TimerProvider;
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
 /**
  * Base resource class for the admin REST api of one realm
  *
@@ -397,8 +393,10 @@ public class RealmAdminResource {
     @GET
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
-    public List<Event> getEvents(@QueryParam("client") String client, @QueryParam("type") String type, @QueryParam("user") String user,
-                                 @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) {
+    public List<Event> getEvents(@QueryParam("client") String client, @QueryParam("type") String type,
+            @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
+            @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
+            @QueryParam("max") Integer maxResults) {
         auth.init(RealmAuth.Resource.EVENTS).requireView();
 
         EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
@@ -413,6 +411,14 @@ public class RealmAdminResource {
         if (user != null) {
             query.user(user);
         }
+        
+        if(dateFrom != null) {
+            query.fromDate(dateFrom);
+        }
+        if(dateTo != null) {
+            query.toDate(dateTo);
+        }
+
         if (ipAddress != null) {
             query.ipAddress(ipAddress);
         }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/events/EventStoreProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/events/EventStoreProviderTest.java
index e985421..f5f81ff 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/events/EventStoreProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/events/EventStoreProviderTest.java
@@ -11,6 +11,9 @@ import org.keycloak.events.EventType;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.testsuite.rule.KeycloakRule;
 
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -70,8 +73,76 @@ public class EventStoreProviderTest {
 
         Assert.assertEquals(newest, eventStore.createQuery().maxResults(1).getResultList().get(0).getTime());
         Assert.assertEquals(oldest, eventStore.createQuery().firstResult(5).maxResults(1).getResultList().get(0).getTime());
+        
+        eventStore.clear("realmId");
+        eventStore.clear("realmId2");
+        
+        Assert.assertEquals(0, eventStore.createQuery().getResultList().size());
+        
+        String d1 = new String("2015-03-04");
+        String d2 = new String("2015-03-05");
+        String d3 = new String("2015-03-06");
+        String d4 = new String("2015-03-07");
+        
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+        Date date1 = null, date2 = null, date3 = null, date4 = null;
+        
+        try {
+            date1 = formatter.parse(d1);
+            date2 = formatter.parse(d2);
+            date3 = formatter.parse(d3);
+            date4 = formatter.parse(d4);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        
+        eventStore.onEvent(create(date1, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        eventStore.onEvent(create(date1, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        eventStore.onEvent(create(date2, EventType.REGISTER, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        eventStore.onEvent(create(date2, EventType.REGISTER, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        eventStore.onEvent(create(date3, EventType.CODE_TO_TOKEN, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
+        eventStore.onEvent(create(date3, EventType.LOGOUT, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
+        eventStore.onEvent(create(date4, EventType.UPDATE_PROFILE, "realmId2", "clientId2", "userId2", "127.0.0.1", "error"));
+        eventStore.onEvent(create(date4, EventType.UPDATE_EMAIL, "realmId2", "clientId2", "userId2", "127.0.0.1", "error"));
+        
+        resetSession();
+        
+        Assert.assertEquals(6, eventStore.createQuery().client("clientId").getResultList().size());
+        Assert.assertEquals(2, eventStore.createQuery().client("clientId2").getResultList().size());
+        
+        Assert.assertEquals(6, eventStore.createQuery().realm("realmId").getResultList().size());
+        Assert.assertEquals(2, eventStore.createQuery().realm("realmId2").getResultList().size());
+        
+        Assert.assertEquals(4, eventStore.createQuery().user("userId").getResultList().size());
+        Assert.assertEquals(4, eventStore.createQuery().user("userId2").getResultList().size());
+        
+        Assert.assertEquals(2, eventStore.createQuery().type(EventType.LOGIN).getResultList().size());
+        Assert.assertEquals(2, eventStore.createQuery().type(EventType.REGISTER).getResultList().size());
+        Assert.assertEquals(4, eventStore.createQuery().type(EventType.LOGIN, EventType.REGISTER).getResultList().size());
+        Assert.assertEquals(1, eventStore.createQuery().type(EventType.CODE_TO_TOKEN).getResultList().size());
+        Assert.assertEquals(1, eventStore.createQuery().type(EventType.LOGOUT).getResultList().size());
+        Assert.assertEquals(1, eventStore.createQuery().type(EventType.UPDATE_PROFILE).getResultList().size());
+        Assert.assertEquals(1, eventStore.createQuery().type(EventType.UPDATE_EMAIL).getResultList().size());
+        
+        Assert.assertEquals(8, eventStore.createQuery().fromDate("2015-03-04").getResultList().size());
+        Assert.assertEquals(8, eventStore.createQuery().toDate("2015-03-07").getResultList().size());
+        
+        Assert.assertEquals(4, eventStore.createQuery().fromDate("2015-03-06").getResultList().size());
+        Assert.assertEquals(4, eventStore.createQuery().toDate("2015-03-05").getResultList().size());
+        
+        Assert.assertEquals(0, eventStore.createQuery().fromDate("2015-03-08").getResultList().size());
+        Assert.assertEquals(0, eventStore.createQuery().toDate("2015-03-03").getResultList().size());
+        
+        Assert.assertEquals(8, eventStore.createQuery().fromDate("2015-03-04").toDate("2015-03-07").getResultList().size());
+        Assert.assertEquals(6, eventStore.createQuery().fromDate("2015-03-05").toDate("2015-03-07").getResultList().size());
+        Assert.assertEquals(4, eventStore.createQuery().fromDate("2015-03-04").toDate("2015-03-05").getResultList().size());
+        Assert.assertEquals(4, eventStore.createQuery().fromDate("2015-03-06").toDate("2015-03-07").getResultList().size());
+        
+        Assert.assertEquals(0, eventStore.createQuery().fromDate("2015-03-01").toDate("2015-03-03").getResultList().size());
+        Assert.assertEquals(0, eventStore.createQuery().fromDate("2015-03-08").toDate("2015-03-10").getResultList().size());
+        
     }
-
+    
     @Test
     public void clear() {
         eventStore.onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
@@ -105,6 +176,10 @@ public class EventStoreProviderTest {
     private Event create(EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
         return create(System.currentTimeMillis(), event, realmId, clientId, userId, ipAddress, error);
     }
+    
+    private Event create(Date date, EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
+        return create(date.getTime(), event, realmId, clientId, userId, ipAddress, error);
+    }
 
     private Event create(long time, EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
         Event e = new Event();