From 962b623b4a8990011c8dcf5cc22fc859f99e06c7 Mon Sep 17 00:00:00 2001 From: girirajsharma Date: Mon, 30 Mar 2015 03:17:19 +0530 Subject: [PATCH] [KEYCLOAK-392] - Admin audit events --- .../META-INF/jpa-changelog-1.0.0.Final.xml | 8 +++ .../idm/RealmEventsConfigRepresentation.java | 9 +++ .../idm/RealmRepresentation.java | 9 +++ .../java/org/keycloak/events/Details.java | 19 ++++++ .../main/java/org/keycloak/events/Event.java | 11 ++++ .../org/keycloak/events/EventBuilder.java | 44 ++++++++++--- .../java/org/keycloak/events/EventGroup.java | 12 ++++ .../java/org/keycloak/events/EventType.java | 62 +++++++++++++++++++ .../org/keycloak/events/jpa/EventEntity.java | 11 ++++ .../events/jpa/JpaEventStoreProvider.java | 4 ++ .../events/mongo/MongoEventStoreProvider.java | 4 ++ .../admin/resources/js/controllers/realm.js | 29 +++++++-- .../partials/realm-events-config.html | 13 ++++ .../resources/partials/realm-events.html | 2 +- .../java/org/keycloak/models/RealmModel.java | 4 ++ .../keycloak/models/entities/RealmEntity.java | 9 +++ .../models/utils/ModelToRepresentation.java | 8 +++ .../models/utils/RepresentationToModel.java | 1 + .../models/file/adapter/RealmAdapter.java | 15 +++++ .../keycloak/models/cache/RealmAdapter.java | 12 ++++ .../models/cache/entities/CachedRealm.java | 6 ++ .../org/keycloak/models/jpa/RealmAdapter.java | 12 ++++ .../models/jpa/entities/RealmEntity.java | 13 ++++ .../mongo/keycloak/adapters/RealmAdapter.java | 16 +++++ .../protocol/oidc/OIDCLoginProtocol.java | 3 +- .../oidc/OIDCLoginProtocolService.java | 18 +----- .../oidc/endpoints/AuthorizationEndpoint.java | 4 +- .../oidc/endpoints/LogoutEndpoint.java | 3 +- .../oidc/endpoints/TokenEndpoint.java | 4 +- .../oidc/endpoints/UserInfoEndpoint.java | 3 + .../oidc/endpoints/ValidateTokenEndpoint.java | 4 +- .../managers/AuthenticationManager.java | 4 +- .../services/managers/EventsManager.java | 10 ++- .../services/managers/RealmManager.java | 4 ++ .../services/resources/AccountService.java | 4 +- .../resources/IdentityBrokerService.java | 4 +- .../resources/LoginActionsService.java | 4 +- .../services/resources/RealmsResource.java | 4 ++ .../resources/admin/AdminConsole.java | 31 +++++++--- .../services/resources/admin/AdminRoot.java | 22 ++++--- .../resources/admin/ApplicationResource.java | 38 ++++++++++-- .../admin/ApplicationsByIdResource.java | 5 +- .../resources/admin/ApplicationsResource.java | 20 ++++-- .../ClientAttributeCertificateResource.java | 23 ++++++- .../admin/IdentityProviderResource.java | 28 ++++++++- .../admin/IdentityProvidersResource.java | 47 +++++++++++--- .../resources/admin/OAuthClientResource.java | 20 ++++-- .../admin/OAuthClientsByIdResource.java | 27 +------- .../resources/admin/OAuthClientsResource.java | 21 +++++-- .../resources/admin/RealmAdminResource.java | 40 +++++++----- .../resources/admin/RealmsAdminResource.java | 22 +++++-- .../resources/admin/RoleByIdResource.java | 34 +++++++++- .../admin/RoleContainerResource.java | 34 +++++++++- .../admin/ServerInfoAdminResource.java | 18 +++++- .../admin/UserFederationResource.java | 45 ++++++++++++-- .../resources/admin/UsersResource.java | 58 +++++++++++++++-- .../events/EventStoreProviderTest.java | 2 + 57 files changed, 797 insertions(+), 144 deletions(-) create mode 100644 events/api/src/main/java/org/keycloak/events/EventGroup.java diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.0.0.Final.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.0.0.Final.xml index edc976ef1c..1700e39bb5 100644 --- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.0.0.Final.xml +++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.0.0.Final.xml @@ -92,6 +92,7 @@ + @@ -196,6 +197,12 @@ + + + + + + @@ -405,6 +412,7 @@ + diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmEventsConfigRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmEventsConfigRepresentation.java index acadc95246..a88a75d93d 100755 --- a/core/src/main/java/org/keycloak/representations/idm/RealmEventsConfigRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/RealmEventsConfigRepresentation.java @@ -10,6 +10,7 @@ public class RealmEventsConfigRepresentation { protected boolean eventsEnabled; protected Long eventsExpiration; protected List eventsListeners; + protected List enabledEventTypes; public boolean isEventsEnabled() { return eventsEnabled; @@ -34,4 +35,12 @@ public class RealmEventsConfigRepresentation { public void setEventsListeners(List eventsListeners) { this.eventsListeners = eventsListeners; } + + public List getEnabledEventTypes() { + return enabledEventTypes; + } + + public void setEnabledEventTypes(List enabledEventTypes) { + this.enabledEventTypes = enabledEventTypes; + } } diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java index 8a4727b441..b350e3825a 100755 --- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java @@ -68,6 +68,7 @@ public class RealmRepresentation { protected Boolean eventsEnabled; protected Long eventsExpiration; protected List eventsListeners; + protected List enabledEventTypes; private List identityProviders; private List protocolMappers; private Boolean identityFederationEnabled; @@ -503,6 +504,14 @@ public class RealmRepresentation { public void setEventsListeners(List eventsListeners) { this.eventsListeners = eventsListeners; } + + public List getEnabledEventTypes() { + return enabledEventTypes; + } + + public void setEnabledEventTypes(List enabledEventTypes) { + this.enabledEventTypes = enabledEventTypes; + } public List getUserFederationProviders() { return userFederationProviders; diff --git a/events/api/src/main/java/org/keycloak/events/Details.java b/events/api/src/main/java/org/keycloak/events/Details.java index d24390c242..75c71ff722 100755 --- a/events/api/src/main/java/org/keycloak/events/Details.java +++ b/events/api/src/main/java/org/keycloak/events/Details.java @@ -14,6 +14,9 @@ public interface Details { String AUTH_METHOD = "auth_method"; String IDENTITY_PROVIDER = "identity_provider"; String IDENTITY_PROVIDER_IDENTITY = "identity_provider_identity"; + String IDENTITY_PROVIDER_ALIAS = "identity_provider_alias"; + String IDENTITY_PROVIDER_FACTORY = "identity_provider_factory"; + String IDENTITY_PROVIDER_FACTORY_IDENTITY = "identity_provider_factory_identity"; String REGISTER_METHOD = "register_method"; String USERNAME = "username"; String REMEMBER_ME = "remember_me"; @@ -23,4 +26,20 @@ public interface Details { String UPDATED_REFRESH_TOKEN_ID = "updated_refresh_token_id"; String NODE_HOST = "node_host"; String REASON = "reason"; + + String REALM_ID = "realm_id"; + String REALM_NAME = "realm_name"; + String REALM_REQUIRED_SSL = "realm_required_ssl"; + + String APPLICATION_CLUSTER_NODE = "application_cluster_node"; + + String ROLE_ID = "role_id"; + String ROLE_NAME = "role_name"; + + String PROVIDER_ID = "provider_id"; + String PROVIDER_NAME = "provider_name"; + + String SERVER_VERSION = "server_version"; + String SERVER_TIME = "server_time"; + } diff --git a/events/api/src/main/java/org/keycloak/events/Event.java b/events/api/src/main/java/org/keycloak/events/Event.java index 0099e8305b..cebd418305 100644 --- a/events/api/src/main/java/org/keycloak/events/Event.java +++ b/events/api/src/main/java/org/keycloak/events/Event.java @@ -11,6 +11,8 @@ public class Event { private long time; private EventType type; + + private EventGroup eventGroup; private String realmId; @@ -41,6 +43,14 @@ public class Event { public void setType(EventType type) { this.type = type; } + + public EventGroup getEventGroup() { + return eventGroup; + } + + public void setEventGroup(EventGroup group) { + this.eventGroup = group; + } public String getRealmId() { return realmId; @@ -102,6 +112,7 @@ public class Event { Event clone = new Event(); clone.time = time; clone.type = type; + clone.eventGroup = eventGroup; clone.realmId = realmId; clone.clientId = clientId; clone.userId = userId; diff --git a/events/api/src/main/java/org/keycloak/events/EventBuilder.java b/events/api/src/main/java/org/keycloak/events/EventBuilder.java index 8ab685777e..0ad60acb12 100644 --- a/events/api/src/main/java/org/keycloak/events/EventBuilder.java +++ b/events/api/src/main/java/org/keycloak/events/EventBuilder.java @@ -1,26 +1,40 @@ package org.keycloak.events; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import org.jboss.logging.Logger; import org.keycloak.models.ClientModel; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; -import java.util.HashMap; -import java.util.List; - /** * @author Stian Thorgersen */ public class EventBuilder { private static final Logger log = Logger.getLogger(EventBuilder.class); - - private List listeners; + + // These events are excluded by default and not persisted. + private EventType[] events = {EventType.VIEW_REALM, + EventType.VIEW_REALM_APPLICATIONS, EventType.VIEW_APPLICATION, EventType.VIEW_APPLICATION_USER_SESSIONS, + EventType.VIEW_IDENTITY_PROVIDER, EventType.VIEW_IDENTITY_PROVIDERS, EventType.VIEW_OAUTH_CLIENT, + EventType.VIEW_OAUTH_CLIENTS, EventType.VIEW_PROVIDER, EventType.VIEW_PROVIDER_FACTORIES, EventType.VIEW_USER, + EventType.VIEW_USER_SESSIONS, EventType.VIEW_USER_SOCIAL_LOGINS, EventType.VIEW_ROLE, EventType.VIEW_ROLES, + EventType.VIEW_CLIENT_CERTIFICATE, EventType.VIEW_SERVER_INFO }; + private Event event; + private List listeners; + private Set enabledEventTypes; + private Set excludedEvents = new HashSet(Arrays.asList(events));; - public EventBuilder(List listeners, RealmModel realm, String ipAddress) { + public EventBuilder(List listeners, Set enabledEventTypes, RealmModel realm, String ipAddress) { this.listeners = listeners; + this.enabledEventTypes = enabledEventTypes; this.event = new Event(); realm(realm); @@ -80,6 +94,11 @@ public class EventBuilder { return this; } + public EventBuilder eventGroup(EventGroup e) { + event.setEventGroup(e); + return this; + } + public EventBuilder detail(String key, String value) { if (value == null || value.equals("")) { return this; @@ -88,7 +107,10 @@ public class EventBuilder { if (event.getDetails() == null) { event.setDetails(new HashMap()); } - event.getDetails().put(key, value); + + if (value != null && !value.isEmpty()) { + event.getDetails().put(key, value); + } return this; } @@ -138,7 +160,13 @@ public class EventBuilder { if (listeners != null) { for (EventListenerProvider l : listeners) { try { - l.onEvent(event); + if (enabledEventTypes != null && enabledEventTypes.size() > 0) { + if (enabledEventTypes.contains(event.getType())) { + l.onEvent(event); + } + } else if (!excludedEvents.contains(event.getType())) { + l.onEvent(event); + } } catch (Throwable t) { log.error("Failed to send type to " + l, t); } diff --git a/events/api/src/main/java/org/keycloak/events/EventGroup.java b/events/api/src/main/java/org/keycloak/events/EventGroup.java new file mode 100644 index 0000000000..fccdb27921 --- /dev/null +++ b/events/api/src/main/java/org/keycloak/events/EventGroup.java @@ -0,0 +1,12 @@ +package org.keycloak.events; + +/** + * @author Giriraj Sharma + */ +public enum EventGroup { + + ADMIN, + USER, + EMAIL, + +} diff --git a/events/api/src/main/java/org/keycloak/events/EventType.java b/events/api/src/main/java/org/keycloak/events/EventType.java index d66660d93e..3a0dc5eef5 100755 --- a/events/api/src/main/java/org/keycloak/events/EventType.java +++ b/events/api/src/main/java/org/keycloak/events/EventType.java @@ -58,4 +58,66 @@ public enum EventType { IDENTITY_PROVIDER_RETRIEVE_TOKEN_ERROR, IDENTITY_PROVIDER_ACCCOUNT_LINKING, IDENTITY_PROVIDER_ACCCOUNT_LINKING_ERROR, + + VIEW_REALM, + UPDATE_REALM, + DELETE_REALM, + IMPORT_REALM, + UPLOAD_REALM, + VIEW_REALM_APPLICATIONS, + SET_REALM_USER_PERMISSIONS, + SET_REALM_ADAPTER_CONFIGURATION, + + CREATE_APPLICATION, + UPDATE_APPLICATION, + VIEW_APPLICATION, + DELETE_APPLICATION, + + VIEW_APPLICATION_USER_SESSIONS, + INVALIDATE_APPLICATION_USER_SESSIONS, + INVALIDATE_APPLICATION_USER_SESSION, + REGISTER_APPLICATION_CLUSTER_NODE, + UNREGISTER_APPLICATION_CLUSTER_NODE, + + VIEW_CLIENT_CERTIFICATE, + GENERATE_CLIENT_CERTIFICATE, + UPLOAD_CLIENT_CERTIFICATE, + DOWNLOAD_CLIENT_CERTIFICATE, + + VIEW_IDENTITY_PROVIDER, + VIEW_IDENTITY_PROVIDERS, + IMPORT_IDENTITY_PROVIDER_CONFIG, + CREATE_IDENTITY_PROVIDER, + UPDATE_IDENTITY_PROVIDER, + DELETE_IDENTITY_PROVIDER, + + CREATE_OAUTH_CLIENT, + UPDATE_OAUTH_CLIENT, + VIEW_OAUTH_CLIENT, + VIEW_OAUTH_CLIENTS, + DELETE_OAUTH_CLIENT, + + VIEW_ROLE, + VIEW_ROLES, + CREATE_ROLE, + UPDATE_ROLE, + DELETE_ROLE, + MAKE_ROLE_COMPOSITE, + + UPDATE_USER, + CREATE_USER, + VIEW_USER, + DELETE_USER, + VIEW_USER_SESSIONS, + VIEW_USER_SOCIAL_LOGINS, + INVALIDATE_USER_SESSIONS, + + CREATE_PROVIDER, + VIEW_PROVIDER, + VIEW_PROVIDER_FACTORIES, + UPDATE_PROVIDER, + DELETE_PROVIDER, + + VIEW_SERVER_INFO, + } diff --git a/events/jpa/src/main/java/org/keycloak/events/jpa/EventEntity.java b/events/jpa/src/main/java/org/keycloak/events/jpa/EventEntity.java index 4a68bb3420..9f0aec251f 100644 --- a/events/jpa/src/main/java/org/keycloak/events/jpa/EventEntity.java +++ b/events/jpa/src/main/java/org/keycloak/events/jpa/EventEntity.java @@ -21,6 +21,9 @@ public class EventEntity { @Column(name="TYPE") private String type; + + @Column(name="EVENT_GROUP") + private String eventGroup; @Column(name="REALM_ID") private String realmId; @@ -67,6 +70,14 @@ public class EventEntity { this.type = type; } + public String getEventGroup() { + return eventGroup; + } + + public void setEventGroup(String eventGroup) { + this.eventGroup = eventGroup; + } + public String getRealmId() { return realmId; } diff --git a/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java index 40b3840055..c604426adb 100755 --- a/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java +++ b/events/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java @@ -4,12 +4,14 @@ import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; import org.jboss.logging.Logger; import org.keycloak.events.Event; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventQuery; import org.keycloak.events.EventStoreProvider; import org.keycloak.events.EventType; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; + import java.io.IOException; import java.util.Map; import java.util.Set; @@ -70,6 +72,7 @@ public class JpaEventStoreProvider implements EventStoreProvider { e.setId(UUID.randomUUID().toString()); e.setTime(o.getTime()); e.setType(o.getType().toString()); + e.setEventGroup(o.getEventGroup().toString()); e.setRealmId(o.getRealmId()); e.setClientId(o.getClientId()); e.setUserId(o.getUserId()); @@ -88,6 +91,7 @@ public class JpaEventStoreProvider implements EventStoreProvider { Event e = new Event(); e.setTime(o.getTime()); e.setType(EventType.valueOf(o.getType())); + e.setEventGroup(EventGroup.valueOf(o.getEventGroup())); e.setRealmId(o.getRealmId()); e.setClientId(o.getClientId()); e.setUserId(o.getUserId()); diff --git a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java index 368ef20331..81181893ce 100755 --- a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java +++ b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java @@ -3,7 +3,9 @@ package org.keycloak.events.mongo; import com.mongodb.BasicDBObject; import com.mongodb.DBCollection; import com.mongodb.DBObject; + import org.keycloak.events.Event; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventQuery; import org.keycloak.events.EventStoreProvider; import org.keycloak.events.EventType; @@ -63,6 +65,7 @@ public class MongoEventStoreProvider implements EventStoreProvider { BasicDBObject e = new BasicDBObject(); e.put("time", o.getTime()); e.put("type", o.getType().toString()); + e.put("group", o.getEventGroup().toString()); e.put("realmId", o.getRealmId()); e.put("clientId", o.getClientId()); e.put("userId", o.getUserId()); @@ -85,6 +88,7 @@ public class MongoEventStoreProvider implements EventStoreProvider { Event e = new Event(); e.setTime(o.getLong("time")); e.setType(EventType.valueOf(o.getString("type"))); + e.setEventGroup(EventGroup.valueOf(o.getString("group"))); e.setRealmId(o.getString("realmId")); e.setClientId(o.getString("clientId")); e.setUserId(o.getString("userId")); diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js index 656ce931f9..3aa8fb1ed7 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js @@ -1238,6 +1238,19 @@ module.controller('RealmEventsConfigCtrl', function($scope, eventsConfig, RealmE }); $scope.eventListeners = serverInfo.eventListeners; + + // Admin can choose any number of these eventTypes for persistence. + // By default, admin view events are not persisted. + $scope.enabledEventTypes = [{tag:'LOGIN'}, {tag:'REGISTER'}, {tag:'LOGOUT'}, {tag:'CODE_TO_TOKEN'}, + {tag:'REFRESH_TOKEN'}, {tag:'VALIDATE_ACCESS_TOKEN'}, {tag:'LOGIN_ERROR'}, {tag:'REGISTER_ERROR'}, + {tag:'LOGOUT_ERROR'}, {tag:'CODE_TO_TOKEN_ERROR'}, {tag:'REFRESH_TOKEN_ERROR'}, {tag:'VALIDATE_ACCESS_TOKEN_ERROR'}, + {tag:'UPDATE_EMAIL'}, {tag:'UPDATE_PROFILE'}, {tag:'UPDATE_PASSWORD'}, {tag:'UPDATE_TOTP'}, + {tag:'UPLOAD_REALM'}, {tag:'IMPORT_REALM'}, {tag:'UPDATE_REALM'}, {tag:'DELETE_REALM'}, + {tag:'CREATE_USER'}, {tag:'UPDATE_USER'}, {tag:'DELETE_USER'}, {tag:'VIEW_USER_SESSIONS'}, + {tag:'CREATE_APPLICATION'}, {tag:'UPDATE_APPLICATION'}, {tag:'DELETE_APPLICATION'}, {tag:'VIEW_APPLICATION'}, + {tag:'CREATE_OAUTH_CLIENT'}, {tag:'UPDATE_OAUTH_CLIENT'}, {tag:'VIEW_OAUTH_CLIENT'}, {tag:'DELETE_OAUTH_CLIENT'}, + {tag:'CREATE_PROVIDER'}, {tag:'UPDATE_PROVIDER'}, {tag:'DELETE_PROVIDER'}, {tag:'VIEW_ROLE'}, + {tag:'CREATE_ROLE'}, {tag:'UPDATE_ROLE'}, {tag:'DELETE_ROLE'}, {tag:'VIEW_SERVER_INFO'}] var oldCopy = angular.copy($scope.eventsConfig); $scope.changed = false; @@ -1282,10 +1295,18 @@ 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'}]; + // Admin can filter events view by selecting any one or multiple of these events. + $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'}, + {tag:'UPLOAD_REALM'}, {tag:'IMPORT_REALM'}, {tag:'UPDATE_REALM'}, {tag:'DELETE_REALM'}, + {tag:'CREATE_USER'}, {tag:'UPDATE_USER'}, {tag:'DELETE_USER'}, {tag:'VIEW_USER_SESSIONS'}, + {tag:'CREATE_APPLICATION'}, {tag:'UPDATE_APPLICATION'}, {tag:'DELETE_APPLICATION'}, {tag:'VIEW_APPLICATION'}, + {tag:'CREATE_OAUTH_CLIENT'}, {tag:'UPDATE_OAUTH_CLIENT'}, {tag:'VIEW_OAUTH_CLIENT'}, {tag:'DELETE_OAUTH_CLIENT'}, + {tag:'CREATE_PROVIDER'}, {tag:'UPDATE_PROVIDER'}, {tag:'DELETE_PROVIDER'}, {tag:'VIEW_ROLE'}, + {tag:'CREATE_ROLE'}, {tag:'UPDATE_ROLE'}, {tag:'DELETE_ROLE'}, {tag:'VIEW_SERVER_INFO'}]; $scope.query = { id : realm.realm, diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-config.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-config.html index 9ce707be65..38d586454a 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-config.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events-config.html @@ -52,6 +52,19 @@ + +
+ + +
+ +
+ + +
+
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events.html index 27843f3926..b7437523ed 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-events.html @@ -34,7 +34,7 @@
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java index f74d54c0ba..f0c5ebfbd9 100755 --- a/model/api/src/main/java/org/keycloak/models/RealmModel.java +++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java @@ -236,6 +236,10 @@ public interface RealmModel extends RoleContainerModel { Set getEventsListeners(); void setEventsListeners(Set listeners); + + Set getEnabledEventTypes(); + + void setEnabledEventTypes(Set enabledEventTypes); ApplicationModel getMasterAdminApp(); diff --git a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java index 678fb3326a..50d2892c9e 100755 --- a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java +++ b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java @@ -62,6 +62,7 @@ public class RealmEntity extends AbstractIdentifiableEntity { private boolean eventsEnabled; private long eventsExpiration; private List eventsListeners = new ArrayList(); + private List enabledEventTypes = new ArrayList(); private String adminAppId; @@ -380,6 +381,14 @@ public class RealmEntity extends AbstractIdentifiableEntity { this.eventsListeners = eventsListeners; } + public List getEnabledEventTypes() { + return enabledEventTypes; + } + + public void setEnabledEventTypes(List enabledEventTypes) { + this.enabledEventTypes = enabledEventTypes; + } + public String getAdminAppId() { return adminAppId; } diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index 1ff0b01ede..78a64ca99a 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -116,6 +116,9 @@ public class ModelToRepresentation { if (realm.getEventsListeners() != null) { rep.setEventsListeners(new LinkedList(realm.getEventsListeners())); } + if (realm.getEnabledEventTypes() != null) { + rep.setEnabledEventTypes(new LinkedList(realm.getEnabledEventTypes())); + } rep.setVerifyEmail(realm.isVerifyEmail()); rep.setResetPasswordAllowed(realm.isResetPasswordAllowed()); @@ -182,6 +185,11 @@ public class ModelToRepresentation { if (realm.getEventsListeners() != null) { rep.setEventsListeners(new LinkedList(realm.getEventsListeners())); } + + if(realm.getEnabledEventTypes() != null) { + rep.setEnabledEventTypes(new LinkedList(realm.getEnabledEventTypes())); + } + return rep; } diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index 85e724c90d..41e97c8e8d 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -357,6 +357,7 @@ public class RepresentationToModel { if (rep.isEventsEnabled() != null) realm.setEventsEnabled(rep.isEventsEnabled()); if (rep.getEventsExpiration() != null) realm.setEventsExpiration(rep.getEventsExpiration()); if (rep.getEventsListeners() != null) realm.setEventsListeners(new HashSet(rep.getEventsListeners())); + if (rep.getEnabledEventTypes() != null) realm.setEnabledEventTypes(new HashSet(rep.getEnabledEventTypes())); if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy())); diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java index 5894784da2..975bf2924f 100755 --- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java +++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java @@ -46,6 +46,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; + import org.keycloak.connections.file.InMemoryModel; import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.UserModel; @@ -1038,6 +1039,20 @@ public class RealmAdapter implements RealmModel { realm.setEventsListeners(Collections.EMPTY_LIST); } } + + @Override + public Set getEnabledEventTypes() { + return new HashSet(realm.getEnabledEventTypes()); + } + + @Override + public void setEnabledEventTypes(Set enabledEventTypes) { + if (enabledEventTypes != null) { + realm.setEnabledEventTypes(new ArrayList(enabledEventTypes)); + } else { + realm.setEnabledEventTypes(Collections.EMPTY_LIST); + } + } @Override public ApplicationModel getMasterAdminApp() { diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java index 16c1d34d05..0cafa72535 100755 --- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java @@ -806,6 +806,18 @@ public class RealmAdapter implements RealmModel { updated.setEventsListeners(listeners); } + @Override + public Set getEnabledEventTypes() { + if (updated != null) return updated.getEnabledEventTypes(); + return cached.getEnabledEventTypes(); + } + + @Override + public void setEnabledEventTypes(Set enabledEventTypes) { + getDelegateForUpdate(); + updated.setEnabledEventTypes(enabledEventTypes); + } + @Override public ApplicationModel getMasterAdminApp() { return cacheSession.getRealm(Config.getAdminRealm()).getApplicationById(cached.getMasterAdminApp()); diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java index a4ce5bb653..5bbe90565b 100755 --- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java @@ -79,6 +79,7 @@ public class CachedRealm { private boolean eventsEnabled; private long eventsExpiration; private Set eventsListeners = new HashSet(); + private Set enabledEventTypes = new HashSet(); private List defaultRoles = new LinkedList(); private Map realmRoles = new HashMap(); private Map applications = new HashMap(); @@ -146,6 +147,7 @@ public class CachedRealm { eventsEnabled = model.isEventsEnabled(); eventsExpiration = model.getEventsExpiration(); eventsListeners.addAll(model.getEventsListeners()); + enabledEventTypes.addAll(model.getEnabledEventTypes()); defaultRoles.addAll(model.getDefaultRoles()); masterAdminApp = model.getMasterAdminApp().getId(); @@ -348,6 +350,10 @@ public class CachedRealm { public Set getEventsListeners() { return eventsListeners; } + + public Set getEnabledEventTypes() { + return enabledEventTypes; + } public List getUserFederationProviders() { return userFederationProviders; diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index 132b949286..9a0111994f 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -23,6 +23,7 @@ import org.keycloak.models.utils.KeycloakModelUtils; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; + import java.security.Key; import java.security.PrivateKey; import java.security.PublicKey; @@ -1139,6 +1140,17 @@ public class RealmAdapter implements RealmModel { realm.setEventsListeners(listeners); em.flush(); } + + @Override + public Set getEnabledEventTypes() { + return realm.getEnabledEventTypes(); + } + + @Override + public void setEnabledEventTypes(Set enabledEventTypes) { + realm.setEnabledEventTypes(enabledEventTypes); + em.flush(); + } @Override public ApplicationModel getMasterAdminApp() { diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java index 9fbf077855..b2a851ab1e 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java @@ -129,6 +129,11 @@ public class RealmEntity { @Column(name="VALUE") @CollectionTable(name="REALM_EVENTS_LISTENERS", joinColumns={ @JoinColumn(name="REALM_ID") }) protected Set eventsListeners = new HashSet(); + + @ElementCollection + @Column(name="VALUE") + @CollectionTable(name="REALM_ENABLED_EVENT_TYPES", joinColumns={ @JoinColumn(name="REALM_ID") }) + protected Set enabledEventTypes = new HashSet(); @OneToOne @JoinColumn(name="MASTER_ADMIN_APP") @@ -418,7 +423,15 @@ public class RealmEntity { public void setEventsListeners(Set eventsListeners) { this.eventsListeners = eventsListeners; } + + public Set getEnabledEventTypes() { + return enabledEventTypes; + } + public void setEnabledEventTypes(Set enabledEventTypes) { + this.enabledEventTypes = enabledEventTypes; + } + public ApplicationEntity getMasterAdminApp() { return masterAdminApp; } diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java index ba0c8d7b43..12f9e7724e 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java @@ -2,6 +2,7 @@ package org.keycloak.models.mongo.keycloak.adapters; import com.mongodb.DBObject; import com.mongodb.QueryBuilder; + import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext; import org.keycloak.enums.SslRequired; import org.keycloak.models.ApplicationModel; @@ -1045,6 +1046,21 @@ public class RealmAdapter extends AbstractMongoAdapter impleme updateRealm(); } + @Override + public Set getEnabledEventTypes() { + return new HashSet(realm.getEnabledEventTypes()); + } + + @Override + public void setEnabledEventTypes(Set enabledEventTypes) { + if (enabledEventTypes != null) { + realm.setEnabledEventTypes(new ArrayList(enabledEventTypes)); + } else { + realm.setEnabledEventTypes(Collections.EMPTY_LIST); + } + updateRealm(); + } + @Override public ApplicationModel getMasterAdminApp() { MongoApplicationEntity appData = getMongoStore().loadEntity(MongoApplicationEntity.class, realm.getAdminAppId(), invocationContext); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java index 581503718b..3b528e2604 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java @@ -26,6 +26,7 @@ import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor; import org.keycloak.OAuth2Constants; import org.keycloak.events.Details; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventType; import org.keycloak.models.ApplicationModel; import org.keycloak.models.ClientSessionModel; @@ -185,7 +186,7 @@ public class OIDCLoginProtocol implements LoginProtocol { public Response finishLogout(UserSessionModel userSession) { String redirectUri = userSession.getNote(OIDCLoginProtocol.LOGOUT_REDIRECT_URI); String state = userSession.getNote(OIDCLoginProtocol.LOGOUT_STATE_PARAM); - event.event(EventType.LOGOUT); + event.eventGroup(EventGroup.USER).event(EventType.LOGOUT); if (redirectUri != null) { event.detail(Details.REDIRECT_URI, redirectUri); } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java index 6bdae4e6ae..431d05ecec 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java @@ -1,18 +1,10 @@ package org.keycloak.protocol.oidc; import org.jboss.logging.Logger; -import org.jboss.resteasy.annotations.cache.NoCache; -import org.jboss.resteasy.spi.HttpRequest; -import org.jboss.resteasy.spi.HttpResponse; import org.jboss.resteasy.spi.ResteasyProviderFactory; -import org.keycloak.ClientConnection; import org.keycloak.OAuth2Constants; -import org.keycloak.OAuthErrorException; -import org.keycloak.RSATokenVerifier; -import org.keycloak.events.Details; -import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; -import org.keycloak.events.EventType; +import org.keycloak.events.EventGroup; import org.keycloak.jose.jwk.JWK; import org.keycloak.jose.jwk.JWKBuilder; import org.keycloak.login.LoginFormsProvider; @@ -25,8 +17,6 @@ import org.keycloak.protocol.oidc.endpoints.TokenEndpoint; import org.keycloak.protocol.oidc.endpoints.UserInfoEndpoint; import org.keycloak.protocol.oidc.endpoints.ValidateTokenEndpoint; import org.keycloak.protocol.oidc.representations.JSONWebKeySet; -import org.keycloak.representations.AccessToken; -import org.keycloak.services.ErrorResponseException; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.resources.RealmsResource; import org.keycloak.services.resources.flows.Flows; @@ -39,12 +29,8 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; -import javax.ws.rs.ext.Providers; -import java.util.HashMap; -import java.util.Map; /** * Resource class for the oauth/openid connect token service @@ -73,7 +59,7 @@ public class OIDCLoginProtocolService { public OIDCLoginProtocolService(RealmModel realm, EventBuilder event, AuthenticationManager authManager) { this.realm = realm; this.tokenManager = new TokenManager(); - this.event = event; + this.event = event.eventGroup(EventGroup.USER); this.authManager = authManager; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java index 66197b7faf..9cb6c0e278 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java @@ -9,6 +9,7 @@ import org.keycloak.constants.AdapterConstants; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventType; import org.keycloak.login.LoginFormsProvider; import org.keycloak.models.ApplicationModel; @@ -35,6 +36,7 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; + import java.util.List; /** @@ -88,7 +90,7 @@ public class AuthorizationEndpoint { this.authManager = authManager; this.realm = realm; this.event = event; - event.event(EventType.LOGIN); + event.eventGroup(EventGroup.USER).event(EventType.LOGIN); } @GET diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java index a61c8112e7..eb27a275ea 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java @@ -9,6 +9,7 @@ import org.keycloak.OAuthErrorException; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventType; import org.keycloak.models.ApplicationModel; import org.keycloak.models.ClientModel; @@ -70,7 +71,7 @@ public class LogoutEndpoint { this.tokenManager = tokenManager; this.authManager = authManager; this.realm = realm; - this.event = event; + this.event = event.eventGroup(EventGroup.USER); } /** diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java index bd211e4e95..cbeca604c3 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java @@ -9,6 +9,7 @@ import org.keycloak.constants.AdapterConstants; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventType; import org.keycloak.models.ApplicationModel; import org.keycloak.models.ClientModel; @@ -40,6 +41,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; + import java.util.Map; /** @@ -85,7 +87,7 @@ public class TokenEndpoint { this.tokenManager = tokenManager; this.authManager = authManager; this.realm = realm; - this.event = event; + this.event = event.eventGroup(EventGroup.USER); } @POST diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java index b41e9721f8..bdb807b919 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java @@ -26,6 +26,7 @@ import org.keycloak.OAuthErrorException; import org.keycloak.RSATokenVerifier; import org.keycloak.events.Details; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventType; import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; @@ -54,6 +55,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; + import java.util.HashMap; import java.util.Map; @@ -114,6 +116,7 @@ public class UserInfoEndpoint { private Response issueUserInfo(String tokenString) { EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder() + .eventGroup(EventGroup.USER) .event(EventType.USER_INFO_REQUEST) .detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java index 31499d1bd1..a3258a680f 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java @@ -9,6 +9,7 @@ import org.keycloak.RSATokenVerifier; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventType; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; @@ -22,6 +23,7 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.*; + import java.util.HashMap; import java.util.Map; @@ -51,7 +53,7 @@ public class ValidateTokenEndpoint { public ValidateTokenEndpoint(TokenManager tokenManager, RealmModel realm, EventBuilder event) { this.tokenManager = tokenManager; this.realm = realm; - this.event = event; + this.event = event.eventGroup(EventGroup.USER); } /** diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index f8b9bb2d0b..53012e862a 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -9,6 +9,7 @@ import org.keycloak.VerificationException; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.events.Details; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventType; import org.keycloak.jose.jws.JWSBuilder; import org.keycloak.login.LoginFormsProvider; @@ -43,6 +44,7 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; + import java.net.URI; import java.util.HashSet; import java.util.LinkedList; @@ -374,7 +376,7 @@ public class AuthenticationManager { logger.debugv("processAccessCode: go to oauth page?: {0}", !isResource); - event.detail(Details.CODE_ID, clientSession.getId()); + event.eventGroup(EventGroup.USER).detail(Details.CODE_ID, clientSession.getId()); Set requiredActions = user.getRequiredActions(); if (!requiredActions.isEmpty()) { diff --git a/services/src/main/java/org/keycloak/services/managers/EventsManager.java b/services/src/main/java/org/keycloak/services/managers/EventsManager.java index 6288546c7a..0bd5e5a0ef 100755 --- a/services/src/main/java/org/keycloak/services/managers/EventsManager.java +++ b/services/src/main/java/org/keycloak/services/managers/EventsManager.java @@ -5,11 +5,14 @@ import org.keycloak.ClientConnection; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventStoreProvider; +import org.keycloak.events.EventType; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Set; /** * @author Stian Thorgersen @@ -50,8 +53,13 @@ public class EventsManager { } } } + + Set enabledEventTypes = new HashSet(); + for(String type : realm.getEnabledEventTypes()) { + enabledEventTypes.add(EventType.valueOf(type)); + } - return new EventBuilder(listeners, realm, clientConnection.getRemoteAddr()); + return new EventBuilder(listeners, enabledEventTypes, realm, clientConnection.getRemoteAddr()); } } diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index 4da8e12ddf..138b0e4e78 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -25,6 +25,7 @@ import org.keycloak.timer.TimerProvider; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; /** @@ -161,6 +162,9 @@ public class RealmManager { if (rep.getEventsListeners() != null) { realm.setEventsListeners(new HashSet(rep.getEventsListeners())); } + if(rep.getEnabledEventTypes() != null) { + realm.setEnabledEventTypes(new HashSet(rep.getEnabledEventTypes())); + } } // Should be RealmManager moved to model/api instead of referencing methods this way? diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java index f694661a62..f8cc72aed4 100755 --- a/services/src/main/java/org/keycloak/services/resources/AccountService.java +++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java @@ -31,6 +31,7 @@ import org.keycloak.account.AccountProvider; import org.keycloak.events.Details; import org.keycloak.events.Event; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventStoreProvider; import org.keycloak.events.EventType; import org.keycloak.models.*; @@ -71,6 +72,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.Variant; + import java.lang.reflect.Method; import java.net.URI; import java.util.HashSet; @@ -141,7 +143,7 @@ public class AccountService { public AccountService(RealmModel realm, ApplicationModel application, EventBuilder event) { this.realm = realm; this.application = application; - this.event = event; + this.event = event.eventGroup(EventGroup.USER); this.authManager = new AppAuthManager(); } diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java index 7a4bea5d58..251130d587 100755 --- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java +++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java @@ -29,6 +29,7 @@ import org.keycloak.broker.provider.IdentityProviderFactory; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventType; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientSessionModel; @@ -61,6 +62,7 @@ import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import javax.ws.rs.core.*; import javax.ws.rs.core.Response.Status; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -109,7 +111,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } public void init() { - this.event = new EventsManager(this.realmModel, this.session, this.clientConnection).createEventBuilder().event(EventType.IDENTITY_PROVIDER_LOGIN); + this.event = new EventsManager(this.realmModel, this.session, this.clientConnection).createEventBuilder().event(EventType.IDENTITY_PROVIDER_LOGIN).eventGroup(EventGroup.USER); } @GET diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java index 5b405355a6..a8021821de 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -29,6 +29,7 @@ import org.keycloak.email.EmailProvider; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventType; import org.keycloak.jose.jws.JWSBuilder; import org.keycloak.login.LoginFormsProvider; @@ -63,6 +64,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Providers; + import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -132,7 +134,7 @@ public class LoginActionsService { public LoginActionsService(RealmModel realm, AuthenticationManager authManager, EventBuilder event) { this.realm = realm; this.authManager = authManager; - this.event = event; + this.event = event.eventGroup(EventGroup.USER); } private boolean checkSsl() { diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java index 1f43e9af0e..22aab14900 100755 --- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java @@ -5,6 +5,7 @@ import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.ClientConnection; import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.models.ApplicationModel; import org.keycloak.models.Constants; import org.keycloak.models.KeycloakSession; @@ -130,6 +131,7 @@ public class RealmsResource { RealmManager realmManager = new RealmManager(session); RealmModel realm = locateRealm(name, realmManager); EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder(); + event.eventGroup(EventGroup.USER); AuthenticationManager authManager = new AuthenticationManager(protector); LoginActionsService service = new LoginActionsService(realm, authManager, event); ResteasyProviderFactory.getInstance().injectProperties(service); @@ -143,6 +145,7 @@ public class RealmsResource { RealmManager realmManager = new RealmManager(session); RealmModel realm = locateRealm(name, realmManager); EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder(); + event.eventGroup(EventGroup.USER); ClientsManagementService service = new ClientsManagementService(realm, event); ResteasyProviderFactory.getInstance().injectProperties(service); return service; @@ -169,6 +172,7 @@ public class RealmsResource { } EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder(); + event.eventGroup(EventGroup.USER); AccountService accountService = new AccountService(realm, application, event); ResteasyProviderFactory.getInstance().injectProperties(accountService); //resourceContext.initResource(accountService); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java index 207d89a47c..19c876f4c3 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java @@ -6,9 +6,11 @@ import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpResponse; import org.jboss.resteasy.spi.NotFoundException; -import org.keycloak.ClientConnection; -import org.keycloak.Config; -import org.keycloak.Version; +import org.keycloak.ClientConnection; +import org.keycloak.Version; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.freemarker.BrowserSecurityHeaderSetup; import org.keycloak.freemarker.FreeMarkerException; import org.keycloak.freemarker.FreeMarkerUtil; @@ -28,21 +30,18 @@ import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.flows.Urls; -import org.keycloak.util.MimeTypeUtil; import javax.ws.rs.GET; import javax.ws.rs.Path; -import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import javax.ws.rs.core.CacheControl; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Providers; + import java.io.IOException; -import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; @@ -86,9 +85,11 @@ public class AdminConsole { protected AppAuthManager authManager; protected RealmModel realm; + private EventBuilder event; - public AdminConsole(RealmModel realm) { + public AdminConsole(RealmModel realm, EventBuilder event) { this.realm = realm; + this.event = event.detail(Details.REALM_NAME, realm.getName()); this.authManager = new AppAuthManager(); } @@ -168,6 +169,12 @@ public class AdminConsole { if (consoleApp == null) { throw new NotFoundException("Could not find admin console application"); } + + event.event(EventType.SET_REALM_ADAPTER_CONFIGURATION) + .client(consoleApp) + .detail(Details.REALM_REQUIRED_SSL, realm.getSslRequired().name().toLowerCase()) + .success(); + return new ApplicationManager().toInstallationRepresentation(realm, consoleApp, keycloak.getBaseUri(uriInfo)); } @@ -212,6 +219,8 @@ public class AdminConsole { logger.debug("setting up realm access for a realm user"); addRealmAccess(realm, user, realmAccess); } + + event.event(EventType.SET_REALM_USER_PERMISSIONS).user(user).success(); return Response.ok(new WhoAmI(user.getId(), realm.getName(), displayName, createRealm, realmAccess)).build(); } @@ -255,12 +264,14 @@ public class AdminConsole { @NoCache public Response logout() { URI redirect = AdminRoot.adminConsoleUrl(uriInfo).build(realm.getName()); - + + event.event(EventType.LOGOUT).detail(Details.REDIRECT_URI, redirect.toString()).success(); + return Response.status(302).location( OIDCLoginProtocolService.logoutUrl(uriInfo).queryParam("redirect_uri", redirect.toString()).build(realm.getName()) ).build(); } - + protected RealmModel getAdminstrationRealm(RealmManager realmManager) { return realmManager.getKeycloakAdminstrationRealm(); } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java index 4ecdbabe27..f50bcd5915 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java @@ -8,6 +8,9 @@ import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.spi.UnauthorizedException; import org.keycloak.ClientConnection; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; import org.keycloak.jose.jws.JWSInput; import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; @@ -16,6 +19,7 @@ import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.representations.AccessToken; import org.keycloak.services.managers.AppAuthManager; import org.keycloak.services.managers.AuthenticationManager; +import org.keycloak.services.managers.EventsManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.resources.Cors; @@ -27,6 +31,7 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; + import java.io.IOException; /** @@ -70,9 +75,6 @@ public class AdminRoot { return base.path(AdminRoot.class); } - - - /** * Convenience path to master realm admin console * @@ -124,7 +126,9 @@ public class AdminRoot { public AdminConsole getAdminConsole(final @PathParam("realm") String name) { RealmManager realmManager = new RealmManager(session); RealmModel realm = locateRealm(name, realmManager); - AdminConsole service = new AdminConsole(realm); + EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder(); + event.eventGroup(EventGroup.ADMIN).detail(Details.REALM_NAME, realm.getName()); + AdminConsole service = new AdminConsole(realm, event); ResteasyProviderFactory.getInstance().injectProperties(service); return service; } @@ -187,7 +191,9 @@ public class AdminRoot { Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response); - RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager); + EventBuilder event = new EventsManager(auth.getRealm(), session, clientConnection).createEventBuilder(); + event.eventGroup(EventGroup.ADMIN); + RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager, event); ResteasyProviderFactory.getInstance().injectProperties(adminResource); //resourceContext.initResource(adminResource); return adminResource; @@ -208,8 +214,10 @@ public class AdminRoot { logger.debug("authenticated admin access for: " + auth.getUser().getUsername()); } Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response); - - ServerInfoAdminResource adminResource = new ServerInfoAdminResource(); + + EventBuilder event = new EventsManager(auth.getRealm(), session, clientConnection).createEventBuilder(); + event.eventGroup(EventGroup.ADMIN); + ServerInfoAdminResource adminResource = new ServerInfoAdminResource(event); ResteasyProviderFactory.getInstance().injectProperties(adminResource); //resourceContext.initResource(adminResource); return adminResource; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java index 7df7b1ed25..9ec26ee734 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java @@ -5,6 +5,9 @@ import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.BadRequestException; import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.ApplicationModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ModelDuplicateException; @@ -40,6 +43,7 @@ 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.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -57,8 +61,10 @@ public class ApplicationResource { protected static final Logger logger = Logger.getLogger(ApplicationResource.class); protected RealmModel realm; private RealmAuth auth; + private EventBuilder event; protected ApplicationModel application; protected KeycloakSession session; + @Context protected UriInfo uriInfo; @@ -69,12 +75,13 @@ public class ApplicationResource { return (KeycloakApplication)keycloak; } - public ApplicationResource(RealmModel realm, RealmAuth auth, ApplicationModel applicationModel, KeycloakSession session) { + public ApplicationResource(RealmModel realm, RealmAuth auth, ApplicationModel applicationModel, KeycloakSession session, EventBuilder event) { this.realm = realm; this.auth = auth; this.application = applicationModel; this.session = session; - + this.event = event; + auth.init(RealmAuth.Resource.APPLICATION); } @@ -98,6 +105,9 @@ public class ApplicationResource { try { RepresentationToModel.updateApplication(rep, application); + + event.event(EventType.UPDATE_APPLICATION).client(application).success(); + return Response.noContent().build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("Application " + rep.getName() + " already exists"); @@ -115,6 +125,8 @@ public class ApplicationResource { @Produces(MediaType.APPLICATION_JSON) public ApplicationRepresentation getApplication() { auth.requireView(); + + event.event(EventType.VIEW_APPLICATION).client(application).success(); return ModelToRepresentation.toRepresentation(application); } @@ -126,7 +138,7 @@ public class ApplicationResource { */ @Path("certificates/{attr}") public ClientAttributeCertificateResource getCertficateResource(@PathParam("attr") String attributePrefix) { - return new ClientAttributeCertificateResource(realm, auth, application, session, attributePrefix); + return new ClientAttributeCertificateResource(realm, auth, application, session, attributePrefix, event); } @@ -175,6 +187,8 @@ public class ApplicationResource { @NoCache public void deleteApplication() { auth.requireManage(); + + event.event(EventType.DELETE_APPLICATION).client(application).success(); new ApplicationManager(new RealmManager(session)).removeApplication(realm, application); } @@ -228,7 +242,7 @@ public class ApplicationResource { @Path("roles") public RoleContainerResource getRoleContainerResource() { - return new RoleContainerResource(realm, auth, application); + return new RoleContainerResource(realm, auth, application, event); } /** @@ -331,6 +345,9 @@ public class ApplicationResource { UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(userSession); sessions.add(rep); } + + event.event(EventType.VIEW_APPLICATION_USER_SESSIONS).client(application).success(); + return sessions; } @@ -342,6 +359,9 @@ public class ApplicationResource { @POST public GlobalRequestResult logoutAll() { auth.requireManage(); + + event.event(EventType.INVALIDATE_APPLICATION_USER_SESSIONS).client(application).success(); + return new ResourceAdminManager().logoutApplication(uriInfo.getRequestUri(), realm, application); } @@ -357,6 +377,8 @@ public class ApplicationResource { if (user == null) { throw new NotFoundException("User not found"); } + + event.event(EventType.INVALIDATE_APPLICATION_USER_SESSION).client(application).user(user).success(); new ResourceAdminManager().logoutUserFromApplication(uriInfo.getRequestUri(), realm, application, user, session); } @@ -378,6 +400,10 @@ public class ApplicationResource { } if (logger.isDebugEnabled()) logger.debug("Register node: " + node); application.registerNode(node, Time.currentTime()); + + event.event(EventType.REGISTER_APPLICATION_CLUSTER_NODE).client(application) + .detail(Details.APPLICATION_CLUSTER_NODE, node) + .success(); } /** @@ -398,6 +424,10 @@ public class ApplicationResource { } application.unregisterNode(node); + + event.event(EventType.UNREGISTER_APPLICATION_CLUSTER_NODE).client(application) + .detail(Details.APPLICATION_CLUSTER_NODE, node) + .success(); } /** diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsByIdResource.java index fc93f017c3..5c840656d4 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsByIdResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsByIdResource.java @@ -1,5 +1,6 @@ package org.keycloak.services.resources.admin; +import org.keycloak.events.EventBuilder; import org.keycloak.models.ApplicationModel; import org.keycloak.models.RealmModel; @@ -8,8 +9,8 @@ import org.keycloak.models.RealmModel; * @version $Revision: 1 $ */ public class ApplicationsByIdResource extends ApplicationsResource { - public ApplicationsByIdResource(RealmModel realm, RealmAuth auth) { - super(realm, auth); + public ApplicationsByIdResource(RealmModel realm, RealmAuth auth, EventBuilder event) { + super(realm, auth, event); } @Override diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java index c74a8f06ca..f907a04453 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java @@ -4,6 +4,9 @@ import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.ApplicationModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ModelDuplicateException; @@ -23,6 +26,7 @@ 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.ArrayList; import java.util.List; @@ -36,14 +40,16 @@ public class ApplicationsResource { protected static final Logger logger = Logger.getLogger(RealmAdminResource.class); protected RealmModel realm; private RealmAuth auth; + private EventBuilder event; @Context protected KeycloakSession session; - public ApplicationsResource(RealmModel realm, RealmAuth auth) { + public ApplicationsResource(RealmModel realm, RealmAuth auth, EventBuilder event) { this.realm = realm; this.auth = auth; - + this.event = event; + auth.init(RealmAuth.Resource.APPLICATION); } @@ -71,6 +77,9 @@ public class ApplicationsResource { rep.add(app); } } + + event.event(EventType.VIEW_REALM_APPLICATIONS).success(); + return rep; } @@ -85,13 +94,16 @@ public class ApplicationsResource { @Consumes(MediaType.APPLICATION_JSON) public Response createApplication(final @Context UriInfo uriInfo, final ApplicationRepresentation rep) { auth.requireManage(); - + try { ApplicationModel applicationModel = RepresentationToModel.createApplication(session, realm, rep, true); + + event.event(EventType.CREATE_APPLICATION).client(applicationModel).success(); return Response.created(uriInfo.getAbsolutePathBuilder().path(getApplicationPath(applicationModel)).build()).build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("Application " + rep.getName() + " already exists"); } + } protected String getApplicationPath(ApplicationModel applicationModel) { @@ -110,7 +122,7 @@ public class ApplicationsResource { if (applicationModel == null) { throw new NotFoundException("Could not find application: " + name); } - ApplicationResource applicationResource = new ApplicationResource(realm, auth, applicationModel, session); + ApplicationResource applicationResource = new ApplicationResource(realm, auth, applicationModel, session, event); ResteasyProviderFactory.getInstance().injectProperties(applicationResource); //resourceContext.initResource(applicationResource); return applicationResource; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java index 4510dc2ae6..670f671e11 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java @@ -6,6 +6,9 @@ import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput; import org.jboss.resteasy.spi.BadRequestException; import org.jboss.resteasy.spi.NotAcceptableException; import org.jboss.resteasy.spi.NotFoundException; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; @@ -21,6 +24,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -39,18 +43,20 @@ import java.util.Map; * @version $Revision: 1 $ */ public class ClientAttributeCertificateResource { + public static final String PRIVATE_KEY = "private.key"; public static final String X509CERTIFICATE = "certificate"; protected RealmModel realm; private RealmAuth auth; + private EventBuilder event; protected ClientModel client; protected KeycloakSession session; protected String attributePrefix; protected String privateAttribute; protected String certificateAttribute; - public ClientAttributeCertificateResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, String attributePrefix) { + public ClientAttributeCertificateResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, String attributePrefix, EventBuilder event) { this.realm = realm; this.auth = auth; this.client = client; @@ -58,6 +64,7 @@ public class ClientAttributeCertificateResource { this.attributePrefix = attributePrefix; this.privateAttribute = attributePrefix + "." + PRIVATE_KEY; this.certificateAttribute = attributePrefix + "." + X509CERTIFICATE; + this.event = event; } public static class ClientKeyPairInfo { @@ -93,6 +100,9 @@ public class ClientAttributeCertificateResource { ClientKeyPairInfo info = new ClientKeyPairInfo(); info.setCertificate(client.getAttribute(certificateAttribute)); info.setPrivateKey(client.getAttribute(privateAttribute)); + + event.event(EventType.VIEW_CLIENT_CERTIFICATE).client(client).success(); + return info; } @@ -131,6 +141,9 @@ public class ClientAttributeCertificateResource { ClientKeyPairInfo info = new ClientKeyPairInfo(); info.setCertificate(client.getAttribute(certificateAttribute)); info.setPrivateKey(client.getAttribute(privateAttribute)); + + event.event(EventType.GENERATE_CLIENT_CERTIFICATE).client(client).success(); + return info; } @@ -187,8 +200,9 @@ public class ClientAttributeCertificateResource { client.setAttribute(certificateAttribute, certPem); info.setCertificate(certPem); } - - + + event.event(EventType.UPLOAD_CLIENT_CERTIFICATE).client(client).success(); + return info; } @@ -314,6 +328,9 @@ public class ClientAttributeCertificateResource { stream.flush(); stream.close(); byte[] rtn = stream.toByteArray(); + + event.event(EventType.DOWNLOAD_CLIENT_CERTIFICATE).client(client).success(); + return rtn; } catch (Exception e) { throw new RuntimeException(e); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java index a5c0f50741..de931b5c2b 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java @@ -4,6 +4,9 @@ import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.cache.NoCache; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.ClientIdentityProviderMappingModel; import org.keycloak.models.ClientModel; import org.keycloak.models.FederatedIdentityModel; @@ -29,6 +32,7 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; + import java.util.ArrayList; import java.util.List; @@ -43,18 +47,26 @@ public class IdentityProviderResource { private final RealmModel realm; private final KeycloakSession session; private final IdentityProviderModel identityProviderModel; + private EventBuilder event; - public IdentityProviderResource(RealmAuth auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel) { + public IdentityProviderResource(RealmAuth auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel, EventBuilder event) { this.realm = realm; this.session = session; this.identityProviderModel = identityProviderModel; this.auth = auth; + this.event = event; } @GET @NoCache @Produces("application/json") public IdentityProviderRepresentation getIdentityProvider() { + + event.event(EventType.VIEW_IDENTITY_PROVIDER) + .detail(Details.IDENTITY_PROVIDER, identityProviderModel.getProviderId()) + .detail(Details.IDENTITY_PROVIDER_ALIAS, identityProviderModel.getAlias()) + .success(); + return ModelToRepresentation.toRepresentation(this.identityProviderModel); } @@ -64,7 +76,14 @@ public class IdentityProviderResource { this.auth.requireManage(); removeClientIdentityProviders(this.realm.getApplications(), this.identityProviderModel); removeClientIdentityProviders(this.realm.getOAuthClients(), this.identityProviderModel); - this.realm.removeIdentityProviderByAlias(this.identityProviderModel.getAlias()); + + this.realm.removeIdentityProviderByAlias(this.identityProviderModel.getAlias()); + + event.event(EventType.DELETE_IDENTITY_PROVIDER) + .detail(Details.IDENTITY_PROVIDER, identityProviderModel.getProviderId()) + .detail(Details.IDENTITY_PROVIDER_ALIAS, identityProviderModel.getAlias()) + .success(); + return Response.noContent().build(); } @@ -89,6 +108,11 @@ public class IdentityProviderResource { updateClientsAfterProviderAliasChange(this.realm.getOAuthClients(), oldProviderId, newProviderId); updateUsersAfterProviderAliasChange(this.session.users().getUsers(this.realm), oldProviderId, newProviderId); } + + event.event(EventType.UPDATE_IDENTITY_PROVIDER) + .detail(Details.IDENTITY_PROVIDER, identityProviderModel.getProviderId()) + .detail(Details.IDENTITY_PROVIDER_ALIAS, identityProviderModel.getAlias()) + .success(); return Response.noContent().build(); } catch (ModelDuplicateException e) { diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java index afae00b1f6..19ec30140a 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java @@ -8,8 +8,9 @@ import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; -import org.keycloak.models.ClientIdentityProviderMappingModel; -import org.keycloak.models.ClientModel; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ModelDuplicateException; @@ -32,6 +33,7 @@ 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.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -48,11 +50,13 @@ public class IdentityProvidersResource { private final RealmModel realm; private final KeycloakSession session; private RealmAuth auth; + private EventBuilder event; - public IdentityProvidersResource(RealmModel realm, KeycloakSession session, RealmAuth auth) { + public IdentityProvidersResource(RealmModel realm, KeycloakSession session, RealmAuth auth, EventBuilder event) { this.realm = realm; this.session = session; this.auth = auth; + this.event = event; this.auth.init(RealmAuth.Resource.IDENTITY_PROVIDER); } @@ -65,6 +69,11 @@ public class IdentityProvidersResource { IdentityProviderFactory providerFactory = getProviderFactorytById(providerId); if (providerFactory != null) { + event.event(EventType.VIEW_IDENTITY_PROVIDERS) + .detail(Details.IDENTITY_PROVIDER_FACTORY, providerFactory.getId()) + .detail(Details.IDENTITY_PROVIDER_FACTORY_IDENTITY, providerFactory.getName()) + .success(); + return Response.ok(providerFactory).build(); } @@ -83,6 +92,12 @@ public class IdentityProvidersResource { InputStream inputStream = file.getBody(InputStream.class, null); IdentityProviderFactory providerFactory = getProviderFactorytById(providerId); Map config = providerFactory.parseConfig(inputStream); + + event.event(EventType.IMPORT_IDENTITY_PROVIDER_CONFIG) + .detail(Details.IDENTITY_PROVIDER_FACTORY, providerFactory.getId()) + .detail(Details.IDENTITY_PROVIDER_FACTORY_IDENTITY, providerFactory.getName()) + .success(); + return config; } @@ -104,6 +119,12 @@ public class IdentityProvidersResource { } IdentityProviderFactory providerFactory = getProviderFactorytById(providerId); Map config = providerFactory.parseConfig(inputStream); + + event.event(EventType.IMPORT_IDENTITY_PROVIDER_CONFIG) + .detail(Details.IDENTITY_PROVIDER_FACTORY, providerFactory.getId()) + .detail(Details.IDENTITY_PROVIDER_FACTORY_IDENTITY, providerFactory.getName()) + .success(); + return config; } @@ -119,6 +140,8 @@ public class IdentityProvidersResource { for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) { representations.add(ModelToRepresentation.toRepresentation(identityProviderModel)); } + + event.event(EventType.VIEW_IDENTITY_PROVIDERS).success(); return representations; } @@ -131,7 +154,12 @@ public class IdentityProvidersResource { try { this.realm.addIdentityProvider(RepresentationToModel.toModel(representation)); - + + event.event(EventType.CREATE_IDENTITY_PROVIDER) + .detail(Details.IDENTITY_PROVIDER, representation.getProviderId()) + .detail(Details.IDENTITY_PROVIDER_ALIAS, representation.getAlias()) + .success(); + return Response.created(uriInfo.getAbsolutePathBuilder().path(representation.getProviderId()).build()).build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("Identity Provider " + representation.getAlias() + " already exists"); @@ -153,9 +181,14 @@ public class IdentityProvidersResource { if (identityProviderModel == null) { throw new NotFoundException("Could not find identity provider: " + alias); } - - IdentityProviderResource identityProviderResource = new IdentityProviderResource(this.auth, realm, session, identityProviderModel); + + IdentityProviderResource identityProviderResource = new IdentityProviderResource(this.auth, realm, session, identityProviderModel, event); ResteasyProviderFactory.getInstance().injectProperties(identityProviderResource); + + event.event(EventType.VIEW_IDENTITY_PROVIDER) + .detail(Details.IDENTITY_PROVIDER, identityProviderModel.getProviderId()) + .detail(Details.IDENTITY_PROVIDER_ALIAS, identityProviderModel.getAlias()) + .success(); return identityProviderResource; } @@ -180,4 +213,4 @@ public class IdentityProvidersResource { return allProviders; } -} +} \ No newline at end of file diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java index b69fb83c29..ea9a69afc5 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java @@ -4,6 +4,9 @@ import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.OAuthClientModel; @@ -31,6 +34,7 @@ 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.io.IOException; /** @@ -43,6 +47,7 @@ public class OAuthClientResource { protected static final Logger logger = Logger.getLogger(RealmAdminResource.class); protected RealmModel realm; private RealmAuth auth; + private EventBuilder event; protected OAuthClientModel oauthClient; protected KeycloakSession session; @Context @@ -55,11 +60,12 @@ public class OAuthClientResource { return (KeycloakApplication)application; } - public OAuthClientResource(RealmModel realm, RealmAuth auth, OAuthClientModel oauthClient, KeycloakSession session) { + public OAuthClientResource(RealmModel realm, RealmAuth auth, OAuthClientModel oauthClient, KeycloakSession session, EventBuilder event) { this.realm = realm; this.auth = auth; this.oauthClient = oauthClient; this.session = session; + this.event = event; auth.init(RealmAuth.Resource.CLIENT); } @@ -84,7 +90,7 @@ public class OAuthClientResource { */ @Path("certificates/{attr}") public ClientAttributeCertificateResource getCertficateResource(@PathParam("attr") String attributePrefix) { - return new ClientAttributeCertificateResource(realm, auth, oauthClient, session, attributePrefix); + return new ClientAttributeCertificateResource(realm, auth, oauthClient, session, attributePrefix, event); } @@ -102,6 +108,8 @@ public class OAuthClientResource { try { RepresentationToModel.updateOAuthClient(session, rep, oauthClient); + event.event(EventType.UPDATE_OAUTH_CLIENT).client(oauthClient).success(); + return Response.noContent().build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("Client " + rep.getName() + " already exists"); @@ -118,7 +126,9 @@ public class OAuthClientResource { @Produces(MediaType.APPLICATION_JSON) public OAuthClientRepresentation getOAuthClient() { auth.requireView(); - + + event.event(EventType.VIEW_OAUTH_CLIENT).client(oauthClient).success(); + return ModelToRepresentation.toRepresentation(oauthClient); } @@ -150,7 +160,9 @@ public class OAuthClientResource { @NoCache public void deleteOAuthClient() { auth.requireManage(); - + + event.event(EventType.DELETE_OAUTH_CLIENT).client(oauthClient).success(); + new OAuthClientManager(new RealmManager(session)).removeClient(realm, oauthClient); } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsByIdResource.java index b7cfb1a8ec..5f19949ff0 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsByIdResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsByIdResource.java @@ -1,38 +1,17 @@ package org.keycloak.services.resources.admin; -import org.jboss.logging.Logger; -import org.jboss.resteasy.annotations.cache.NoCache; -import org.jboss.resteasy.spi.NotFoundException; -import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.keycloak.events.EventBuilder; import org.keycloak.models.KeycloakSession; -import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.OAuthClientModel; import org.keycloak.models.RealmModel; -import org.keycloak.models.utils.ModelToRepresentation; -import org.keycloak.models.utils.RepresentationToModel; -import org.keycloak.representations.idm.OAuthClientRepresentation; -import org.keycloak.services.resources.flows.Flows; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -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.ArrayList; -import java.util.List; /** * @author Bill Burke * @version $Revision: 1 $ */ public class OAuthClientsByIdResource extends OAuthClientsResource { - public OAuthClientsByIdResource(RealmModel realm, RealmAuth auth, KeycloakSession session) { - super(realm, auth, session); + public OAuthClientsByIdResource(RealmModel realm, RealmAuth auth, KeycloakSession session, EventBuilder event) { + super(realm, auth, session, event); } @Override diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java index a2c387ccb1..f76e002bab 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java @@ -4,6 +4,9 @@ import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.OAuthClientModel; @@ -23,6 +26,7 @@ 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.ArrayList; import java.util.List; @@ -33,9 +37,9 @@ import java.util.List; public class OAuthClientsResource { protected static final Logger logger = Logger.getLogger(RealmAdminResource.class); protected RealmModel realm; - + private EventBuilder event; protected KeycloakSession session; - + /* @Context protected ResourceContext resourceContext; @@ -43,11 +47,12 @@ public class OAuthClientsResource { */ private RealmAuth auth; - public OAuthClientsResource(RealmModel realm, RealmAuth auth, KeycloakSession session) { + public OAuthClientsResource(RealmModel realm, RealmAuth auth, KeycloakSession session, EventBuilder event) { this.auth = auth; this.realm = realm; this.session = session; - + this.event = event; + auth.init(RealmAuth.Resource.CLIENT); } @@ -73,6 +78,9 @@ public class OAuthClientsResource { rep.add(client); } } + + event.event(EventType.VIEW_OAUTH_CLIENTS).success(); + return rep; } @@ -90,10 +98,13 @@ public class OAuthClientsResource { try { OAuthClientModel oauth = RepresentationToModel.createOAuthClient(session, rep, realm); + event.event(EventType.CREATE_OAUTH_CLIENT).client(oauth).success(); + return Response.created(uriInfo.getAbsolutePathBuilder().path(getClientPath(oauth)).build()).build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("Client " + rep.getName() + " already exists"); } + } protected String getClientPath(OAuthClientModel oauth) { @@ -114,7 +125,7 @@ public class OAuthClientsResource { if (oauth == null) { throw new NotFoundException("OAuth Client not found"); } - OAuthClientResource oAuthClientResource = new OAuthClientResource(realm, auth, oauth, session); + OAuthClientResource oAuthClientResource = new OAuthClientResource(realm, auth, oauth, session, event); ResteasyProviderFactory.getInstance().injectProperties(oAuthClientResource); //resourceContext.initResource(oAuthClientResource); return oAuthClientResource; 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 e62b4ba446..75a5416be8 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 @@ -26,6 +26,7 @@ import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.ClientConnection; import org.keycloak.events.Event; +import org.keycloak.events.EventBuilder; import org.keycloak.events.EventQuery; import org.keycloak.events.EventStoreProvider; import org.keycloak.events.EventType; @@ -63,6 +64,7 @@ public class RealmAdminResource { protected RealmAuth auth; protected RealmModel realm; private TokenManager tokenManager; + private EventBuilder event; @Context protected KeycloakSession session; @@ -75,12 +77,13 @@ public class RealmAdminResource { @Context protected HttpHeaders headers; - - public RealmAdminResource(RealmAuth auth, RealmModel realm, TokenManager tokenManager) { + + public RealmAdminResource(RealmAuth auth, RealmModel realm, TokenManager tokenManager, EventBuilder event) { this.auth = auth; this.realm = realm; this.tokenManager = tokenManager; - + this.event = event; + auth.init(RealmAuth.Resource.REALM); } @@ -102,7 +105,7 @@ public class RealmAdminResource { */ @Path("applications") public ApplicationsResource getApplications() { - ApplicationsResource applicationsResource = new ApplicationsResource(realm, auth); + ApplicationsResource applicationsResource = new ApplicationsResource(realm, auth, event); ResteasyProviderFactory.getInstance().injectProperties(applicationsResource); //resourceContext.initResource(applicationsResource); return applicationsResource; @@ -115,7 +118,7 @@ public class RealmAdminResource { */ @Path("applications-by-id") public ApplicationsByIdResource getApplicationsById() { - ApplicationsByIdResource applicationsResource = new ApplicationsByIdResource(realm, auth); + ApplicationsByIdResource applicationsResource = new ApplicationsByIdResource(realm, auth, event); ResteasyProviderFactory.getInstance().injectProperties(applicationsResource); //resourceContext.initResource(applicationsResource); return applicationsResource; @@ -128,7 +131,7 @@ public class RealmAdminResource { */ @Path("oauth-clients") public OAuthClientsResource getOAuthClients() { - OAuthClientsResource oauth = new OAuthClientsResource(realm, auth, session); + OAuthClientsResource oauth = new OAuthClientsResource(realm, auth, session, event); ResteasyProviderFactory.getInstance().injectProperties(oauth); //resourceContext.initResource(oauth); return oauth; @@ -141,7 +144,7 @@ public class RealmAdminResource { */ @Path("oauth-clients-by-id") public OAuthClientsByIdResource getOAuthClientsById() { - OAuthClientsByIdResource oauth = new OAuthClientsByIdResource(realm, auth, session); + OAuthClientsByIdResource oauth = new OAuthClientsByIdResource(realm, auth, session, event); ResteasyProviderFactory.getInstance().injectProperties(oauth); //resourceContext.initResource(oauth); return oauth; @@ -154,7 +157,7 @@ public class RealmAdminResource { */ @Path("roles") public RoleContainerResource getRoleContainerResource() { - return new RoleContainerResource(realm, auth, realm); + return new RoleContainerResource(realm, auth, realm, event); } /** @@ -177,13 +180,18 @@ public class RealmAdminResource { CacheUserProvider cache = (CacheUserProvider)session.userStorage(); rep.setUserCacheEnabled(cache.isEnabled()); } + + event.event(EventType.VIEW_REALM).success(); + return rep; } else { auth.requireAny(); RealmRepresentation rep = new RealmRepresentation(); rep.setRealm(realm.getName()); - + + event.event(EventType.VIEW_REALM).success(); + return rep; } } @@ -218,7 +226,9 @@ public class RealmAdminResource { for (final UserFederationProviderModel fedProvider : federationProviders) { usersSyncManager.refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), fedProvider, realm.getId()); } - + + event.event(EventType.UPDATE_REALM).success(); + return Response.noContent().build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("Realm " + rep.getRealm() + " already exists"); @@ -236,6 +246,8 @@ public class RealmAdminResource { if (!new RealmManager(session).removeRealm(realm)) { throw new NotFoundException("Realm doesn't exist"); } + + event.event(EventType.DELETE_REALM).success(); } /** @@ -245,7 +257,7 @@ public class RealmAdminResource { */ @Path("users") public UsersResource users() { - UsersResource users = new UsersResource(realm, auth, tokenManager); + UsersResource users = new UsersResource(realm, auth, tokenManager, event); ResteasyProviderFactory.getInstance().injectProperties(users); //resourceContext.initResource(users); return users; @@ -253,7 +265,7 @@ public class RealmAdminResource { @Path("user-federation") public UserFederationResource userFederation() { - UserFederationResource fed = new UserFederationResource(realm, auth); + UserFederationResource fed = new UserFederationResource(realm, auth, event); ResteasyProviderFactory.getInstance().injectProperties(fed); //resourceContext.initResource(fed); return fed; @@ -266,7 +278,7 @@ public class RealmAdminResource { */ @Path("roles-by-id") public RoleByIdResource rolesById() { - RoleByIdResource resource = new RoleByIdResource(realm, auth); + RoleByIdResource resource = new RoleByIdResource(realm, auth, event); ResteasyProviderFactory.getInstance().injectProperties(resource); //resourceContext.initResource(resource); return resource; @@ -473,6 +485,6 @@ public class RealmAdminResource { @Path("identity-provider") public IdentityProvidersResource getIdentityProviderResource() { - return new IdentityProvidersResource(realm, session, this.auth); + return new IdentityProvidersResource(realm, session, this.auth, event); } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java index e434738dc1..947e732140 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java @@ -6,6 +6,10 @@ import org.jboss.resteasy.plugins.providers.multipart.InputPart; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput; import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventGroup; +import org.keycloak.events.EventType; import org.keycloak.models.AdminRoles; import org.keycloak.models.ApplicationModel; import org.keycloak.models.KeycloakSession; @@ -33,6 +37,7 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; + import java.io.IOException; import java.net.URI; import java.util.ArrayList; @@ -49,10 +54,12 @@ public class RealmsAdminResource { protected static final Logger logger = Logger.getLogger(RealmsAdminResource.class); protected AdminAuth auth; protected TokenManager tokenManager; + private EventBuilder event; - public RealmsAdminResource(AdminAuth auth, TokenManager tokenManager) { + public RealmsAdminResource(AdminAuth auth, TokenManager tokenManager, EventBuilder event) { this.auth = auth; this.tokenManager = tokenManager; + this.event = event; } public static final CacheControl noCache = new CacheControl(); @@ -72,7 +79,6 @@ public class RealmsAdminResource { @Context protected KeycloakApplication keycloak; - /** * Returns a list of realms. This list is filtered based on what realms the caller is allowed to view. * @@ -135,6 +141,9 @@ public class RealmsAdminResource { URI location = AdminRoot.realmsUrl(uriInfo).path(realm.getName()).build(); logger.debugv("imported realm success, sending back: {0}", location.toString()); + + event.event(EventType.IMPORT_REALM).detail(Details.REALM_NAME, realm.getName()).success(); + return Response.created(location).build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("Realm " + rep.getRealm() + " already exists"); @@ -181,8 +190,10 @@ public class RealmsAdminResource { URI location = AdminRoot.realmsUrl(uriInfo).path(realm.getName()).build(); return Response.created(location).build(); } + + event.event(EventType.UPLOAD_REALM).detail(Details.REALM_NAME, realm.getName()).success(); } - + return Response.noContent().build(); } @@ -224,8 +235,9 @@ public class RealmsAdminResource { } else { realmAuth = new RealmAuth(auth, realm.getApplicationByName(realmManager.getRealmAdminApplicationName(auth.getRealm()))); } - - RealmAdminResource adminResource = new RealmAdminResource(realmAuth, realm, tokenManager); + + event.detail(Details.REALM_NAME, realm.getName()); + RealmAdminResource adminResource = new RealmAdminResource(realmAuth, realm, tokenManager, event); ResteasyProviderFactory.getInstance().injectProperties(adminResource); //resourceContext.initResource(adminResource); return adminResource; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java index 96c71f2fb3..07759769ae 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java @@ -3,7 +3,11 @@ package org.keycloak.services.resources.admin; import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.NotFoundException; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.ApplicationModel; +import org.keycloak.models.KeycloakSession; import org.keycloak.models.OAuthClientModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; @@ -18,6 +22,8 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; + import java.util.List; import java.util.Set; @@ -31,12 +37,17 @@ public class RoleByIdResource extends RoleResource { protected static final Logger logger = Logger.getLogger(RoleByIdResource.class); private final RealmModel realm; private final RealmAuth auth; + private EventBuilder event; - public RoleByIdResource(RealmModel realm, RealmAuth auth) { + @Context + protected KeycloakSession session; + + public RoleByIdResource(RealmModel realm, RealmAuth auth, EventBuilder event) { super(realm); this.realm = realm; this.auth = auth; + this.event = event; } /** @@ -52,6 +63,12 @@ public class RoleByIdResource extends RoleResource { public RoleRepresentation getRole(final @PathParam("role-id") String id) { RoleModel roleModel = getRoleModel(id); auth.requireView(); + + event.event(EventType.VIEW_ROLE) + .detail(Details.ROLE_ID, roleModel.getId()) + .detail(Details.ROLE_NAME, roleModel.getName()) + .success(); + return getRole(roleModel); } @@ -88,6 +105,11 @@ public class RoleByIdResource extends RoleResource { RoleModel role = getRoleModel(id); auth.requireManage(); deleteRole(role); + + event.event(EventType.DELETE_ROLE) + .detail(Details.ROLE_ID, role.getId()) + .detail(Details.ROLE_NAME, role.getName()) + .success(); } /** @@ -103,6 +125,11 @@ public class RoleByIdResource extends RoleResource { RoleModel role = getRoleModel(id); auth.requireManage(); updateRole(rep, role); + + event.event(EventType.UPDATE_ROLE) + .detail(Details.ROLE_ID, role.getId()) + .detail(Details.ROLE_NAME, role.getName()) + .success(); } /** @@ -118,6 +145,11 @@ public class RoleByIdResource extends RoleResource { RoleModel role = getRoleModel(id); auth.requireManage(); addComposites(roles, role); + + event.event(EventType.MAKE_ROLE_COMPOSITE) + .detail(Details.ROLE_ID, role.getId()) + .detail(Details.ROLE_NAME, role.getName()) + .success(); } /** diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java index 5ee76af001..f01841ddf8 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java @@ -2,6 +2,9 @@ package org.keycloak.services.resources.admin; import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.NotFoundException; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.ApplicationModel; import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.RealmModel; @@ -22,6 +25,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; + import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -34,12 +38,14 @@ public class RoleContainerResource extends RoleResource { private final RealmModel realm; private final RealmAuth auth; protected RoleContainerModel roleContainer; + private EventBuilder event; - public RoleContainerResource(RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer) { + public RoleContainerResource(RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer, EventBuilder event) { super(realm); this.realm = realm; this.auth = auth; this.roleContainer = roleContainer; + this.event = event; } /** @@ -58,6 +64,9 @@ public class RoleContainerResource extends RoleResource { for (RoleModel roleModel : roleModels) { roles.add(ModelToRepresentation.toRepresentation(roleModel)); } + + event.event(EventType.VIEW_ROLES).success(); + return roles; } @@ -76,6 +85,12 @@ public class RoleContainerResource extends RoleResource { try { RoleModel role = roleContainer.addRole(rep.getName()); role.setDescription(rep.getDescription()); + + event.event(EventType.CREATE_ROLE) + .detail(Details.ROLE_ID, role.getId()) + .detail(Details.ROLE_NAME, role.getName()) + .success(); + return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getName()).build()).build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("Role with name " + rep.getName() + " already exists"); @@ -99,6 +114,12 @@ public class RoleContainerResource extends RoleResource { if (roleModel == null) { throw new NotFoundException("Could not find role: " + roleName); } + + event.event(EventType.VIEW_ROLE) + .detail(Details.ROLE_ID, roleModel.getId()) + .detail(Details.ROLE_NAME, roleModel.getName()) + .success(); + return getRole(roleModel); } @@ -118,6 +139,11 @@ public class RoleContainerResource extends RoleResource { throw new NotFoundException("Could not find role: " + roleName); } deleteRole(role); + + event.event(EventType.DELETE_ROLE) + .detail(Details.ROLE_ID, role.getId()) + .detail(Details.ROLE_NAME, role.getName()) + .success(); } /** @@ -139,6 +165,12 @@ public class RoleContainerResource extends RoleResource { } try { updateRole(rep, role); + + event.event(EventType.UPDATE_ROLE) + .detail(Details.ROLE_ID, role.getId()) + .detail(Details.ROLE_NAME, role.getName()) + .success(); + return Response.noContent().build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("Role with name " + rep.getName() + " already exists"); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java index 80ba4025c9..df75c51724 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java @@ -3,7 +3,10 @@ package org.keycloak.services.resources.admin; import org.keycloak.Version; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; import org.keycloak.events.EventListenerProvider; +import org.keycloak.events.EventType; import org.keycloak.exportimport.ApplicationImporter; import org.keycloak.exportimport.ApplicationImporterFactory; import org.keycloak.freemarker.Theme; @@ -23,6 +26,7 @@ import org.keycloak.social.SocialIdentityProvider; import javax.ws.rs.GET; import javax.ws.rs.core.Context; + import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -40,7 +44,13 @@ public class ServerInfoAdminResource { @Context private KeycloakSession session; - + + private EventBuilder event; + + public ServerInfoAdminResource(EventBuilder event) { + this.event = event; + } + /** * Returns a list of themes, social providers, auth providers, and event listeners available on this server * @@ -60,6 +70,12 @@ public class ServerInfoAdminResource { setProviders(info); setProtocolMapperTypes(info); setBuiltinProtocolMappers(info); + + event.event(EventType.VIEW_SERVER_INFO) + .detail(Details.SERVER_VERSION, info.version) + .detail(Details.SERVER_TIME, info.serverTime) + .success(); + return info; } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java index 47f1b65faa..1dad039a2c 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java @@ -11,6 +11,9 @@ import org.keycloak.models.UserFederationProvider; import org.keycloak.models.UserFederationProviderFactory; import org.keycloak.models.UserFederationProviderModel; import org.keycloak.constants.KerberosConstants; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.provider.ProviderFactory; import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation; @@ -30,6 +33,7 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; + import java.util.LinkedList; import java.util.List; @@ -45,16 +49,19 @@ public class UserFederationResource { protected RealmModel realm; protected RealmAuth auth; - + + private EventBuilder event; + @Context protected UriInfo uriInfo; - + @Context protected KeycloakSession session; - public UserFederationResource(RealmModel realm, RealmAuth auth) { + public UserFederationResource(RealmModel realm, RealmAuth auth, EventBuilder event) { this.auth = auth; this.realm = realm; + this.event = event; auth.init(RealmAuth.Resource.USER); } @@ -77,11 +84,14 @@ public class UserFederationResource { rep.setOptions(((UserFederationProviderFactory)factory).getConfigurationOptions()); providers.add(rep); } + + event.event(EventType.VIEW_PROVIDER_FACTORIES).success(); + return providers; } /** - * Get List of available provider factories + * Get a provider * * @return */ @@ -98,6 +108,9 @@ public class UserFederationResource { UserFederationProviderFactoryRepresentation rep = new UserFederationProviderFactoryRepresentation(); rep.setId(factory.getId()); rep.setOptions(((UserFederationProviderFactory)factory).getConfigurationOptions()); + + event.event(EventType.VIEW_PROVIDER).detail(Details.PROVIDER_ID, rep.getId()).success(); + return rep; } throw new NotFoundException("Could not find provider"); @@ -122,7 +135,12 @@ public class UserFederationResource { rep.getFullSyncPeriod(), rep.getChangedSyncPeriod(), rep.getLastSync()); new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId()); checkKerberosCredential(model); - + + event.event(EventType.CREATE_PROVIDER) + .detail(Details.PROVIDER_ID, model.getId()) + .detail(Details.PROVIDER_NAME, model.getProviderName()) + .success(); + return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build(); } @@ -146,6 +164,11 @@ public class UserFederationResource { realm.updateUserFederationProvider(model); new UsersSyncManager().refreshPeriodicSyncForProvider(session.getKeycloakSessionFactory(), session.getProvider(TimerProvider.class), model, realm.getId()); checkKerberosCredential(model); + + event.event(EventType.UPDATE_PROVIDER) + .detail(Details.PROVIDER_ID, model.getId()) + .detail(Details.PROVIDER_NAME, model.getProviderName()) + .success(); } /** @@ -161,9 +184,16 @@ public class UserFederationResource { auth.requireView(); for (UserFederationProviderModel model : realm.getUserFederationProviders()) { if (model.getId().equals(id)) { + + event.event(EventType.VIEW_PROVIDER) + .detail(Details.PROVIDER_ID, model.getId()) + .detail(Details.PROVIDER_NAME, model.getProviderName()) + .success(); + return ModelToRepresentation.toRepresentation(model); } } + throw new NotFoundException("could not find provider"); } @@ -179,6 +209,11 @@ public class UserFederationResource { UserFederationProviderModel model = new UserFederationProviderModel(id, null, null, -1, null, -1, -1, 0); realm.removeUserFederationProvider(model); new UsersSyncManager().removePeriodicSyncForProvider(session.getProvider(TimerProvider.class), model); + + event.event(EventType.DELETE_PROVIDER) + .detail(Details.PROVIDER_ID, model.getId()) + .detail(Details.PROVIDER_NAME, model.getProviderName()) + .success(); } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java index e860ea8d84..f66ec2e21c 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java @@ -7,6 +7,9 @@ import org.jboss.resteasy.spi.NotFoundException; import org.keycloak.ClientConnection; import org.keycloak.email.EmailException; import org.keycloak.email.EmailProvider; +import org.keycloak.events.Details; +import org.keycloak.events.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.models.ApplicationModel; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientSessionModel; @@ -24,7 +27,6 @@ import org.keycloak.models.UserSessionModel; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.utils.RedirectUtils; import org.keycloak.representations.idm.ApplicationMappingsRepresentation; @@ -57,6 +59,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; + import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -79,6 +82,8 @@ public class UsersResource { private RealmAuth auth; private TokenManager tokenManager; + + private EventBuilder event; @Context protected ClientConnection clientConnection; @@ -91,11 +96,12 @@ public class UsersResource { @Context protected HttpHeaders headers; - - public UsersResource(RealmModel realm, RealmAuth auth, TokenManager tokenManager) { + + public UsersResource(RealmModel realm, RealmAuth auth, TokenManager tokenManager, EventBuilder event) { this.auth = auth; this.realm = realm; this.tokenManager = tokenManager; + this.event = event; auth.init(RealmAuth.Resource.USER); } @@ -120,10 +126,15 @@ public class UsersResource { } updateUserFromRep(user, rep); + event.event(EventType.UPDATE_USER) + .user(user) + .detail(Details.USERNAME, user.getUsername()) + .success(); + if (session.getTransaction().isActive()) { session.getTransaction().commit(); } - + return Response.noContent().build(); } catch (ModelDuplicateException e) { return Flows.errors().exists("User exists with same username or email"); @@ -155,11 +166,16 @@ public class UsersResource { try { UserModel user = session.users().addUser(realm, rep.getUsername()); updateUserFromRep(user, rep); - + + event.event(EventType.CREATE_USER) + .user(user) + .detail(Details.USERNAME, user.getUsername()) + .success(); + if (session.getTransaction().isActive()) { session.getTransaction().commit(); } - + return Response.created(uriInfo.getAbsolutePathBuilder().path(user.getUsername()).build()).build(); } catch (ModelDuplicateException e) { if (session.getTransaction().isActive()) { @@ -220,6 +236,12 @@ public class UsersResource { if (user == null) { throw new NotFoundException("User not found"); } + + event.event(EventType.VIEW_USER) + .user(user) + .detail(Details.USERNAME, user.getUsername()) + .success(); + return ModelToRepresentation.toRepresentation(user); } @@ -245,6 +267,12 @@ public class UsersResource { UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session); reps.add(rep); } + + event.event(EventType.VIEW_USER_SESSIONS) + .user(user) + .detail(Details.USERNAME, user.getUsername()) + .success(); + return reps; } @@ -276,6 +304,12 @@ public class UsersResource { } } } + + event.event(EventType.VIEW_USER_SOCIAL_LOGINS) + .user(user) + .detail(Details.USERNAME, user.getUsername()) + .success(); + return result; } @@ -326,10 +360,16 @@ public class UsersResource { if (user == null) { throw new NotFoundException("User not found"); } + List userSessions = session.sessions().getUserSessions(realm, user); for (UserSessionModel userSession : userSessions) { AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers); } + + event.event(EventType.INVALIDATE_USER_SESSIONS) + .user(user) + .detail(Details.USERNAME, user.getUsername()) + .success(); } /** @@ -350,6 +390,12 @@ public class UsersResource { boolean removed = new UserManager(session).removeUser(realm, user); if (removed) { + + event.event(EventType.DELETE_USER) + .user(user) + .detail(Details.USERNAME, user.getUsername()) + .success(); + return Response.noContent().build(); } else { return Flows.errors().error("User couldn't be deleted", Response.Status.BAD_REQUEST); 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 f5f81ffc36..b82c73a9c7 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 @@ -6,6 +6,7 @@ import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import org.keycloak.events.Event; +import org.keycloak.events.EventGroup; import org.keycloak.events.EventStoreProvider; import org.keycloak.events.EventType; import org.keycloak.models.KeycloakSession; @@ -185,6 +186,7 @@ public class EventStoreProviderTest { Event e = new Event(); e.setTime(time); e.setType(event); + e.setEventGroup(EventGroup.USER); e.setRealmId(realmId); e.setClientId(clientId); e.setUserId(userId);