Added JPA audit provider£
This commit is contained in:
parent
1e15e97d17
commit
722a077de7
20 changed files with 628 additions and 40 deletions
|
@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.provider.ProviderFactoryLoader;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -20,14 +21,17 @@ public class Audit {
|
||||||
private Event event;
|
private Event event;
|
||||||
|
|
||||||
public static Audit create(RealmModel realm, String ipAddress) {
|
public static Audit create(RealmModel realm, String ipAddress) {
|
||||||
|
ProviderFactoryLoader<AuditListenerFactory> loader = ProviderFactoryLoader.load(AuditListenerFactory.class);
|
||||||
|
|
||||||
List<AuditListener> listeners = null;
|
List<AuditListener> listeners = null;
|
||||||
if (realm.getAuditListeners() != null) {
|
if (realm.getAuditListeners() != null) {
|
||||||
listeners = new LinkedList<AuditListener>();
|
listeners = new LinkedList<AuditListener>();
|
||||||
|
|
||||||
for (String id : realm.getAuditListeners()) {
|
for (String id : realm.getAuditListeners()) {
|
||||||
listeners.add(AuditLoader.load(id));
|
listeners.add(loader.find(id).create());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Audit(listeners, new Event()).realm(realm).ipAddress(ipAddress);
|
return new Audit(listeners, new Event()).realm(realm).ipAddress(ipAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package org.keycloak.audit;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface AuditListener {
|
public interface AuditListener extends Provider {
|
||||||
|
|
||||||
public String getId();
|
|
||||||
|
|
||||||
public void onEvent(Event event);
|
public void onEvent(Event event);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.keycloak.audit;
|
||||||
|
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public interface AuditListenerFactory extends ProviderFactory<AuditListener> {
|
||||||
|
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
package org.keycloak.audit;
|
|
||||||
|
|
||||||
import org.keycloak.util.ProviderLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class AuditLoader {
|
|
||||||
|
|
||||||
private AuditLoader() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AuditListener load(String id) {
|
|
||||||
if (id == null) {
|
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (AuditListener l : load()) {
|
|
||||||
if (id.equals(l.getId())) {
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Iterable<AuditListener> load() {
|
|
||||||
return ProviderLoader.load(AuditListener.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.keycloak.audit;
|
||||||
|
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public interface AuditProviderFactory extends ProviderFactory<AuditProvider> {
|
||||||
|
|
||||||
|
}
|
|
@ -11,11 +11,10 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public class JBossLoggingAuditListener implements AuditListener {
|
public class JBossLoggingAuditListener implements AuditListener {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger("org.keycloak.audit");
|
private final Logger logger;
|
||||||
|
|
||||||
@Override
|
public JBossLoggingAuditListener(Logger logger) {
|
||||||
public String getId() {
|
this.logger = logger;
|
||||||
return "jboss-logging";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -60,4 +59,8 @@ public class JBossLoggingAuditListener implements AuditListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.keycloak.audit.log;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.audit.AuditListener;
|
||||||
|
import org.keycloak.audit.AuditListenerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
|
||||||
|
|
||||||
|
public static final String ID = "jboss-logging";
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger("org.keycloak.audit");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuditListener create() {
|
||||||
|
return new JBossLoggingAuditListener(logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
org.keycloak.audit.log.JBossLoggingAuditListener
|
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.audit.log.JBossLoggingAuditListenerFactory
|
|
@ -19,11 +19,37 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-audit-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
|
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-entitymanager</artifactId>
|
||||||
|
<version>${hibernate.entitymanager.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class EventEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private long time;
|
||||||
|
|
||||||
|
private String event;
|
||||||
|
|
||||||
|
private String realmId;
|
||||||
|
|
||||||
|
private String clientId;
|
||||||
|
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
private String ipAddress;
|
||||||
|
|
||||||
|
private String error;
|
||||||
|
|
||||||
|
private String detailsJson;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTime(long time) {
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEvent() {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvent(String event) {
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRealmId() {
|
||||||
|
return realmId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRealmId(String realmId) {
|
||||||
|
this.realmId = realmId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIpAddress() {
|
||||||
|
return ipAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIpAddress(String ipAddress) {
|
||||||
|
this.ipAddress = ipAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setError(String error) {
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetailsJson() {
|
||||||
|
return detailsJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetailsJson(String detailsJson) {
|
||||||
|
this.detailsJson = detailsJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.keycloak.audit.AuditProvider;
|
||||||
|
import org.keycloak.audit.Event;
|
||||||
|
import org.keycloak.audit.EventQuery;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class JpaAuditProvider implements AuditProvider {
|
||||||
|
|
||||||
|
private EntityManager em;
|
||||||
|
|
||||||
|
public JpaAuditProvider(EntityManager em) {
|
||||||
|
this.em = em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EventQuery createQuery() {
|
||||||
|
return new JpaEventQuery(em);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(Event event) {
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(convert(event));
|
||||||
|
em.getTransaction().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
static EventEntity convert(Event o) {
|
||||||
|
EventEntity e = new EventEntity();
|
||||||
|
e.setId(UUID.randomUUID().toString());
|
||||||
|
e.setTime(o.getTime());
|
||||||
|
e.setEvent(o.getEvent());
|
||||||
|
e.setRealmId(o.getRealmId());
|
||||||
|
e.setClientId(o.getClientId());
|
||||||
|
e.setUserId(o.getUserId());
|
||||||
|
e.setIpAddress(o.getIpAddress());
|
||||||
|
e.setError(o.getError());
|
||||||
|
e.setDetailsJson(new JSONObject(o.getDetails()).toString());
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Event convert(EventEntity o) {
|
||||||
|
Event e = new Event();
|
||||||
|
e.setTime(o.getTime());
|
||||||
|
e.setEvent(o.getEvent());
|
||||||
|
e.setRealmId(o.getRealmId());
|
||||||
|
e.setClientId(o.getClientId());
|
||||||
|
e.setUserId(o.getUserId());
|
||||||
|
e.setIpAddress(o.getIpAddress());
|
||||||
|
e.setError(o.getError());
|
||||||
|
|
||||||
|
JSONObject object = new JSONObject(o.getDetailsJson());
|
||||||
|
Map<String, String> details = new HashMap<String, String>();
|
||||||
|
for (Object k : object.keySet()) {
|
||||||
|
details.put((String) k, object.getString((String) k));
|
||||||
|
}
|
||||||
|
|
||||||
|
e.setDetails(details);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
|
import org.keycloak.audit.AuditProvider;
|
||||||
|
import org.keycloak.audit.AuditProviderFactory;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
import javax.persistence.Persistence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class JpaAuditProviderFactory implements AuditProviderFactory {
|
||||||
|
|
||||||
|
public static final String ID = "jpa";
|
||||||
|
private EntityManagerFactory emf;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuditProvider create() {
|
||||||
|
return new JpaAuditProvider(emf.createEntityManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
emf = Persistence.createEntityManagerFactory("jpa-keycloak-audit-store");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
emf.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
|
import org.keycloak.audit.Event;
|
||||||
|
import org.keycloak.audit.EventQuery;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.TypedQuery;
|
||||||
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
import javax.persistence.criteria.Predicate;
|
||||||
|
import javax.persistence.criteria.Root;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class JpaEventQuery implements EventQuery {
|
||||||
|
|
||||||
|
private final EntityManager em;
|
||||||
|
private final CriteriaBuilder cb;
|
||||||
|
private final CriteriaQuery<EventEntity> cq;
|
||||||
|
private final Root<EventEntity> root;
|
||||||
|
private final ArrayList<Predicate> predicates;
|
||||||
|
private Integer firstResult;
|
||||||
|
private Integer maxResults;
|
||||||
|
|
||||||
|
public JpaEventQuery(EntityManager em) {
|
||||||
|
this.em = em;
|
||||||
|
|
||||||
|
cb = em.getCriteriaBuilder();
|
||||||
|
cq = cb.createQuery(EventEntity.class);
|
||||||
|
root = cq.from(EventEntity.class);
|
||||||
|
predicates = new ArrayList<Predicate>(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EventQuery event(String event) {
|
||||||
|
predicates.add(cb.equal(root.get("event"), event));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EventQuery realm(String realmId) {
|
||||||
|
predicates.add(cb.equal(root.get("realmId"), realmId));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EventQuery client(String clientId) {
|
||||||
|
predicates.add(cb.equal(root.get("clientId"), clientId));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EventQuery user(String userId) {
|
||||||
|
predicates.add(cb.equal(root.get("userId"), userId));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EventQuery firstResult(int firstResult) {
|
||||||
|
this.firstResult = firstResult;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EventQuery maxResults(int maxResults) {
|
||||||
|
this.maxResults = maxResults;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Event> getResultList() {
|
||||||
|
if (!predicates.isEmpty()) {
|
||||||
|
cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
|
||||||
|
}
|
||||||
|
|
||||||
|
cq.orderBy(cb.asc(root.get("time")), cb.asc(root.get("id")));
|
||||||
|
|
||||||
|
TypedQuery<EventEntity> query = em.createQuery(cq);
|
||||||
|
|
||||||
|
if (firstResult != null) {
|
||||||
|
query.setFirstResult(firstResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxResults != null) {
|
||||||
|
query.setMaxResults(maxResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Event> events = new LinkedList<Event>();
|
||||||
|
for (EventEntity e : query.getResultList()) {
|
||||||
|
events.add(JpaAuditProvider.convert(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.audit.jpa.JpaAuditProviderFactory
|
|
@ -0,0 +1,80 @@
|
||||||
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.audit.AuditProvider;
|
||||||
|
import org.keycloak.audit.AuditProviderFactory;
|
||||||
|
import org.keycloak.audit.Event;
|
||||||
|
import org.keycloak.provider.ProviderFactoryLoader;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class JpaAuditProviderTest {
|
||||||
|
|
||||||
|
private AuditProviderFactory factory;
|
||||||
|
private AuditProvider provider;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
ProviderFactoryLoader<AuditProviderFactory> loader = ProviderFactoryLoader.load(AuditProviderFactory.class);
|
||||||
|
factory = loader.find(JpaAuditProviderFactory.ID);
|
||||||
|
factory.init();
|
||||||
|
|
||||||
|
provider = factory.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
factory.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void save() {
|
||||||
|
provider.onEvent(create("event", "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void query() {
|
||||||
|
provider.onEvent(create("event", "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create("event2", "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create("event", "realmId2", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create("event", "realmId", "clientId2", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create("event", "realmId", "clientId", "userId2", "127.0.0.1", "error"));
|
||||||
|
|
||||||
|
Assert.assertEquals(4, provider.createQuery().client("clientId").getResultList().size());
|
||||||
|
Assert.assertEquals(4, provider.createQuery().realm("realmId").getResultList().size());
|
||||||
|
Assert.assertEquals(4, provider.createQuery().event("event").getResultList().size());
|
||||||
|
Assert.assertEquals(4, provider.createQuery().user("userId").getResultList().size());
|
||||||
|
|
||||||
|
Assert.assertEquals(1, provider.createQuery().user("userId").event("event2").getResultList().size());
|
||||||
|
|
||||||
|
Assert.assertEquals(2, provider.createQuery().maxResults(2).getResultList().size());
|
||||||
|
Assert.assertEquals(1, provider.createQuery().firstResult(4).getResultList().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Event create(String event, String realmId, String clientId, String userId, String ipAddress, String error) {
|
||||||
|
Event e = new Event();
|
||||||
|
e.setTime(System.currentTimeMillis());
|
||||||
|
e.setEvent(event);
|
||||||
|
e.setRealmId(realmId);
|
||||||
|
e.setClientId(clientId);
|
||||||
|
e.setUserId(userId);
|
||||||
|
e.setIpAddress(ipAddress);
|
||||||
|
e.setError(error);
|
||||||
|
|
||||||
|
Map<String, String> details = new HashMap<String, String>();
|
||||||
|
details.put("key1", "value1");
|
||||||
|
details.put("key2", "value2");
|
||||||
|
|
||||||
|
e.setDetails(details);
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
audit/jpa/src/src/test/resources/META-INF/persistence.xml
Executable file
22
audit/jpa/src/src/test/resources/META-INF/persistence.xml
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
|
||||||
|
version="1.0">
|
||||||
|
<persistence-unit name="jpa-keycloak-audit-store" transaction-type="RESOURCE_LOCAL">
|
||||||
|
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
||||||
|
|
||||||
|
<class>org.keycloak.audit.jpa.EventEntity</class>
|
||||||
|
|
||||||
|
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<property name="hibernate.connection.url" value="jdbc:h2:mem:test"/>
|
||||||
|
<property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
|
||||||
|
<property name="hibernate.connection.username" value="sa"/>
|
||||||
|
<property name="hibernate.connection.password" value=""/>
|
||||||
|
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
|
||||||
|
<property name="hibernate.show_sql" value="false" />
|
||||||
|
<property name="hibernate.format_sql" value="true" />
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
</persistence>
|
10
core/src/main/java/org/keycloak/provider/Provider.java
Normal file
10
core/src/main/java/org/keycloak/provider/Provider.java
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package org.keycloak.provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public interface Provider {
|
||||||
|
|
||||||
|
public void close();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.keycloak.provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public interface ProviderFactory<T extends Provider> {
|
||||||
|
|
||||||
|
public T create();
|
||||||
|
|
||||||
|
public void init();
|
||||||
|
|
||||||
|
public void close();
|
||||||
|
|
||||||
|
public String getId();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package org.keycloak.provider;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class ProviderFactoryLoader<P extends ProviderFactory> implements Iterable<P> {
|
||||||
|
|
||||||
|
private ServiceLoader<P> serviceLoader;
|
||||||
|
|
||||||
|
private ProviderFactoryLoader(ServiceLoader<P> serviceLoader) {
|
||||||
|
this.serviceLoader = serviceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <P extends ProviderFactory> ProviderFactoryLoader<P> load(Class<P> service) {
|
||||||
|
return new ProviderFactoryLoader(ServiceLoader.load(service));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <P extends ProviderFactory> ProviderFactoryLoader<P> load(Class<P> service, ClassLoader loader) {
|
||||||
|
return new ProviderFactoryLoader(ServiceLoader.load(service, loader));
|
||||||
|
}
|
||||||
|
|
||||||
|
public P find(String id) {
|
||||||
|
Iterator<P> itr = iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
P p = itr.next();
|
||||||
|
if (p.getId() != null && p.getId().equals(id)) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<P> iterator() {
|
||||||
|
return new ProviderFactoryIterator(serviceLoader.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ProviderFactoryIterator<P> implements Iterator<P> {
|
||||||
|
|
||||||
|
private Iterator<P> itr;
|
||||||
|
|
||||||
|
private P next;
|
||||||
|
|
||||||
|
private ProviderFactoryIterator(Iterator<P> itr) {
|
||||||
|
this.itr = itr;
|
||||||
|
setNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return next != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public P next() {
|
||||||
|
P n = next;
|
||||||
|
setNext();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setNext() {
|
||||||
|
next = null;
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
if (itr.hasNext()) {
|
||||||
|
P n = itr.next();
|
||||||
|
if (!System.getProperties().containsKey(n.getClass().getName() + ".disabled")) {
|
||||||
|
next = n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue