Infinispan Protostream Marshaller (#29474)

Closes #29394

Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
Pedro Ruivo 2024-06-13 17:02:46 +01:00 committed by GitHub
parent ca0833b2e4
commit 18a6c79011
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
134 changed files with 2617 additions and 4553 deletions

View file

@ -9,3 +9,12 @@ to different organizations.
When creating a social broker, you should now provide an `Alias` and optionally a `Display name` just like any other
broker.
= Infinispan marshalling changes to Infinispan Protostream
Marshalling is the process of converting Java objects into bytes to send them across the network between {project_name} servers.
With {project_name} 26, we changed the marshalling format from JBoss Marshalling to Infinispan Protostream.
WARNING: JBoss Marshalling and Infinispan Protostream are not compatible with each other and incorrect usage may lead to data loss.
Consequently, all caches are cleared when upgrading to this version.
Infinispan Protostream is based on https://protobuf.dev/programming-guides/proto3/[Protocol Buffers] (proto 3), which has the advantage of backwards/forwards compatibility.

View file

@ -0,0 +1,10 @@
= Infinispan marshalling changes
Marshalling is the process of converting Java objects into bytes to send them across the network between {project_name} servers.
With {project_name} 26, the marshalling library has changed from JBoss Marshalling to Infinispan Protostream.
The libraries are not compatible between each other and, it requires some steps to ensure the session data is not lost.
WARNING: JBoss Marshalling and Infinispan Protostream are not compatible with each other and incorrect usage may lead to data loss.
Consequently, all caches are cleared when upgrading to this version.
To prevent losing user sessions upgrade to Keycloak 25 first and enable the persistent sessions feature as outlined in the migration guide for {project_name} 25.

View file

@ -1,6 +1,10 @@
[[migration-changes]]
== Migration Changes
=== Migrating to 26.0.0
include::changes-26_0_0.adoc[leveloffset=3]
=== Migrating to 25.0.0
include::changes-25_0_0.adoc[leveloffset=3]

View file

@ -67,7 +67,23 @@
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-jboss-marshalling</artifactId>
<artifactId>infinispan-component-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.infinispan.protostream</groupId>
<artifactId>protostream</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan.protostream</groupId>
<artifactId>protostream-types</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan.protostream</groupId>
<artifactId>protostream-processor</artifactId>
<!-- compile-only dependency -->
<scope>provided</scope>
</dependency>
<dependency>

View file

@ -17,7 +17,6 @@
package org.keycloak.cluster.infinispan;
import java.io.Serializable;
import java.util.Set;
import org.infinispan.Cache;
@ -35,10 +34,10 @@ abstract class CrossDCAwareCacheFactory {
protected static final Logger logger = Logger.getLogger(CrossDCAwareCacheFactory.class);
abstract BasicCache<String, Serializable> getCache();
abstract BasicCache<String, Object> getCache();
static CrossDCAwareCacheFactory getFactory(Cache<String, Serializable> workCache, Set<RemoteStore> remoteStores) {
static CrossDCAwareCacheFactory getFactory(Cache<String, Object> workCache, Set<RemoteStore> remoteStores) {
if (remoteStores.isEmpty()) {
logger.debugf("No configured remoteStore available. Cross-DC scenario is not used");
return new InfinispanCacheWrapperFactory(workCache);
@ -66,14 +65,14 @@ abstract class CrossDCAwareCacheFactory {
// We don't have external JDG configured. No cross-DC.
private static class InfinispanCacheWrapperFactory extends CrossDCAwareCacheFactory {
private final Cache<String, Serializable> workCache;
private final Cache<String, Object> workCache;
InfinispanCacheWrapperFactory(Cache<String, Serializable> workCache) {
InfinispanCacheWrapperFactory(Cache<String, Object> workCache) {
this.workCache = workCache;
}
@Override
BasicCache<String, Serializable> getCache() {
BasicCache<String, Object> getCache() {
return workCache;
}
@ -83,14 +82,14 @@ abstract class CrossDCAwareCacheFactory {
// We have external JDG configured. Cross-DC should be enabled
private static class RemoteCacheWrapperFactory extends CrossDCAwareCacheFactory {
private final RemoteCache<String, Serializable> remoteCache;
private final RemoteCache<String, Object> remoteCache;
RemoteCacheWrapperFactory(RemoteCache<String, Serializable> remoteCache) {
RemoteCacheWrapperFactory(RemoteCache<String, Object> remoteCache) {
this.remoteCache = remoteCache;
}
@Override
BasicCache<String, Serializable> getCache() {
BasicCache<String, Object> getCache() {
// Flags are per-invocation!
return remoteCache.withFlags(Flag.FORCE_RETURN_VALUE);
}

View file

@ -17,18 +17,17 @@
package org.keycloak.cluster.infinispan;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.jboss.logging.Logger;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.cluster.ClusterListener;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.cluster.ExecutionResult;
import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
*
@ -130,26 +129,18 @@ public class InfinispanClusterProvider implements ClusterProvider {
this.notificationsManager.notify(taskKey, event, ignoreSender, dcNotify);
}
private LockEntry createLockEntry() {
LockEntry lock = new LockEntry();
lock.setNode(myAddress);
lock.setTimestamp(Time.currentTime());
return lock;
}
private boolean tryLock(String cacheKey, int taskTimeoutInSeconds) {
LockEntry myLock = createLockEntry();
LockEntry myLock = new LockEntry(myAddress);
LockEntry existingLock = InfinispanClusterProviderFactory.putIfAbsentWithRetries(crossDCAwareCacheFactory, cacheKey, myLock, taskTimeoutInSeconds);
if (existingLock != null) {
if (logger.isTraceEnabled()) {
logger.tracef("Task %s in progress already by node %s. Ignoring task.", cacheKey, existingLock.getNode());
logger.tracef("Task %s in progress already by node %s. Ignoring task.", cacheKey, existingLock.node());
}
return false;
} else {
if (logger.isTraceEnabled()) {
logger.tracef("Successfully acquired lock for task %s. Our node is %s", cacheKey, myLock.getNode());
logger.tracef("Successfully acquired lock for task %s. Our node is %s", cacheKey, myLock.node());
}
return true;
}

View file

@ -38,7 +38,6 @@ import org.keycloak.connections.infinispan.TopologyInfo;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@ -59,7 +58,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
protected static final Logger logger = Logger.getLogger(InfinispanClusterProviderFactory.class);
// Infinispan cache
private volatile Cache<String, Serializable> workCache;
private volatile Cache<String, Object> workCache;
// Ensure that atomic operations (like putIfAbsent) must work correctly in any of: non-clustered, clustered or cross-Data-Center (cross-DC) setups
private CrossDCAwareCacheFactory crossDCAwareCacheFactory;
@ -134,7 +133,7 @@ public class InfinispanClusterProviderFactory implements ClusterProviderFactory
// Will retry few times for the case when backup site not available in cross-dc environment.
// The site might be taken offline automatically if "take-offline" properly configured
static <V extends Serializable> V putIfAbsentWithRetries(CrossDCAwareCacheFactory crossDCAwareCacheFactory, String key, V value, int taskTimeoutInSeconds) {
static <V> V putIfAbsentWithRetries(CrossDCAwareCacheFactory crossDCAwareCacheFactory, String key, V value, int taskTimeoutInSeconds) {
AtomicReference<V> resultRef = new AtomicReference<>();
Retry.executeWithBackoff(iteration -> {

View file

@ -75,7 +75,7 @@ public class InfinispanNotificationsManager {
private final ConcurrentMap<String, TaskCallback> taskCallbacks = new ConcurrentHashMap<>();
private final Cache<String, Serializable> workCache;
private final Cache<String, Object> workCache;
private final RemoteCache<Object, Serializable> workRemoteCache;
@ -85,7 +85,7 @@ public class InfinispanNotificationsManager {
private final ExecutorService listenersExecutor;
protected InfinispanNotificationsManager(Cache<String, Serializable> workCache, RemoteCache<Object, Serializable> workRemoteCache, String myAddress, String mySite, ExecutorService listenersExecutor) {
protected InfinispanNotificationsManager(Cache<String, Object> workCache, RemoteCache<Object, Serializable> workRemoteCache, String myAddress, String mySite, ExecutorService listenersExecutor) {
this.workCache = workCache;
this.workRemoteCache = workRemoteCache;
this.myAddress = myAddress;
@ -95,7 +95,7 @@ public class InfinispanNotificationsManager {
// Create and init manager including all listeners etc
public static InfinispanNotificationsManager create(KeycloakSession session, Cache<String, Serializable> workCache, String myAddress, String mySite, Set<RemoteStore> remoteStores) {
public static InfinispanNotificationsManager create(KeycloakSession session, Cache<String, Object> workCache, String myAddress, String mySite, Set<RemoteStore> remoteStores) {
RemoteCache<Object, Serializable> workRemoteCache = null;
if (!remoteStores.isEmpty()) {
@ -141,13 +141,7 @@ public class InfinispanNotificationsManager {
void notify(String taskKey, ClusterEvent event, boolean ignoreSender, ClusterProvider.DCNotify dcNotify) {
WrapperClusterEvent wrappedEvent = new WrapperClusterEvent();
wrappedEvent.setEventKey(taskKey);
wrappedEvent.setDelegateEvent(event);
wrappedEvent.setIgnoreSender(ignoreSender);
wrappedEvent.setIgnoreSenderSite(dcNotify == ClusterProvider.DCNotify.ALL_BUT_LOCAL_DC);
wrappedEvent.setSender(myAddress);
wrappedEvent.setSenderSite(mySite);
var wrappedEvent = WrapperClusterEvent.wrap(taskKey, event, myAddress, mySite, dcNotify, ignoreSender);
String eventKey = UUID.randomUUID().toString();
@ -186,17 +180,17 @@ public class InfinispanNotificationsManager {
public class CacheEntryListener {
@CacheEntryCreated
public void cacheEntryCreated(CacheEntryCreatedEvent<String, Serializable> event) {
public void cacheEntryCreated(CacheEntryCreatedEvent<String, Object> event) {
eventReceived(event.getKey(), event.getValue());
}
@CacheEntryModified
public void cacheEntryModified(CacheEntryModifiedEvent<String, Serializable> event) {
public void cacheEntryModified(CacheEntryModifiedEvent<String, Object> event) {
eventReceived(event.getKey(), event.getNewValue());
}
@CacheEntryRemoved
public void cacheEntryRemoved(CacheEntryRemovedEvent<String, Serializable> event) {
public void cacheEntryRemoved(CacheEntryRemovedEvent<String, Object> event) {
taskFinished(event.getKey());
}
@ -267,7 +261,7 @@ public class InfinispanNotificationsManager {
}
}
private void eventReceived(String key, Serializable obj) {
private void eventReceived(String key, Object obj) {
if (!(obj instanceof WrapperClusterEvent event)) {
// Items with the TASK_KEY_PREFIX might be gone fast once the locking is complete, therefore, don't log them.
// It is still good to have the warning in case of real events return null because they have been, for example, expired
@ -277,16 +271,8 @@ public class InfinispanNotificationsManager {
return;
}
if (event.isIgnoreSender()) {
if (this.myAddress.equals(event.getSender())) {
return;
}
}
if (event.isIgnoreSenderSite()) {
if (this.mySite == null || this.mySite.equals(event.getSenderSite())) {
return;
}
if (event.rejectEvent(myAddress, mySite)) {
return;
}
String eventKey = event.getEventKey();

View file

@ -17,67 +17,14 @@
package org.keycloak.cluster.infinispan;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import org.infinispan.protostream.annotations.Proto;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(LockEntry.ExternalizerImpl.class)
public class LockEntry implements Serializable {
private String node;
private int timestamp;
public String getNode() {
return node;
}
public void setNode(String node) {
this.node = node;
}
public int getTimestamp() {
return timestamp;
}
public void setTimestamp(int timestamp) {
this.timestamp = timestamp;
}
public static class ExternalizerImpl implements Externalizer<LockEntry> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, LockEntry obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.node, output);
KeycloakMarshallUtil.marshall(obj.timestamp, output);
}
@Override
public LockEntry readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public LockEntry readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
LockEntry entry = new LockEntry();
entry.setNode(MarshallUtil.unmarshallString(input));
entry.setTimestamp(KeycloakMarshallUtil.unmarshallInteger(input));
return entry;
}
}
@ProtoTypeId(Marshalling.LOCK_ENTRY)
@Proto
public record LockEntry(String node) {
}

View file

@ -18,67 +18,38 @@
package org.keycloak.cluster.infinispan;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(LockEntryPredicate.ExternalizerImpl.class)
public class LockEntryPredicate implements Predicate<Map.Entry<String, Serializable>> {
@ProtoTypeId(Marshalling.LOCK_ENTRY_PREDICATE)
public class LockEntryPredicate implements Predicate<Map.Entry<String, Object>> {
private final Set<String> removedNodesAddresses;
@ProtoFactory
public LockEntryPredicate(Set<String> removedNodesAddresses) {
this.removedNodesAddresses = removedNodesAddresses;
}
@ProtoField(value = 1, collectionImplementation = HashSet.class)
Set<String> getRemovedNodesAddresses() {
return removedNodesAddresses;
}
@Override
public boolean test(Map.Entry<String, Serializable> entry) {
if (!(entry.getValue() instanceof LockEntry)) {
return false;
}
public boolean test(Map.Entry<String, Object> entry) {
return entry.getValue() instanceof LockEntry lock &&
removedNodesAddresses.contains(lock.node());
LockEntry lock = (LockEntry) entry.getValue();
return removedNodesAddresses.contains(lock.getNode());
}
public static class ExternalizerImpl implements Externalizer<LockEntryPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, LockEntryPredicate obj) throws IOException {
output.writeByte(VERSION_1);
KeycloakMarshallUtil.writeCollection(obj.removedNodesAddresses, KeycloakMarshallUtil.STRING_EXT, output);
}
@Override
public LockEntryPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public LockEntryPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
return new LockEntryPredicate(
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet)
);
}
}
}

View file

@ -17,134 +17,124 @@
package org.keycloak.cluster.infinispan;
import org.keycloak.cluster.ClusterEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.WrappedMessage;
import org.infinispan.protostream.annotations.Proto;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.marshalling.Marshalling;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(WrapperClusterEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.WRAPPED_CLUSTER_EVENT)
public class WrapperClusterEvent implements ClusterEvent {
private String eventKey;
private String sender;
private String senderSite;
private boolean ignoreSender;
private boolean ignoreSenderSite;
private ClusterEvent delegateEvent;
@ProtoField(1)
final String eventKey;
@ProtoField(2)
final String senderAddress; // null means invoke everywhere
@ProtoField(3)
final String senderSite; // can be null
@ProtoField(4)
final SiteFilter siteFilter;
final ClusterEvent delegateEvent;
private WrapperClusterEvent(String eventKey, String senderAddress, String senderSite, SiteFilter siteFilter, ClusterEvent delegateEvent) {
this.eventKey = Objects.requireNonNull(eventKey);
this.senderAddress = senderAddress;
this.senderSite = senderSite;
this.siteFilter = Objects.requireNonNull(siteFilter);
this.delegateEvent = Objects.requireNonNull(delegateEvent);
}
@ProtoFactory
static WrapperClusterEvent protoFactory(String eventKey, String senderAddress, String senderSite, SiteFilter siteFilter, WrappedMessage eventPS) {
return new WrapperClusterEvent(eventKey, Marshalling.emptyStringToNull(senderAddress), Marshalling.emptyStringToNull(senderSite), siteFilter, (ClusterEvent) eventPS.getValue());
}
public static WrapperClusterEvent wrap(String eventKey, ClusterEvent event, String senderAddress, String senderSite, ClusterProvider.DCNotify dcNotify, boolean ignoreSender) {
senderAddress = ignoreSender ? Objects.requireNonNull(senderAddress) : null;
senderSite = dcNotify == ClusterProvider.DCNotify.ALL_DCS ? null : senderSite;
var siteNotification = switch (dcNotify) {
case ALL_DCS -> SiteFilter.ALL;
case LOCAL_DC_ONLY -> SiteFilter.LOCAL;
case ALL_BUT_LOCAL_DC -> SiteFilter.REMOTE;
};
return new WrapperClusterEvent(eventKey, senderAddress, senderSite, siteNotification, event);
}
@ProtoField(5)
WrappedMessage getEventPS() {
return new WrappedMessage(delegateEvent);
}
public String getEventKey() {
return eventKey;
}
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getSenderSite() {
return senderSite;
}
public void setSenderSite(String senderSite) {
this.senderSite = senderSite;
}
public boolean isIgnoreSender() {
return ignoreSender;
}
public void setIgnoreSender(boolean ignoreSender) {
this.ignoreSender = ignoreSender;
}
public boolean isIgnoreSenderSite() {
return ignoreSenderSite;
}
public void setIgnoreSenderSite(boolean ignoreSenderSite) {
this.ignoreSenderSite = ignoreSenderSite;
}
public ClusterEvent getDelegateEvent() {
return delegateEvent;
}
public void setDelegateEvent(ClusterEvent delegateEvent) {
this.delegateEvent = delegateEvent;
public boolean rejectEvent(String mySiteAddress, String mySiteName) {
return (senderAddress != null && senderAddress.equals(mySiteAddress)) ||
(senderSite != null && siteFilter.reject(senderSite, mySiteName));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WrapperClusterEvent that = (WrapperClusterEvent) o;
return ignoreSender == that.ignoreSender && ignoreSenderSite == that.ignoreSenderSite && Objects.equals(eventKey, that.eventKey) && Objects.equals(sender, that.sender) && Objects.equals(senderSite, that.senderSite) && Objects.equals(delegateEvent, that.delegateEvent);
return eventKey.equals(that.eventKey) &&
Objects.equals(senderAddress, that.senderAddress) &&
Objects.equals(senderSite, that.senderSite) &&
siteFilter == that.siteFilter &&
delegateEvent.equals(that.delegateEvent);
}
@Override
public int hashCode() {
return Objects.hash(eventKey, sender, senderSite, ignoreSender, ignoreSenderSite, delegateEvent);
int result = eventKey.hashCode();
result = 31 * result + Objects.hashCode(senderAddress);
result = 31 * result + Objects.hashCode(senderSite);
result = 31 * result + siteFilter.hashCode();
result = 31 * result + delegateEvent.hashCode();
return result;
}
@Override
public String toString() {
return String.format("WrapperClusterEvent [ eventKey=%s, sender=%s, senderSite=%s, delegateEvent=%s ]", eventKey, sender, senderSite, delegateEvent.toString());
return String.format("WrapperClusterEvent [ eventKey=%s, sender=%s, senderSite=%s, delegateEvent=%s ]", eventKey, senderAddress, senderSite, delegateEvent);
}
public static class ExternalizerImpl implements Externalizer<WrapperClusterEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, WrapperClusterEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.eventKey, output);
MarshallUtil.marshallString(obj.sender, output);
MarshallUtil.marshallString(obj.senderSite, output);
output.writeBoolean(obj.ignoreSender);
output.writeBoolean(obj.ignoreSenderSite);
output.writeObject(obj.delegateEvent);
}
@Override
public WrapperClusterEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
@Proto
@ProtoTypeId(Marshalling.WRAPPED_CLUSTER_EVENT_SITE_FILTER)
public enum SiteFilter {
ALL {
@Override
boolean reject(String senderSite, String mySite) {
return false;
}
}
}, LOCAL {
@Override
boolean reject(String senderSite, String mySite) {
return !Objects.equals(senderSite, mySite);
}
}, REMOTE {
@Override
boolean reject(String senderSite, String mySite) {
return Objects.equals(senderSite, mySite);
}
};
public WrapperClusterEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
WrapperClusterEvent res = new WrapperClusterEvent();
res.eventKey = MarshallUtil.unmarshallString(input);
res.sender = MarshallUtil.unmarshallString(input);
res.senderSite = MarshallUtil.unmarshallString(input);
res.ignoreSender = input.readBoolean();
res.ignoreSenderSite = input.readBoolean();
res.delegateEvent = (ClusterEvent) input.readObject();
return res;
}
abstract boolean reject(String senderSite, String mySite);
}
}

View file

@ -17,9 +17,14 @@
package org.keycloak.connections.infinispan;
import java.util.concurrent.CompletionStage;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.commons.util.concurrent.CompletionStages;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.manager.PersistenceManager;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -36,6 +41,14 @@ public class DefaultInfinispanConnectionProvider implements InfinispanConnection
this.topologyInfo = topologyInfo;
}
private static PersistenceManager persistenceManager(Cache<?, ?> cache) {
return ComponentRegistry.componentOf(cache, PersistenceManager.class);
}
private static CompletionStage<Void> clearPersistenceManager(PersistenceManager persistenceManager) {
return persistenceManager.clearAllStores(PersistenceManager.AccessMode.BOTH);
}
@Override
public <K, V> Cache<K, V> getCache(String name, boolean createIfAbsent) {
return cacheManager.getCache(name, createIfAbsent);
@ -51,6 +64,19 @@ public class DefaultInfinispanConnectionProvider implements InfinispanConnection
return topologyInfo;
}
@Override
public CompletionStage<Void> migrateToProtostream() {
// Only the CacheStore (persistence) stores data in binary format and needs to be deleted.
// We assume rolling-upgrade between KC 25 and KC 26 is not available, in other words, KC 25 and KC 26 servers are not present in the same cluster.
var stage = CompletionStages.aggregateCompletionStage();
DISTRIBUTED_REPLICATED_CACHE_NAMES.stream()
.map(this::getCache)
.map(DefaultInfinispanConnectionProvider::persistenceManager)
.map(DefaultInfinispanConnectionProvider::clearPersistenceManager)
.forEach(stage::dependsOn);
return stage.freeze();
}
@Override
public void close() {
}

View file

@ -238,7 +238,8 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
if (clustered) {
String jgroupsUdpMcastAddr = config.get("jgroupsUdpMcastAddr", System.getProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR));
configureTransport(gcb, topologyInfo.getMyNodeName(), topologyInfo.getMySiteName(), jgroupsUdpMcastAddr,
String jgroupsBindAddr = config.get("jgroupsBindAddr", System.getProperty(InfinispanConnectionProvider.JGROUPS_BIND_ADDR));
configureTransport(gcb, topologyInfo.getMyNodeName(), topologyInfo.getMySiteName(), jgroupsUdpMcastAddr, jgroupsBindAddr,
"default-configs/default-keycloak-jgroups-udp.xml");
gcb.jmx()
.domain(InfinispanConnectionProvider.JMX_DOMAIN + "-" + topologyInfo.getMyNodeName()).enable();

View file

@ -18,6 +18,8 @@
package org.keycloak.connections.infinispan;
import java.util.List;
import java.util.concurrent.CompletionStage;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.keycloak.provider.Provider;
@ -57,7 +59,8 @@ public interface InfinispanConnectionProvider extends Provider {
// System property used on Wildfly to identify distributedCache address and sticky session route
String JBOSS_NODE_NAME = "jboss.node.name";
String JGROUPS_UDP_MCAST_ADDR = "jgroups.udp.mcast_addr";
String JGROUPS_UDP_MCAST_ADDR = "jgroups.mcast_addr";
String JGROUPS_BIND_ADDR = "jgroups.bind.address";
// TODO This property is not in Wildfly. Check if corresponding property in Wildfly exists
String JBOSS_SITE_NAME = "jboss.site.name";
@ -127,4 +130,11 @@ public interface InfinispanConnectionProvider extends Provider {
*/
TopologyInfo getTopologyInfo();
/**
* Migrates the JBoss Marshalling encoding to Infinispan Protostream
*
* @return A {@link CompletionStage} to signal when the operator is completed.
*/
CompletionStage<Void> migrateToProtostream();
}

View file

@ -102,7 +102,7 @@ public class InfinispanUtil {
private static final Object CHANNEL_INIT_SYNCHRONIZER = new Object();
public static void configureTransport(GlobalConfigurationBuilder gcb, String nodeName, String siteName, String jgroupsUdpMcastAddr,
String jgroupsConfigPath) {
String jgroupsBindAddr, String jgroupsConfigPath) {
if (nodeName == null) {
gcb.transport().defaultTransport();
} else {
@ -115,6 +115,12 @@ public class InfinispanUtil {
} else {
System.setProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR, jgroupsUdpMcastAddr);
}
var originalBindAddr = System.getProperty(InfinispanConnectionProvider.JGROUPS_BIND_ADDR);
if (jgroupsBindAddr == null) {
System.getProperties().remove(InfinispanConnectionProvider.JGROUPS_BIND_ADDR);
} else {
System.setProperty(InfinispanConnectionProvider.JGROUPS_BIND_ADDR, jgroupsBindAddr);
}
try {
JChannel channel = new JChannel(fileLookup.lookupFileLocation(jgroupsConfigPath, InfinispanUtil.class.getClassLoader()).openStream());
channel.setName(nodeName);
@ -144,6 +150,11 @@ public class InfinispanUtil {
} else {
System.setProperty(InfinispanConnectionProvider.JGROUPS_UDP_MCAST_ADDR, originalMcastAddr);
}
if (originalBindAddr == null) {
System.getProperties().remove(InfinispanConnectionProvider.JGROUPS_BIND_ADDR);
} else {
System.setProperty(InfinispanConnectionProvider.JGROUPS_BIND_ADDR, originalBindAddr);
}
}
}
}

View file

@ -17,69 +17,33 @@
package org.keycloak.keys.infinispan;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(PublicKeyStorageInvalidationEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.PUBLIC_KEY_INVALIDATION_EVENT)
public class PublicKeyStorageInvalidationEvent extends InvalidationEvent {
private String cacheKey;
public static PublicKeyStorageInvalidationEvent create(String cacheKey) {
PublicKeyStorageInvalidationEvent event = new PublicKeyStorageInvalidationEvent();
event.cacheKey = cacheKey;
return event;
private PublicKeyStorageInvalidationEvent(String cacheKey) {
super(cacheKey);
}
@Override
public String getId() {
return cacheKey;
@ProtoFactory
public static PublicKeyStorageInvalidationEvent create(String id) {
return new PublicKeyStorageInvalidationEvent(id);
}
public String getCacheKey() {
return cacheKey;
return getId();
}
@Override
public String toString() {
return "PublicKeyStorageInvalidationEvent [ " + cacheKey + " ]";
}
public static class ExternalizerImpl implements Externalizer<PublicKeyStorageInvalidationEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, PublicKeyStorageInvalidationEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.cacheKey, output);
}
@Override
public PublicKeyStorageInvalidationEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public PublicKeyStorageInvalidationEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
PublicKeyStorageInvalidationEvent res = new PublicKeyStorageInvalidationEvent();
res.cacheKey = MarshallUtil.unmarshallString(input);
return res;
}
return "PublicKeyStorageInvalidationEvent [ " + getId() + " ]";
}
}

View file

@ -17,13 +17,12 @@
package org.keycloak.keys.infinispan;
import java.io.Serializable;
import org.keycloak.crypto.PublicKeysWrapper;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class PublicKeysEntry implements Serializable {
public class PublicKeysEntry {
private final int lastRequestTime;

View file

@ -0,0 +1,200 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.marshalling;
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.ProtoSchema;
import org.infinispan.protostream.annotations.ProtoSyntax;
import org.infinispan.protostream.types.java.CommonTypes;
import org.keycloak.cluster.infinispan.LockEntry;
import org.keycloak.cluster.infinispan.LockEntryPredicate;
import org.keycloak.cluster.infinispan.WrapperClusterEvent;
import org.keycloak.component.ComponentModel;
import org.keycloak.keys.infinispan.PublicKeyStorageInvalidationEvent;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.infinispan.authorization.events.PolicyRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.PolicyUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceServerUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ResourceUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ScopeRemovedEvent;
import org.keycloak.models.cache.infinispan.authorization.events.ScopeUpdatedEvent;
import org.keycloak.models.cache.infinispan.authorization.stream.InResourcePredicate;
import org.keycloak.models.cache.infinispan.authorization.stream.InResourceServerPredicate;
import org.keycloak.models.cache.infinispan.authorization.stream.InScopePredicate;
import org.keycloak.models.cache.infinispan.events.AuthenticationSessionAuthNoteUpdateEvent;
import org.keycloak.models.cache.infinispan.events.ClientAddedEvent;
import org.keycloak.models.cache.infinispan.events.ClientRemovedEvent;
import org.keycloak.models.cache.infinispan.events.ClientScopeAddedEvent;
import org.keycloak.models.cache.infinispan.events.ClientScopeRemovedEvent;
import org.keycloak.models.cache.infinispan.events.ClientUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.GroupAddedEvent;
import org.keycloak.models.cache.infinispan.events.GroupMovedEvent;
import org.keycloak.models.cache.infinispan.events.GroupRemovedEvent;
import org.keycloak.models.cache.infinispan.events.GroupUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.RealmRemovedEvent;
import org.keycloak.models.cache.infinispan.events.RealmUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.RoleAddedEvent;
import org.keycloak.models.cache.infinispan.events.RoleRemovedEvent;
import org.keycloak.models.cache.infinispan.events.RoleUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.UserCacheRealmInvalidationEvent;
import org.keycloak.models.cache.infinispan.events.UserConsentsUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.UserFederationLinkRemovedEvent;
import org.keycloak.models.cache.infinispan.events.UserFederationLinkUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.UserFullInvalidationEvent;
import org.keycloak.models.cache.infinispan.events.UserUpdatedEvent;
import org.keycloak.models.cache.infinispan.stream.GroupListPredicate;
import org.keycloak.models.cache.infinispan.stream.HasRolePredicate;
import org.keycloak.models.cache.infinispan.stream.InClientPredicate;
import org.keycloak.models.cache.infinispan.stream.InGroupPredicate;
import org.keycloak.models.cache.infinispan.stream.InIdentityProviderPredicate;
import org.keycloak.models.cache.infinispan.stream.InRealmPredicate;
import org.keycloak.models.sessions.infinispan.changes.ReplaceFunction;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.changes.sessions.LastSessionRefreshEvent;
import org.keycloak.models.sessions.infinispan.changes.sessions.SessionData;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore;
import org.keycloak.models.sessions.infinispan.entities.AuthenticationSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.SingleUseObjectValueEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveAllUserLoginFailuresEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.initializer.InitializerState;
import org.keycloak.models.sessions.infinispan.stream.SessionPredicate;
import org.keycloak.models.sessions.infinispan.stream.SessionWrapperPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
import org.keycloak.sessions.CommonClientSessionModel;
import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.managers.UserStorageSyncManager;
@ProtoSchema(
syntax = ProtoSyntax.PROTO3,
schemaPackageName = "keycloak",
schemaFilePath = "proto/generated",
// common-types for UUID
dependsOn = CommonTypes.class,
includeClasses = {
// Model
UserSessionModel.State.class,
CommonClientSessionModel.ExecutionStatus.class,
ComponentModel.MultiMapEntry.class,
UserStorageProviderModel.class,
UserStorageSyncManager.UserStorageProviderClusterEvent.class,
// clustering.infinispan package
LockEntry.class,
LockEntryPredicate.class,
WrapperClusterEvent.class,
WrapperClusterEvent.SiteFilter.class,
// keys.infinispan package
PublicKeyStorageInvalidationEvent.class,
//models.cache.infinispan.authorization.events package
PolicyUpdatedEvent.class,
PolicyRemovedEvent.class,
ResourceUpdatedEvent.class,
ResourceRemovedEvent.class,
ResourceServerUpdatedEvent.class,
ResourceServerRemovedEvent.class,
ScopeUpdatedEvent.class,
ScopeRemovedEvent.class,
// models.sessions.infinispan.initializer package
InitializerState.class,
// models.sessions.infinispan.changes package
SessionEntityWrapper.class,
// models.sessions.infinispan.changes.sessions package
LastSessionRefreshEvent.class,
SessionData.class,
// models.cache.infinispan.authorization.stream package
InResourcePredicate.class,
InResourceServerPredicate.class,
InScopePredicate.class,
// models.sessions.infinispan.events package
RealmRemovedSessionEvent.class,
RemoveAllUserLoginFailuresEvent.class,
RemoveUserSessionsEvent.class,
// models.sessions.infinispan.stream package
SessionPredicate.class,
SessionWrapperPredicate.class,
UserSessionPredicate.class,
// models.cache.infinispan.stream package
GroupListPredicate.class,
HasRolePredicate.class,
InClientPredicate.class,
InGroupPredicate.class,
InIdentityProviderPredicate.class,
InRealmPredicate.class,
// models.cache.infinispan.events package
AuthenticationSessionAuthNoteUpdateEvent.class,
ClientAddedEvent.class,
ClientUpdatedEvent.class,
ClientRemovedEvent.class,
ClientScopeAddedEvent.class,
ClientScopeRemovedEvent.class,
GroupAddedEvent.class,
GroupMovedEvent.class,
GroupRemovedEvent.class,
GroupUpdatedEvent.class,
RealmUpdatedEvent.class,
RealmRemovedEvent.class,
RoleAddedEvent.class,
RoleUpdatedEvent.class,
RoleRemovedEvent.class,
UserCacheRealmInvalidationEvent.class,
UserConsentsUpdatedEvent.class,
UserFederationLinkRemovedEvent.class,
UserFederationLinkUpdatedEvent.class,
UserFullInvalidationEvent.class,
UserUpdatedEvent.class,
// sessions.infinispan.entities package
AuthenticatedClientSessionStore.class,
AuthenticatedClientSessionEntity.class,
AuthenticationSessionEntity.class,
LoginFailureEntity.class,
LoginFailureKey.class,
RootAuthenticationSessionEntity.class,
SingleUseObjectValueEntity.class,
UserSessionEntity.class,
ReplaceFunction.class
}
)
public interface KeycloakModelSchema extends GeneratedSchema {
KeycloakModelSchema INSTANCE = new KeycloakModelSchemaImpl();
}

View file

@ -1,25 +1,155 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.marshalling;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.jboss.marshalling.core.JBossUserMarshaller;
import org.keycloak.models.sessions.infinispan.changes.ReplaceFunction;
@SuppressWarnings("removal")
/**
* Ids of the protostream type.
* <p>
* Read careful the following warning to ensure compatibility when updating schemas.
* <p>
* WARNING! IDs lower or equal than 65535 are reserved for internal Inifinispan classes and cannot be used.
* WARNING! ID defined in this class must be unique. If one type is removed, its ID must not be reused. You have been
* warned! The ID identifies the message, and it is stored and used to save space.
* WARNING! The field IDs cannot be reused as well for the same reason.
* WARNING! Primitive types cannot be null in proto3 syntax (Integer, String). Take that in consideration.
* <p>
* Be Aware of the following default in Proto3 syntax!
* For strings, the default value is the empty string.
* For bytes, the default value is empty bytes.
* For bools, the default value is false.
* For numeric types, the default value is zero.
* For enums, the default value is the first defined enum value, which must be 0.
* For message fields, the field is not set. (null)
* <p>
* Docs: <a href="https://protobuf.dev/programming-guides/proto3/">Language Guide (proto 3)</a>
*/
public final class Marshalling {
private Marshalling() {
}
// Note: Min ID is 2500
public static final Integer REPLACE_FUNCTION_ID = 2500;
// Model
// see org.keycloak.models.UserSessionModel.State
public static final int USER_STATE_ENUM = 65536;
// see org.keycloak.sessions.CommonClientSessionModel.ExecutionStatus
public static final int CLIENT_SESSION_EXECUTION_STATUS = 65537;
// see org.keycloak.component.ComponentModel.MultiMapEntry
public static final int MULTIMAP_ENTRY = 65538;
// see org.keycloak.storage.UserStorageProviderModel
public static final int USER_STORAGE_PROVIDER_MODES = 65539;
// see org.keycloak.storage.managers.UserStorageSyncManager.UserStorageProviderClusterEvent
public static final int USER_STORAGE_PROVIDER_CLUSTER_EVENT = 65540;
// clustering.infinispan package
public static final int LOCK_ENTRY = 65541;
public static final int LOCK_ENTRY_PREDICATE = 65542;
public static final int WRAPPED_CLUSTER_EVENT = 65543;
public static final int WRAPPED_CLUSTER_EVENT_SITE_FILTER = 65544;
// keys.infinispan package
public static final int PUBLIC_KEY_INVALIDATION_EVENT = 65545;
//models.cache.infinispan.authorization.events package
public static final int POLICY_UPDATED_EVENT = 65546;
public static final int POLICY_REMOVED_EVENT = 65547;
public static final int RESOURCE_UPDATED_EVENT = 65548;
public static final int RESOURCE_REMOVED_EVENT = 65549;
public static final int RESOURCE_SERVER_UPDATED_EVENT = 65550;
public static final int RESOURCE_SERVER_REMOVED_EVENT = 65551;
public static final int SCOPE_UPDATED_EVENT = 65552;
public static final int SCOPE_REMOVED_EVENT = 65553;
// models.sessions.infinispan.initializer package
public static final int INITIALIZER_STATE = 65554;
// models.sessions.infinispan.changes package
public static final int SESSION_ENTITY_WRAPPER = 65555;
public static final int REPLACE_FUNCTION = 65656;
// models.sessions.infinispan.changes.sessions package
public static final int LAST_SESSION_REFRESH_EVENT = 65557;
public static final int SESSION_DATA = 65558;
// models.cache.infinispan.authorization.stream package
public static final int IN_RESOURCE_PREDICATE = 65559;
public static final int IN_RESOURCE_SERVER_PREDICATE = 65560;
public static final int IN_SCOPE_PREDICATE = 65561;
// models.sessions.infinispan.events package
public static final int REALM_REMOVED_SESSION_EVENT = 65562;
public static final int REMOVE_ALL_USER_LOGIN_FAILURES_EVENT = 65563;
public static final int REMOVE_ALL_USER_SESSIONS_EVENT = 65564;
// models.sessions.infinispan.stream package
public static final int SESSION_PREDICATE = 65565;
public static final int SESSION_WRAPPER_PREDICATE = 65566;
public static final int USER_SESSION_PREDICATE = 65567;
// models.cache.infinispan.stream package
public static final int GROUP_LIST_PREDICATE = 65568;
public static final int HAS_ROLE_PREDICATE = 65569;
public static final int IN_CLIENT_PREDICATE = 65570;
public static final int IN_GROUP_PREDICATE = 65571;
public static final int IN_IDENTITY_PROVIDER_PREDICATE = 65572;
public static final int IN_REALM_PREDICATE = 65573;
// models.cache.infinispan.events package
public static final int AUTHENTICATION_SESSION_AUTH_NOTE_UPDATE_EVENT = 65574;
public static final int CLIENT_ADDED_EVENT = 65575;
public static final int CLIENT_UPDATED_EVENT = 65576;
public static final int CLIENT_REMOVED_EVENT = 65577;
public static final int CLIENT_SCOPE_ADDED_EVENT = 65578;
public static final int CLIENT_SCOPE_REMOVED_EVENT = 65579;
public static final int GROUP_ADDED_EVENT = 65580;
public static final int GROUP_MOVED_EVENT = 65581;
public static final int GROUP_REMOVED_EVENT = 65582;
public static final int GROUP_UPDATED_EVENT = 65583;
public static final int REALM_UPDATED_EVENT = 65584;
public static final int REALM_REMOVED_EVENT = 65585;
public static final int ROLE_ADDED_EVENT = 65586;
public static final int ROLE_UPDATED_EVENT = 65587;
public static final int ROLE_REMOVED_EVENT = 65588;
public static final int USER_CACHE_REALM_INVALIDATION_EVENT = 65589;
public static final int USER_CONSENTS_UPDATED_EVENT = 65590;
public static final int USER_FEDERATION_LINK_REMOVED_EVENT = 65591;
public static final int USER_FEDERATION_LINK_UPDATED_EVENT = 65592;
public static final int USER_FULL_INVALIDATION_EVENT = 65593;
public static final int USER_UPDATED_EVENT = 65594;
// sessions.infinispan.entities package
public static final int AUTHENTICATED_CLIENT_SESSION_STORE = 65595;
public static final int AUTHENTICATED_CLIENT_SESSION_ENTITY = 65596;
public static final int AUTHENTICATION_SESSION_ENTITY = 65597;
public static final int LOGIN_FAILURE_ENTITY = 65598;
public static final int LOGIN_FAILURE_KEY = 65599;
public static final int ROOT_AUTHENTICATION_SESSION_ENTITY = 65600;
public static final int SINGLE_USE_OBJECT_VALUE_ENTITY = 65601;
public static final int USER_SESSION_ENTITY = 65602;
// For Infinispan 10, we go with the JBoss marshalling.
// TODO: This should be replaced later with the marshalling recommended by infinispan. Probably protostream.
// See https://infinispan.org/docs/stable/titles/developing/developing.html#marshalling for the details
public static void configure(GlobalConfigurationBuilder builder) {
builder.serialization()
.marshaller(new JBossUserMarshaller())
.addAdvancedExternalizer(ReplaceFunction.INSTANCE);
.addContextInitializer(KeycloakModelSchema.INSTANCE);
}
public static String emptyStringToNull(String value) {
return value == null || value.isEmpty() ? null : value;
}
}

View file

@ -17,27 +17,73 @@
package org.keycloak.models.cache.infinispan;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jboss.logging.Logger;
import org.keycloak.client.clienttype.ClientTypeManager;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.Profile;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.*;
import org.keycloak.models.ClientInitialAccessModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientProvider;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.ClientScopeProvider;
import org.keycloak.models.GroupModel;
import org.keycloak.models.GroupProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleModel;
import org.keycloak.models.RoleProvider;
import org.keycloak.models.UserModel;
import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.CachedRealmModel;
import org.keycloak.models.cache.infinispan.entities.*;
import org.keycloak.models.cache.infinispan.events.*;
import org.keycloak.models.cache.infinispan.entities.CachedClient;
import org.keycloak.models.cache.infinispan.entities.CachedClientRole;
import org.keycloak.models.cache.infinispan.entities.CachedClientScope;
import org.keycloak.models.cache.infinispan.entities.CachedGroup;
import org.keycloak.models.cache.infinispan.entities.CachedRealm;
import org.keycloak.models.cache.infinispan.entities.CachedRealmRole;
import org.keycloak.models.cache.infinispan.entities.CachedRole;
import org.keycloak.models.cache.infinispan.entities.ClientListQuery;
import org.keycloak.models.cache.infinispan.entities.ClientScopeListQuery;
import org.keycloak.models.cache.infinispan.entities.GroupListQuery;
import org.keycloak.models.cache.infinispan.entities.GroupNameQuery;
import org.keycloak.models.cache.infinispan.entities.RealmListQuery;
import org.keycloak.models.cache.infinispan.entities.RoleListQuery;
import org.keycloak.models.cache.infinispan.events.ClientAddedEvent;
import org.keycloak.models.cache.infinispan.events.ClientRemovedEvent;
import org.keycloak.models.cache.infinispan.events.ClientScopeAddedEvent;
import org.keycloak.models.cache.infinispan.events.ClientScopeRemovedEvent;
import org.keycloak.models.cache.infinispan.events.ClientUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.GroupAddedEvent;
import org.keycloak.models.cache.infinispan.events.GroupMovedEvent;
import org.keycloak.models.cache.infinispan.events.GroupRemovedEvent;
import org.keycloak.models.cache.infinispan.events.GroupUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.cache.infinispan.events.RealmRemovedEvent;
import org.keycloak.models.cache.infinispan.events.RealmUpdatedEvent;
import org.keycloak.models.cache.infinispan.events.RoleAddedEvent;
import org.keycloak.models.cache.infinispan.events.RoleRemovedEvent;
import org.keycloak.models.cache.infinispan.events.RoleUpdatedEvent;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.DatastoreProvider;
import org.keycloak.storage.StoreManagers;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.StoreManagers;
import org.keycloak.storage.client.ClientStorageProviderModel;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* - the high level architecture of this cache is an invalidation cache.
@ -221,7 +267,6 @@ public class RealmCacheSession implements CacheRealmProvider {
public void registerClientScopeInvalidation(String id, String realmId) {
invalidateClientScope(id);
cache.clientScopeUpdated(realmId, invalidations);
invalidationEvents.add(ClientTemplateEvent.create(id));
}
private void invalidateClientScope(String id) {
@ -561,7 +606,7 @@ public class RealmCacheSession implements CacheRealmProvider {
// this is needed so that a client that hasn't been committed isn't cached in a query
listInvalidations.add(realm.getId());
invalidationEvents.add(ClientAddedEvent.create(client.getId(), client.getClientId(), realm.getId()));
invalidationEvents.add(ClientAddedEvent.create(client.getId(), realm.getId()));
cache.clientAdded(realm.getId(), invalidations);
return client;
}

View file

@ -62,7 +62,7 @@ public class StoreFactoryCacheManager extends CacheManager {
public void resourceServerRemoval(String id, Set<String> invalidations) {
resourceServerUpdated(id, invalidations);
addInvalidations(InResourceServerPredicate.create().resourceServer(id), invalidations);
addInvalidations(InResourceServerPredicate.create(id), invalidations);
}
public void scopeUpdated(String id, String name, String serverId, Set<String> invalidations) {
@ -74,7 +74,7 @@ public class StoreFactoryCacheManager extends CacheManager {
public void scopeRemoval(String id, String name, String serverId, Set<String> invalidations) {
scopeUpdated(id, name, serverId, invalidations);
addInvalidations(InScopePredicate.create().scope(id), invalidations);
addInvalidations(InScopePredicate.create(id), invalidations);
}
public void resourceUpdated(String id, String name, String type, Set<String> uris, Set<String> scopes, String serverId, String owner, Set<String> invalidations) {
@ -83,14 +83,14 @@ public class StoreFactoryCacheManager extends CacheManager {
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByOwnerCacheKey(owner, null));
invalidations.add(StoreFactoryCacheSession.getPermissionTicketByResource(id, serverId));
addInvalidations(InResourcePredicate.create().resource(name), invalidations);
addInvalidations(InResourcePredicate.create(name), invalidations);
if (type != null) {
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, owner, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByTypeCacheKey(type, null, serverId));
invalidations.add(StoreFactoryCacheSession.getResourceByTypeInstanceCacheKey(type, serverId));
addInvalidations(InResourcePredicate.create().resource(type), invalidations);
addInvalidations(InResourcePredicate.create(type), invalidations);
}
if (uris != null) {
@ -102,14 +102,14 @@ public class StoreFactoryCacheManager extends CacheManager {
if (scopes != null) {
for (String scope : scopes) {
invalidations.add(StoreFactoryCacheSession.getResourceByScopeCacheKey(scope, serverId));
addInvalidations(InScopePredicate.create().scope(scope), invalidations);
addInvalidations(InScopePredicate.create(scope), invalidations);
}
}
}
public void resourceRemoval(String id, String name, String type, Set<String> uris, String owner, Set<String> scopes, String serverId, Set<String> invalidations) {
resourceUpdated(id, name, type, uris, scopes, serverId, owner, invalidations);
addInvalidations(InResourcePredicate.create().resource(id), invalidations);
addInvalidations(InResourcePredicate.create(id), invalidations);
}
public void policyUpdated(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId, Set<String> invalidations) {

View file

@ -270,7 +270,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
ResourceAdapter adapter = managedResources.get(id);
if (adapter != null) adapter.invalidateFlag();
invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uris, scopes, serverId, owner));
invalidationEvents.add(ResourceUpdatedEvent.create(id, name, type, uris, owner, scopes, serverId));
}
public void registerPolicyInvalidation(String id, String name, Set<String> resources, Set<String> scopes, String defaultResourceType, String serverId) {
@ -443,7 +443,7 @@ public class StoreFactoryCacheSession implements CachedStoreFactoryProvider {
if (server == null) return;
cache.invalidateObject(id);
invalidationEvents.add(ResourceServerRemovedEvent.create(id, server.getId()));
invalidationEvents.add(ResourceServerRemovedEvent.create(id));
cache.resourceServerRemoval(id, invalidations);
getResourceServerStoreDelegate().delete(client);

View file

@ -0,0 +1,78 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.cache.infinispan.authorization.events;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
abstract class BasePolicyEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoField(2)
final String name;
@ProtoField(value = 3, collectionImplementation = HashSet.class)
final Set<String> resources;
@ProtoField(value = 4, collectionImplementation = HashSet.class)
final Set<String> resourceTypes;
@ProtoField(value = 5, collectionImplementation = HashSet.class)
final Set<String> scopes;
@ProtoField(6)
final String serverId;
BasePolicyEvent(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
super(id);
this.name = Objects.requireNonNull(name);
this.resources = resources;
this.resourceTypes = resourceTypes;
this.scopes = scopes;
this.serverId = Objects.requireNonNull(serverId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BasePolicyEvent that = (BasePolicyEvent) o;
return name.equals(that.name) &&
Objects.equals(resources, that.resources) &&
Objects.equals(resourceTypes, that.resourceTypes) &&
Objects.equals(scopes, that.scopes) &&
serverId.equals(that.serverId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + Objects.hashCode(resources);
result = 31 * result + Objects.hashCode(resourceTypes);
result = 31 * result + Objects.hashCode(scopes);
result = 31 * result + serverId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [id=%s, name=%s]", getClass().getSimpleName(), getId(), name);
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.cache.infinispan.authorization.events;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
abstract class BaseResourceEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoField(2)
final String name;
@ProtoField(3)
final String owner;
@ProtoField(4)
final String serverId;
@ProtoField(5)
final String type;
@ProtoField(value = 6, collectionImplementation = HashSet.class)
final Set<String> uris;
@ProtoField(value = 7, collectionImplementation = HashSet.class)
final Set<String> scopes;
BaseResourceEvent(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
super(id);
this.name = Objects.requireNonNull(name);
this.owner = Objects.requireNonNull(owner);
this.serverId = Objects.requireNonNull(serverId);
this.type = type;
this.uris = uris;
this.scopes = scopes;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseResourceEvent that = (BaseResourceEvent) o;
return name.equals(that.name) &&
owner.equals(that.owner) &&
serverId.equals(that.serverId) &&
Objects.equals(type, that.type) &&
Objects.equals(uris, that.uris) &&
Objects.equals(scopes, that.scopes);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + owner.hashCode();
result = 31 * result + serverId.hashCode();
result = 31 * result + Objects.hashCode(type);
result = 31 * result + Objects.hashCode(uris);
result = 31 * result + Objects.hashCode(scopes);
return result;
}
@Override
public String toString() {
return String.format("%s [ id=%s, name=%s]", getClass().getSimpleName(), getId(), name);
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
abstract class BaseResourceServerEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
BaseResourceServerEvent(String id) {
super(id);
}
@Override
public String toString() {
return String.format("%s [ id=%s ]", getClass().getSimpleName(), getId());
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.cache.infinispan.authorization.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
abstract class BaseScopeEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoField(2)
final String name;
@ProtoField(3)
final String serverId;
BaseScopeEvent(String id, String name, String serverId) {
super(id);
this.name = Objects.requireNonNull(name);
this.serverId = Objects.requireNonNull(serverId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseScopeEvent that = (BaseScopeEvent) o;
return name.equals(that.name) &&
serverId.equals(that.serverId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + name.hashCode();
result = 31 * result + serverId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ id=%s, name=%s ]", getClass(), getId(), name);
}
}

View file

@ -28,7 +28,6 @@ import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
*/
public class PermissionTicketRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String owner;
private String resource;
private String scope;
@ -36,9 +35,12 @@ public class PermissionTicketRemovedEvent extends InvalidationEvent implements A
private String requester;
private String resourceName;
private PermissionTicketRemovedEvent(String id) {
super(id);
}
public static PermissionTicketRemovedEvent create(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId) {
PermissionTicketRemovedEvent event = new PermissionTicketRemovedEvent();
event.id = id;
PermissionTicketRemovedEvent event = new PermissionTicketRemovedEvent(id);
event.owner = owner;
event.requester = requester;
event.resource = resource;
@ -48,32 +50,27 @@ public class PermissionTicketRemovedEvent extends InvalidationEvent implements A
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
PermissionTicketRemovedEvent that = (PermissionTicketRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(resource, that.resource) && Objects.equals(serverId, that.serverId);
return Objects.equals(resource, that.resource) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, resource, serverId);
return Objects.hash(super.hashCode(), resource, serverId);
}
@Override
public String toString() {
return String.format("PermissionTicketRemovedEvent [ id=%s, name=%s]", id, resource);
return String.format("PermissionTicketRemovedEvent [ id=%s, name=%s]", getId(), resource);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.permissionTicketRemoval(id, owner, requester, resource, resourceName, scope, serverId, invalidations);
cache.permissionTicketRemoval(getId(), owner, requester, resource, resourceName, scope, serverId, invalidations);
}
}

View file

@ -28,7 +28,6 @@ import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
*/
public class PermissionTicketUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
private String id;
private String owner;
private String resource;
private String scope;
@ -36,9 +35,12 @@ public class PermissionTicketUpdatedEvent extends InvalidationEvent implements A
private String requester;
private String resourceName;
private PermissionTicketUpdatedEvent(String id) {
super(id);
}
public static PermissionTicketUpdatedEvent create(String id, String owner, String requester, String resource, String resourceName, String scope, String serverId) {
PermissionTicketUpdatedEvent event = new PermissionTicketUpdatedEvent();
event.id = id;
PermissionTicketUpdatedEvent event = new PermissionTicketUpdatedEvent(id);
event.owner = owner;
event.requester = requester;
event.resource = resource;
@ -48,34 +50,27 @@ public class PermissionTicketUpdatedEvent extends InvalidationEvent implements A
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
PermissionTicketUpdatedEvent that = (PermissionTicketUpdatedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(resource, that.resource) && Objects.equals(serverId, that.serverId);
return Objects.equals(resource, that.resource) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, resource, serverId);
return Objects.hash(super.hashCode(), resource, serverId);
}
@Override
public String toString() {
return String.format("PermissionTicketUpdatedEvent [ id=%s, name=%s]", id, resource);
return String.format("PermissionTicketUpdatedEvent [ id=%s, name=%s]", getId(), resource);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.permissionTicketUpdated(id, owner, requester, resource, resourceName, scope, serverId, invalidations);
cache.permissionTicketUpdated(getId(), owner, requester, resource, resourceName, scope, serverId, invalidations);
}
}

View file

@ -17,109 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(PolicyRemovedEvent.ExternalizerImpl.class)
public class PolicyRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoTypeId(Marshalling.POLICY_REMOVED_EVENT)
public class PolicyRemovedEvent extends BasePolicyEvent {
private String id;
private String name;
private Set<String> resources;
private Set<String> resourceTypes;
private Set<String> scopes;
private String serverId;
@ProtoFactory
PolicyRemovedEvent(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
super(id, name, resources, resourceTypes, scopes, serverId);
}
public static PolicyRemovedEvent create(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
PolicyRemovedEvent event = new PolicyRemovedEvent();
event.id = id;
event.name = name;
event.resources = resources;
event.resourceTypes = resourceTypes;
event.scopes = scopes;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
PolicyRemovedEvent that = (PolicyRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId);
}
@Override
public String toString() {
return String.format("PolicyRemovedEvent [ id=%s, name=%s]", id, name);
return new PolicyRemovedEvent(id, name, resources, resourceTypes, scopes, serverId);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.policyRemoval(id, name, resources, resourceTypes, scopes, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<PolicyRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, PolicyRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
KeycloakMarshallUtil.writeCollection(obj.scopes, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.resources, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.resourceTypes, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public PolicyRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public PolicyRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
PolicyRemovedEvent res = new PolicyRemovedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.scopes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.resources = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.resourceTypes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
cache.policyRemoval(getId(), name, resources, resourceTypes, scopes, serverId, invalidations);
}
}

View file

@ -17,109 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(PolicyUpdatedEvent.ExternalizerImpl.class)
public class PolicyUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoTypeId(Marshalling.POLICY_UPDATED_EVENT)
public class PolicyUpdatedEvent extends BasePolicyEvent {
private String id;
private String name;
private Set<String> resources;
private Set<String> resourceTypes;
private Set<String> scopes;
private String serverId;
@ProtoFactory
PolicyUpdatedEvent(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
super(id, name, resources, resourceTypes, scopes, serverId);
}
public static PolicyUpdatedEvent create(String id, String name, Set<String> resources, Set<String> resourceTypes, Set<String> scopes, String serverId) {
PolicyUpdatedEvent event = new PolicyUpdatedEvent();
event.id = id;
event.name = name;
event.resources = resources;
event.resourceTypes = resourceTypes;
event.scopes = scopes;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
PolicyUpdatedEvent that = (PolicyUpdatedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId);
}
@Override
public String toString() {
return String.format("PolicyUpdatedEvent [ id=%s, name=%s ]", id, name);
return new PolicyUpdatedEvent(id, name, resources, resourceTypes, scopes, serverId);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<PolicyUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, PolicyUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
KeycloakMarshallUtil.writeCollection(obj.resources, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.resourceTypes, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.scopes, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public PolicyUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public PolicyUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
PolicyUpdatedEvent res = new PolicyUpdatedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.resources = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.resourceTypes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.scopes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
cache.policyUpdated(getId(), name, resources, resourceTypes, scopes, serverId, invalidations);
}
}

View file

@ -17,113 +17,34 @@
package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ResourceRemovedEvent.ExternalizerImpl.class)
public class ResourceRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoTypeId(Marshalling.RESOURCE_REMOVED_EVENT)
public class ResourceRemovedEvent extends BaseResourceEvent {
private String id;
private String name;
private String owner;
private String serverId;
private String type;
private Set<String> uris;
private Set<String> scopes;
@ProtoFactory
static ResourceRemovedEvent protoFactory(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
return new ResourceRemovedEvent(id, name, owner, serverId, Marshalling.emptyStringToNull(type), uris, scopes);
}
private ResourceRemovedEvent(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
super(id, name, owner, serverId, type, uris, scopes);
}
public static ResourceRemovedEvent create(String id, String name, String type, Set<String> uris, String owner, Set<String> scopes, String serverId) {
ResourceRemovedEvent event = new ResourceRemovedEvent();
event.id = id;
event.name = name;
event.type = type;
event.uris = uris;
event.owner = owner;
event.scopes = scopes;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ResourceRemovedEvent that = (ResourceRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(owner, that.owner) && Objects.equals(serverId, that.serverId) && Objects.equals(type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, owner, serverId, type);
}
@Override
public String toString() {
return String.format("ResourceRemovedEvent [ id=%s, name=%s ]", id, name);
return new ResourceRemovedEvent(id, name, owner, serverId, type, uris, scopes);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceRemoval(id, name, type, uris, owner, scopes, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ResourceRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ResourceRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
MarshallUtil.marshallString(obj.type, output);
KeycloakMarshallUtil.writeCollection(obj.uris, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.owner, output);
KeycloakMarshallUtil.writeCollection(obj.scopes, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public ResourceRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ResourceRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ResourceRemovedEvent res = new ResourceRemovedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.type = MarshallUtil.unmarshallString(input);
res.uris = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.owner = MarshallUtil.unmarshallString(input);
res.scopes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
cache.resourceRemoval(getId(), name, type, uris, owner, scopes, serverId, invalidations);
}
}

View file

@ -17,91 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ResourceServerRemovedEvent.ExternalizerImpl.class)
public class ResourceServerRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoTypeId(Marshalling.RESOURCE_SERVER_REMOVED_EVENT)
public class ResourceServerRemovedEvent extends BaseResourceServerEvent {
private String id;
private String clientId;
public static ResourceServerRemovedEvent create(String id, String clientId) {
ResourceServerRemovedEvent event = new ResourceServerRemovedEvent();
event.id = id;
event.clientId = clientId;
return event;
@ProtoFactory
ResourceServerRemovedEvent(String id) {
super(id);
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ResourceServerRemovedEvent that = (ResourceServerRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(clientId, that.clientId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, clientId);
}
@Override
public String toString() {
return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, clientId);
public static ResourceServerRemovedEvent create(String id) {
return new ResourceServerRemovedEvent(id);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceServerRemoval(id, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ResourceServerRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ResourceServerRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.clientId, output);
}
@Override
public ResourceServerRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ResourceServerRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ResourceServerRemovedEvent res = new ResourceServerRemovedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.clientId = MarshallUtil.unmarshallString(input);
return res;
}
cache.resourceServerRemoval(getId(), invalidations);
}
}

View file

@ -17,72 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ResourceServerUpdatedEvent.ExternalizerImpl.class)
public class ResourceServerUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoTypeId(Marshalling.RESOURCE_SERVER_UPDATED_EVENT)
public class ResourceServerUpdatedEvent extends BaseResourceServerEvent {
private String id;
@ProtoFactory
ResourceServerUpdatedEvent(String id) {
super(id);
}
public static ResourceServerUpdatedEvent create(String id) {
ResourceServerUpdatedEvent event = new ResourceServerUpdatedEvent();
event.id = id;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ResourceServerRemovedEvent [ id=%s, clientId=%s ]", id, id);
return new ResourceServerUpdatedEvent(id);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceServerUpdated(id, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ResourceServerUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ResourceServerUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
}
@Override
public ResourceServerUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ResourceServerUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ResourceServerUpdatedEvent res = new ResourceServerUpdatedEvent();
res.id = MarshallUtil.unmarshallString(input);
return res;
}
cache.resourceServerUpdated(getId(), invalidations);
}
}

View file

@ -17,113 +17,35 @@
package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ResourceUpdatedEvent.ExternalizerImpl.class)
public class ResourceUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoTypeId(Marshalling.RESOURCE_UPDATED_EVENT)
public class ResourceUpdatedEvent extends BaseResourceEvent {
private String id;
private String name;
private String serverId;
private String type;
private Set<String> uris;
private Set<String> scopes;
private String owner;
public static ResourceUpdatedEvent create(String id, String name, String type, Set<String> uris, Set<String> scopes, String serverId, String owner) {
ResourceUpdatedEvent event = new ResourceUpdatedEvent();
event.id = id;
event.name = name;
event.type = type;
event.uris = uris;
event.scopes = scopes;
event.serverId = serverId;
event.owner = owner;
return event;
@ProtoFactory
static ResourceUpdatedEvent protoFactory(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
return new ResourceUpdatedEvent(id, name, owner, serverId, Marshalling.emptyStringToNull(type), uris, scopes);
}
@Override
public String getId() {
return id;
private ResourceUpdatedEvent(String id, String name, String owner, String serverId, String type, Set<String> uris, Set<String> scopes) {
super(id, name, owner, serverId, type, uris, scopes);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ResourceUpdatedEvent that = (ResourceUpdatedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId) && Objects.equals(type, that.type) && Objects.equals(owner, that.owner);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId, type, owner);
}
@Override
public String toString() {
return String.format("ResourceUpdatedEvent [ id=%s, name=%s ]", id, name);
public static ResourceUpdatedEvent create(String id, String name, String type, Set<String> uris, String owner, Set<String> scopes, String serverId) {
return new ResourceUpdatedEvent(id, name, owner, serverId, type, uris, scopes);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.resourceUpdated(id, name, type, uris, scopes, serverId, owner, invalidations);
cache.resourceUpdated(getId(), name, type, uris, scopes, serverId, owner, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ResourceUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ResourceUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
MarshallUtil.marshallString(obj.type, output);
KeycloakMarshallUtil.writeCollection(obj.uris, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(obj.scopes, KeycloakMarshallUtil.STRING_EXT, output);
MarshallUtil.marshallString(obj.serverId, output);
MarshallUtil.marshallString(obj.owner, output);
}
@Override
public ResourceUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ResourceUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ResourceUpdatedEvent res = new ResourceUpdatedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.type = MarshallUtil.unmarshallString(input);
res.uris = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.scopes = KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, HashSet::new);
res.serverId = MarshallUtil.unmarshallString(input);
res.owner = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -17,95 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ScopeRemovedEvent.ExternalizerImpl.class)
public class ScopeRemovedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoTypeId(Marshalling.SCOPE_REMOVED_EVENT)
public class ScopeRemovedEvent extends BaseScopeEvent {
private String id;
private String name;
private String serverId;
@ProtoFactory
ScopeRemovedEvent(String id, String name, String serverId) {
super(id, name, serverId);
}
public static ScopeRemovedEvent create(String id, String name, String serverId) {
ScopeRemovedEvent event = new ScopeRemovedEvent();
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public String toString() {
return String.format("ScopeRemovedEvent [ id=%s, name=%s]", id, name);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ScopeRemovedEvent that = (ScopeRemovedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId);
return new ScopeRemovedEvent(id, name, serverId);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.scopeRemoval(id, name, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ScopeRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ScopeRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public ScopeRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ScopeRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ScopeRemovedEvent res = new ScopeRemovedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
cache.scopeRemoval(getId(), name, serverId, invalidations);
}
}

View file

@ -17,95 +17,30 @@
package org.keycloak.models.cache.infinispan.authorization.events;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
import org.keycloak.models.cache.infinispan.events.InvalidationEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import java.util.Set;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ScopeUpdatedEvent.ExternalizerImpl.class)
public class ScopeUpdatedEvent extends InvalidationEvent implements AuthorizationCacheInvalidationEvent {
@ProtoTypeId(Marshalling.SCOPE_UPDATED_EVENT)
public class ScopeUpdatedEvent extends BaseScopeEvent {
private String id;
private String name;
private String serverId;
@ProtoFactory
ScopeUpdatedEvent(String id, String name, String serverId) {
super(id, name, serverId);
}
public static ScopeUpdatedEvent create(String id, String name, String serverId) {
ScopeUpdatedEvent event = new ScopeUpdatedEvent();
event.id = id;
event.name = name;
event.serverId = serverId;
return event;
}
@Override
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ScopeUpdatedEvent that = (ScopeUpdatedEvent) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name) && Objects.equals(serverId, that.serverId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), id, name, serverId);
}
@Override
public String toString() {
return String.format("ScopeUpdatedEvent [ id=%s, name=%s ]", id, name);
return new ScopeUpdatedEvent(id, name, serverId);
}
@Override
public void addInvalidations(StoreFactoryCacheManager cache, Set<String> invalidations) {
cache.scopeUpdated(id, name, serverId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ScopeUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ScopeUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
MarshallUtil.marshallString(obj.name, output);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public ScopeUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ScopeUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ScopeUpdatedEvent res = new ScopeUpdatedEvent();
res.id = MarshallUtil.unmarshallString(input);
res.name = MarshallUtil.unmarshallString(input);
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
cache.scopeUpdated(getId(), name, serverId, invalidations);
}
}

View file

@ -16,71 +16,42 @@
*/
package org.keycloak.models.cache.infinispan.authorization.stream;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.authorization.entities.InResource;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.marshalling.Marshalling;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@SerializeWith(InResourcePredicate.ExternalizerImpl.class)
public class InResourcePredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
@ProtoTypeId(Marshalling.IN_RESOURCE_PREDICATE)
public class InResourcePredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String resourceId;
private final String resourceId;
public static InResourcePredicate create() {
return new InResourcePredicate();
private InResourcePredicate(String resourceId) {
this.resourceId = Objects.requireNonNull(resourceId);
}
public InResourcePredicate resource(String id) {
resourceId = id;
return this;
@ProtoFactory
public static InResourcePredicate create(String resourceId) {
return new InResourcePredicate(resourceId);
}
@ProtoField(1)
String getResourceId() {
return resourceId;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (!(value instanceof InResource)) return false;
return resourceId.equals(((InResource)value).getResourceId());
return entry.getValue() instanceof InResource inResource && resourceId.equals(inResource.getResourceId());
}
public static class ExternalizerImpl implements Externalizer<InResourcePredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InResourcePredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.resourceId, output);
}
@Override
public InResourcePredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InResourcePredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InResourcePredicate res = new InResourcePredicate();
res.resourceId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -1,70 +1,41 @@
package org.keycloak.models.cache.infinispan.authorization.stream;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.entities.InResourceServer;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@SerializeWith(InResourceServerPredicate.ExternalizerImpl.class)
public class InResourceServerPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
private String serverId;
@ProtoTypeId(Marshalling.IN_RESOURCE_SERVER_PREDICATE)
public class InResourceServerPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private final String serverId;
public static InResourceServerPredicate create() {
return new InResourceServerPredicate();
private InResourceServerPredicate(String serverId) {
this.serverId = Objects.requireNonNull(serverId);
}
public InResourceServerPredicate resourceServer(String id) {
serverId = id;
return this;
@ProtoFactory
public static InResourceServerPredicate create(String serverId) {
return new InResourceServerPredicate(serverId);
}
@ProtoField(1)
String getServerId() {
return serverId;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (!(value instanceof InResourceServer)) return false;
return serverId.equals(((InResourceServer)value).getResourceServerId());
return entry.getValue() instanceof InResourceServer inResourceServer && serverId.equals(inResourceServer.getResourceServerId());
}
public static class ExternalizerImpl implements Externalizer<InResourceServerPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InResourceServerPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.serverId, output);
}
@Override
public InResourceServerPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InResourceServerPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InResourceServerPredicate res = new InResourceServerPredicate();
res.serverId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -1,70 +1,41 @@
package org.keycloak.models.cache.infinispan.authorization.stream;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.authorization.entities.InScope;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@SerializeWith(InScopePredicate.ExternalizerImpl.class)
public class InScopePredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
private String scopeId;
@ProtoTypeId(Marshalling.IN_SCOPE_PREDICATE)
public class InScopePredicate implements Predicate<Map.Entry<String, Revisioned>> {
private final String scopeId;
public static InScopePredicate create() {
return new InScopePredicate();
private InScopePredicate(String scopeId) {
this.scopeId = Objects.requireNonNull(scopeId);
}
public InScopePredicate scope(String id) {
scopeId = id;
return this;
@ProtoFactory
public static InScopePredicate create(String scopeId) {
return new InScopePredicate(scopeId);
}
@ProtoField(1)
String getScopeId() {
return scopeId;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (!(value instanceof InScope)) return false;
return scopeId.equals(((InScope)value).getScopeId());
return entry.getValue() instanceof InScope inScope && scopeId.equals(inScope.getScopeId());
}
public static class ExternalizerImpl implements Externalizer<InScopePredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InScopePredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.scopeId, output);
}
@Override
public InScopePredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InScopePredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InScopePredicate res = new InScopePredicate();
res.scopeId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -9,8 +9,8 @@ import java.io.Serializable;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AbstractRevisioned implements Revisioned, Serializable, CachedObject {
private String id;
public class AbstractRevisioned implements Revisioned, CachedObject {
private final String id;
private Long revision;
private final long cacheTimestamp = Time.currentTimeMillis();

View file

@ -28,7 +28,9 @@ import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.common.util.ConcurrentMultivaluedHashMap;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.MultivaluedMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel;
@ -122,8 +124,8 @@ public class CachedRealm extends AbstractExtendableRevisioned {
protected String masterAdminClient;
protected List<RequiredCredentialModel> requiredCredentials;
protected MultivaluedHashMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>();
protected MultivaluedHashMap<String, ComponentModel> componentsByParentAndType = new MultivaluedHashMap<>();
protected MultivaluedMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>();
protected MultivaluedMap<String, ComponentModel> componentsByParentAndType = new ConcurrentMultivaluedHashMap<>();
protected Map<String, ComponentModel> components;
protected List<IdentityProviderModel> identityProviders;
@ -723,11 +725,11 @@ public class CachedRealm extends AbstractExtendableRevisioned {
return requiredActionProviderList;
}
public MultivaluedHashMap<String, ComponentModel> getComponentsByParent() {
public MultivaluedMap<String, ComponentModel> getComponentsByParent() {
return componentsByParent;
}
public MultivaluedHashMap<String, ComponentModel> getComponentsByParentAndType() {
public MultivaluedMap<String, ComponentModel> getComponentsByParentAndType() {
return componentsByParentAndType;
}

View file

@ -16,115 +16,80 @@
*/
package org.keycloak.models.cache.infinispan.events;
import org.keycloak.cluster.ClusterEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.marshalling.Marshalling;
/**
*
* @author hmlnarik
*/
@SerializeWith(AuthenticationSessionAuthNoteUpdateEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.AUTHENTICATION_SESSION_AUTH_NOTE_UPDATE_EVENT)
public class AuthenticationSessionAuthNoteUpdateEvent implements ClusterEvent {
private String authSessionId;
private String tabId;
private String clientUUID;
private final String authSessionId;
private final String tabId;
private final Map<String, String> authNotesFragment;
private Map<String, String> authNotesFragment;
private AuthenticationSessionAuthNoteUpdateEvent(Map<String, String> authNotesFragment, String authSessionId, String tabId) {
this.authNotesFragment = Objects.requireNonNull(authNotesFragment);
this.authSessionId = Objects.requireNonNull(authSessionId);
this.tabId = Objects.requireNonNull(tabId);
}
/**
* Creates an instance of the event.
* @param authSessionId
* @param authNotesFragment
*
* @return Event. Note that {@code authNotesFragment} property is not thread safe which is fine for now.
*/
public static AuthenticationSessionAuthNoteUpdateEvent create(String authSessionId, String tabId, String clientUUID, Map<String, String> authNotesFragment) {
AuthenticationSessionAuthNoteUpdateEvent event = new AuthenticationSessionAuthNoteUpdateEvent();
event.authSessionId = authSessionId;
event.tabId = tabId;
event.clientUUID = clientUUID;
event.authNotesFragment = new LinkedHashMap<>(authNotesFragment);
return event;
@ProtoFactory
public static AuthenticationSessionAuthNoteUpdateEvent create(String authSessionId, String tabId, Map<String, String> authNotesFragment) {
return new AuthenticationSessionAuthNoteUpdateEvent(authNotesFragment, authSessionId, tabId);
}
@ProtoField(1)
public String getAuthSessionId() {
return authSessionId;
}
@ProtoField(2)
public String getTabId() {
return tabId;
}
public String getClientUUID() {
return clientUUID;
}
@ProtoField(value = 3, mapImplementation = LinkedHashMap.class)
public Map<String, String> getAuthNotesFragment() {
return authNotesFragment;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AuthenticationSessionAuthNoteUpdateEvent that = (AuthenticationSessionAuthNoteUpdateEvent) o;
return Objects.equals(authSessionId, that.authSessionId) && Objects.equals(tabId, that.tabId) && Objects.equals(clientUUID, that.clientUUID);
return Objects.equals(authSessionId, that.authSessionId) && Objects.equals(tabId, that.tabId);
}
@Override
public int hashCode() {
return Objects.hash(authSessionId, tabId, clientUUID);
return Objects.hash(authSessionId, tabId);
}
@Override
public String toString() {
return String.format("AuthenticationSessionAuthNoteUpdateEvent [ authSessionId=%s, tabId=%s, clientUUID=%s, authNotesFragment=%s ]",
authSessionId, clientUUID, authNotesFragment);
return String.format("AuthenticationSessionAuthNoteUpdateEvent [ authSessionId=%s, tabId=%s, authNotesFragment=%s ]",
authSessionId, tabId, authNotesFragment);
}
public static class ExternalizerImpl implements Externalizer<AuthenticationSessionAuthNoteUpdateEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, AuthenticationSessionAuthNoteUpdateEvent value) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(value.authSessionId, output);
MarshallUtil.marshallString(value.tabId, output);
MarshallUtil.marshallString(value.clientUUID, output);
MarshallUtil.marshallMap(value.authNotesFragment, output);
}
@Override
public AuthenticationSessionAuthNoteUpdateEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public AuthenticationSessionAuthNoteUpdateEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
return create(
MarshallUtil.unmarshallString(input),
MarshallUtil.unmarshallString(input),
MarshallUtil.unmarshallString(input),
MarshallUtil.<String, String, Map<String, String>>unmarshallMap(input, HashMap::new)
);
}
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
abstract class BaseClientEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoField(2)
final String realmId;
BaseClientEvent(String clientUuid, String realmId) {
super(clientUuid);
this.realmId = Objects.requireNonNull(realmId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseClientEvent that = (BaseClientEvent) o;
return realmId.equals(that.realmId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + realmId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ realmId=%s, clientUuid=%s ]", getClass().getSimpleName(), realmId, getId());
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
abstract class BaseClientScopeEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoField(2)
final String realmId;
BaseClientScopeEvent(String clientScopeId, String realmId) {
super(clientScopeId);
this.realmId = Objects.requireNonNull(realmId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseClientScopeEvent that = (BaseClientScopeEvent) o;
return realmId.equals(that.realmId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + realmId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ clientScopeId=%s, realmId=%s ]", getClass().getSimpleName(), getId(), realmId);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
abstract class BaseRealmEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoField(2)
final String realmName;
BaseRealmEvent(String realmId, String realmName) {
super(realmId);
this.realmName = Objects.requireNonNull(realmName);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseRealmEvent that = (BaseRealmEvent) o;
return realmName.equals(that.realmName);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + realmName.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ realmId=%s, realmName=%s ]", getClass().getSimpleName(), getId(), realmName);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
abstract class BaseRoleEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoField(2)
final String containerId;
BaseRoleEvent(String roleId, String containerId) {
super(roleId);
this.containerId = Objects.requireNonNull(containerId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BaseRoleEvent that = (BaseRoleEvent) o;
return containerId.equals(that.containerId);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + containerId.hashCode();
return result;
}
@Override
public String toString() {
return String.format("%s [ roleId=%s, containerId=%s ]", getClass().getSimpleName(), getId(), containerId);
}
}

View file

@ -17,94 +17,30 @@
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ClientAddedEvent.ExternalizerImpl.class)
public class ClientAddedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoTypeId(Marshalling.CLIENT_ADDED_EVENT)
public class ClientAddedEvent extends BaseClientEvent {
private String clientUuid;
private String clientId;
private String realmId;
public static ClientAddedEvent create(String clientUuid, String clientId, String realmId) {
ClientAddedEvent event = new ClientAddedEvent();
event.clientUuid = clientUuid;
event.clientId = clientId;
event.realmId = realmId;
return event;
@ProtoFactory
ClientAddedEvent(String id, String realmId) {
super(id, realmId);
}
@Override
public String getId() {
return clientUuid;
}
@Override
public String toString() {
return String.format("ClientAddedEvent [ realmId=%s, clientUuid=%s, clientId=%s ]", realmId, clientUuid, clientId);
public static ClientAddedEvent create(String clientUuid, String realmId) {
return new ClientAddedEvent(clientUuid, realmId);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientAdded(realmId, invalidations);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientAddedEvent that = (ClientAddedEvent) o;
return Objects.equals(clientUuid, that.clientUuid) && Objects.equals(clientId, that.clientId) && Objects.equals(realmId, that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientUuid, clientId, realmId);
}
public static class ExternalizerImpl implements Externalizer<ClientAddedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientAddedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientUuid, output);
MarshallUtil.marshallString(obj.clientId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public ClientAddedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientAddedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientAddedEvent res = new ClientAddedEvent();
res.clientUuid = MarshallUtil.unmarshallString(input);
res.clientId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -20,73 +20,56 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.jboss.logging.Logger;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ClientRemovedEvent.ExternalizerImpl.class)
public class ClientRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoTypeId(Marshalling.CLIENT_REMOVED_EVENT)
public class ClientRemovedEvent extends BaseClientEvent {
private String clientUuid;
private String clientId;
private String realmId;
@ProtoField(3)
final String clientId;
// roleId -> roleName
private Map<String, String> clientRoles;
private static final Logger log = Logger.getLogger(ClientRemovedEvent.class);
@ProtoField(4)
final Map<String, String> clientRoles;
@ProtoFactory
ClientRemovedEvent(String id, String realmId, String clientId, Map<String, String> clientRoles) {
super(id, realmId);
this.clientId = Objects.requireNonNull(clientId);
this.clientRoles = Objects.requireNonNull(clientRoles);
}
public static ClientRemovedEvent create(ClientModel client) {
log.tracev("Created; clientId={0}", client.getClientId());
ClientRemovedEvent event = new ClientRemovedEvent();
event.realmId = client.getRealm().getId();
event.clientUuid = client.getId();
event.clientId = client.getClientId();
event.clientRoles = client.getRolesStream().collect(Collectors.toMap(RoleModel::getId, RoleModel::getName));
return event;
var clientRoles = client.getRolesStream().collect(Collectors.toMap(RoleModel::getId, RoleModel::getName));
return new ClientRemovedEvent(client.getId(), client.getClientId(), client.getRealm().getId(), clientRoles);
}
@Override
protected void finalize() throws Throwable {
log.tracev("Finalized; clientId={0}", clientId);
super.finalize();
}
@Override
public String getId() {
return clientUuid;
}
@Override
public String toString() {
return String.format("ClientRemovedEvent [ realmId=%s, clientUuid=%s, clientId=%s, clientRoleIds=%s ]", realmId, clientUuid, clientId, clientRoles);
return String.format("ClientRemovedEvent [ realmId=%s, clientUuid=%s, clientId=%s, clientRoleIds=%s ]", realmId, getId(), clientId, clientRoles);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientRemoval(realmId, clientUuid, clientId, invalidations);
realmCache.clientRemoval(realmId, getId(), clientId, invalidations);
// Separate iteration for all client roles to invalidate records dependent on them
for (Map.Entry<String, String> clientRole : clientRoles.entrySet()) {
String roleId = clientRole.getKey();
String roleName = clientRole.getValue();
realmCache.roleRemoval(roleId, roleName, clientUuid, invalidations);
realmCache.roleRemoval(roleId, roleName, getId(), invalidations);
}
}
@ -96,56 +79,15 @@ public class ClientRemovedEvent extends InvalidationEvent implements RealmCacheI
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientRemovedEvent that = (ClientRemovedEvent) o;
boolean equals = Objects.equals(clientUuid, that.clientUuid) &&
Objects.equals(clientId, that.clientId) &&
Objects.equals(realmId, that.realmId) &&
Objects.equals(clientRoles, that.clientRoles);
log.tracev("Equals; clientId={0}, equals={1}", clientId, equals);
return equals;
return clientId.equals(that.clientId) &&
clientRoles.equals(that.clientRoles);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientUuid, clientId, realmId, clientRoles);
}
public static class ExternalizerImpl implements Externalizer<ClientRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientUuid, output);
MarshallUtil.marshallString(obj.clientId, output);
MarshallUtil.marshallString(obj.realmId, output);
KeycloakMarshallUtil.writeMap(obj.clientRoles, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
log.tracev("Write; clientId={0}", obj.clientId);
}
@Override
public ClientRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientRemovedEvent res = new ClientRemovedEvent();
res.clientUuid = MarshallUtil.unmarshallString(input);
res.clientId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
res.clientRoles = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT,
size -> new ConcurrentHashMap<>(size));
log.tracev("Read; clientId={0}", res.clientId);
return res;
}
int result = super.hashCode();
result = 31 * result + clientId.hashCode();
result = 31 * result + clientRoles.hashCode();
return result;
}
}

View file

@ -17,87 +17,27 @@
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
@SerializeWith(ClientScopeAddedEvent.ExternalizerImpl.class)
public class ClientScopeAddedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoTypeId(Marshalling.CLIENT_SCOPE_ADDED_EVENT)
public class ClientScopeAddedEvent extends BaseClientScopeEvent {
private String clientScopeId;
private String realmId;
@ProtoFactory
ClientScopeAddedEvent(String id, String realmId) {
super(id, realmId);
}
public static ClientScopeAddedEvent create(String clientScopeId, String realmId) {
ClientScopeAddedEvent event = new ClientScopeAddedEvent();
event.clientScopeId = clientScopeId;
event.realmId = realmId;
return event;
}
@Override
public String getId() {
return clientScopeId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientScopeAddedEvent that = (ClientScopeAddedEvent) o;
return Objects.equals(clientScopeId, that.clientScopeId) && Objects.equals(realmId, that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientScopeId, realmId);
}
@Override
public String toString() {
return String.format("ClientScopeAddedEvent [ clientScopeId=%s, realmId=%s ]", clientScopeId, realmId);
return new ClientScopeAddedEvent(clientScopeId, realmId);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientScopeAdded(realmId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ClientScopeAddedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientScopeAddedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientScopeId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public ClientScopeAddedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientScopeAddedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientScopeAddedEvent res = new ClientScopeAddedEvent();
res.clientScopeId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -17,88 +17,27 @@
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
@ProtoTypeId(Marshalling.CLIENT_SCOPE_REMOVED_EVENT)
public class ClientScopeRemovedEvent extends BaseClientScopeEvent {
@SerializeWith(ClientScopeRemovedEvent.ExternalizerImpl.class)
public class ClientScopeRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String clientScopeId;
private String realmId;
@ProtoFactory
ClientScopeRemovedEvent(String id, String realmId) {
super(id, realmId);
}
public static ClientScopeRemovedEvent create(String clientScopeId, String realmId) {
ClientScopeRemovedEvent event = new ClientScopeRemovedEvent();
event.clientScopeId = clientScopeId;
event.realmId = realmId;
return event;
}
@Override
public String getId() {
return clientScopeId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientScopeRemovedEvent that = (ClientScopeRemovedEvent) o;
return Objects.equals(clientScopeId, that.clientScopeId) && Objects.equals(realmId, that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientScopeId, realmId);
}
@Override
public String toString() {
return String.format("ClientScopeRemovedEvent [ clientScopeId=%s, realmId=%s ]", clientScopeId, realmId);
return new ClientScopeRemovedEvent(clientScopeId, realmId);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientScopeRemoval(realmId, invalidations);
}
public static class ExternalizerImpl implements Externalizer<ClientScopeRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientScopeRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientScopeId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public ClientScopeRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientScopeRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientScopeRemovedEvent res = new ClientScopeRemovedEvent();
res.clientScopeId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -1,106 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* TODO Leave the name ClientTemplateEvent just due the backwards compatibility of infinispan migration. See if can be renamed based on
* rolling upgrades plan...
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ClientTemplateEvent.ExternalizerImpl.class)
public class ClientTemplateEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String clientTemplateId;
public static ClientTemplateEvent create(String clientTemplateId) {
ClientTemplateEvent event = new ClientTemplateEvent();
event.clientTemplateId = clientTemplateId;
return event;
}
@Override
public String getId() {
return clientTemplateId;
}
@Override
public String toString() {
return "ClientTemplateEvent [ " + clientTemplateId + " ]";
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
// Nothing. ID was already invalidated
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientTemplateEvent that = (ClientTemplateEvent) o;
return Objects.equals(clientTemplateId, that.clientTemplateId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientTemplateId);
}
public static class ExternalizerImpl implements Externalizer<ClientTemplateEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientTemplateEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientTemplateId, output);
}
@Override
public ClientTemplateEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientTemplateEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientTemplateEvent res = new ClientTemplateEvent();
res.clientTemplateId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -17,94 +17,40 @@
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(ClientUpdatedEvent.ExternalizerImpl.class)
public class ClientUpdatedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoTypeId(Marshalling.CLIENT_UPDATED_EVENT)
public class ClientUpdatedEvent extends BaseClientEvent {
private String clientUuid;
private String clientId;
private String realmId;
@ProtoField(3)
final String clientId;
public static ClientUpdatedEvent create(String clientUuid, String clientId, String realmId) {
ClientUpdatedEvent event = new ClientUpdatedEvent();
event.clientUuid = clientUuid;
event.clientId = clientId;
event.realmId = realmId;
return event;
@ProtoFactory
ClientUpdatedEvent(String id, String realmId, String clientId) {
super(id, realmId);
this.clientId = clientId;
}
@Override
public String getId() {
return clientUuid;
public static ClientUpdatedEvent create(String clientUuid, String clientId, String realmId) {
return new ClientUpdatedEvent(clientUuid, realmId, clientId);
}
@Override
public String toString() {
return String.format("ClientUpdatedEvent [ realmId=%s, clientUuid=%s, clientId=%s ]", realmId, clientUuid, clientId);
return String.format("ClientUpdatedEvent [ realmId=%s, clientUuid=%s, clientId=%s ]", realmId, getId(), clientId);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.clientUpdated(realmId, clientUuid, clientId, invalidations);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ClientUpdatedEvent that = (ClientUpdatedEvent) o;
return Objects.equals(clientUuid, that.clientUuid) && Objects.equals(clientId, that.clientId) && Objects.equals(realmId, that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), clientUuid, clientId, realmId);
}
public static class ExternalizerImpl implements Externalizer<ClientUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, ClientUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientUuid, output);
MarshallUtil.marshallString(obj.clientId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public ClientUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public ClientUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
ClientUpdatedEvent res = new ClientUpdatedEvent();
res.clientUuid = MarshallUtil.unmarshallString(input);
res.clientId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
realmCache.clientUpdated(realmId, getId(), clientId, invalidations);
}
}

View file

@ -20,41 +20,42 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(GroupAddedEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.GROUP_ADDED_EVENT)
public class GroupAddedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String groupId;
private String realmId;
private String parentId;
@ProtoField(2)
final String realmId;
@ProtoField(3)
final String parentId; //parentId may be null
public static GroupAddedEvent create(String groupId, String parentId, String realmId) {
GroupAddedEvent event = new GroupAddedEvent();
event.realmId = realmId;
event.parentId = parentId;
event.groupId = groupId;
return event;
private GroupAddedEvent(String groupId, String realmId, String parentId) {
super(groupId);
this.realmId = Objects.requireNonNull(realmId);
this.parentId = parentId;
}
@Override
public String getId() {
return groupId;
@ProtoFactory
static GroupAddedEvent protoFactory(String id, String realmId, String parentId) {
return new GroupAddedEvent(id, realmId, Marshalling.emptyStringToNull(parentId));
}
public static GroupAddedEvent create(String groupId, String parentId, String realmId) {
return new GroupAddedEvent(groupId, realmId, parentId);
}
@Override
public String toString() {
return String.format("GroupAddedEvent [ realmId=%s, groupId=%s ]", realmId, groupId);
return String.format("GroupAddedEvent [ realmId=%s, groupId=%s ]", realmId, getId());
}
@Override
@ -70,56 +71,16 @@ public class GroupAddedEvent extends InvalidationEvent implements RealmCacheInva
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
GroupAddedEvent that = (GroupAddedEvent) o;
return Objects.equals(groupId, that.groupId) && Objects.equals(realmId, that.realmId) && Objects.equals(parentId, that.parentId);
return realmId.equals(that.realmId) && Objects.equals(parentId, that.parentId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), groupId, realmId, parentId);
}
public static class ExternalizerImpl implements Externalizer<GroupAddedEvent> {
private static final int VERSION_1 = 1;
private static final int VERSION_2 = 2;
@Override
public void writeObject(ObjectOutput output, GroupAddedEvent obj) throws IOException {
output.writeByte(VERSION_2);
MarshallUtil.marshallString(obj.groupId, output);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.parentId, output);
}
@Override
public GroupAddedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
case VERSION_2:
return readObjectVersion2(input);
default:
throw new IOException("Unknown version");
}
}
public GroupAddedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupAddedEvent res = new GroupAddedEvent();
res.groupId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
public GroupAddedEvent readObjectVersion2(ObjectInput input) throws IOException, ClassNotFoundException {
GroupAddedEvent res = new GroupAddedEvent();
res.groupId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
res.parentId = MarshallUtil.unmarshallString(input);
return res;
}
int result = super.hashCode();
result = 31 * result + realmId.hashCode();
result = 31 * result + Objects.hashCode(parentId);
return result;
}
}

View file

@ -20,49 +20,51 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.GroupModel;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(GroupMovedEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.GROUP_MOVED_EVENT)
public class GroupMovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String groupId;
private String newParentId; // null if moving to top-level
private String oldParentId; // null if moving from top-level
private String realmId;
@ProtoField(2)
final String newParentId; // null if moving to top-level
@ProtoField(3)
final String oldParentId; // null if moving from top-level
@ProtoField(4)
final String realmId;
public static GroupMovedEvent create(GroupModel group, GroupModel toParent, String realmId) {
GroupMovedEvent event = new GroupMovedEvent();
event.realmId = realmId;
event.groupId = group.getId();
event.oldParentId = group.getParentId();
event.newParentId = toParent==null ? null : toParent.getId();
return event;
private GroupMovedEvent(String groupId, String newParentId, String oldParentId, String realmId) {
super(groupId);
this.newParentId = newParentId;
this.oldParentId = oldParentId;
this.realmId = Objects.requireNonNull(realmId);
}
@Override
public String getId() {
return groupId;
@ProtoFactory
static GroupMovedEvent protoFactory(String id, String newParentId, String oldParentId, String realmId) {
return new GroupMovedEvent(id, Marshalling.emptyStringToNull(newParentId), Marshalling.emptyStringToNull(oldParentId), realmId);
}
public static GroupMovedEvent create(GroupModel group, GroupModel toParent, String realmId) {
return new GroupMovedEvent(group.getId(), group.getId(), toParent == null ? null : toParent.getId(), realmId);
}
@Override
public String toString() {
return String.format("GroupMovedEvent [ realmId=%s, groupId=%s, newParentId=%s, oldParentId=%s ]", realmId, groupId, newParentId, oldParentId);
return String.format("GroupMovedEvent [ realmId=%s, groupId=%s, newParentId=%s, oldParentId=%s ]", realmId, getId(), newParentId, oldParentId);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.groupQueriesInvalidations(realmId, invalidations);
realmCache.groupNameInvalidations(groupId, invalidations);
realmCache.groupNameInvalidations(getId(), invalidations);
if (newParentId != null) {
invalidations.add(newParentId);
}
@ -76,47 +78,19 @@ public class GroupMovedEvent extends InvalidationEvent implements RealmCacheInva
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
GroupMovedEvent that = (GroupMovedEvent) o;
return Objects.equals(groupId, that.groupId) && Objects.equals(newParentId, that.newParentId) && Objects.equals(oldParentId, that.oldParentId) && Objects.equals(realmId, that.realmId);
return Objects.equals(newParentId, that.newParentId) &&
Objects.equals(oldParentId, that.oldParentId) &&
realmId.equals(that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), groupId, newParentId, oldParentId, realmId);
}
public static class ExternalizerImpl implements Externalizer<GroupMovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, GroupMovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.groupId, output);
MarshallUtil.marshallString(obj.newParentId, output);
MarshallUtil.marshallString(obj.oldParentId, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public GroupMovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public GroupMovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupMovedEvent res = new GroupMovedEvent();
res.groupId = MarshallUtil.unmarshallString(input);
res.newParentId = MarshallUtil.unmarshallString(input);
res.oldParentId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
int result = super.hashCode();
result = 31 * result + Objects.hashCode(newParentId);
result = 31 * result + Objects.hashCode(oldParentId);
result = 31 * result + realmId.hashCode();
return result;
}
}

View file

@ -20,47 +20,48 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.GroupModel;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(GroupRemovedEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.GROUP_REMOVED_EVENT)
public class GroupRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String groupId;
private String parentId;
private String realmId;
@ProtoField(2)
final String realmId;
@ProtoField(3)
final String parentId;
public static GroupRemovedEvent create(GroupModel group, String realmId) {
GroupRemovedEvent event = new GroupRemovedEvent();
event.realmId = realmId;
event.groupId = group.getId();
event.parentId = group.getParentId();
return event;
public GroupRemovedEvent(String groupId, String realmId, String parentId) {
super(groupId);
this.realmId = Objects.requireNonNull(realmId);
this.parentId = parentId;
}
@Override
public String getId() {
return groupId;
@ProtoFactory
static GroupRemovedEvent protoFactory(String id, String realmId, String parentId) {
return new GroupRemovedEvent(id, realmId, Marshalling.emptyStringToNull(parentId));
}
public static GroupRemovedEvent create(GroupModel group, String realmId) {
return new GroupRemovedEvent(group.getId(), realmId, group.getParentId());
}
@Override
public String toString() {
return String.format("GroupRemovedEvent [ realmId=%s, groupId=%s, parentId=%s ]", realmId, groupId, parentId);
return String.format("GroupRemovedEvent [ realmId=%s, groupId=%s, parentId=%s ]", realmId, getId(), parentId);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.groupQueriesInvalidations(realmId, invalidations);
realmCache.groupNameInvalidations(groupId, invalidations);
realmCache.groupNameInvalidations(getId(), invalidations);
if (parentId != null) {
invalidations.add(parentId);
}
@ -71,45 +72,16 @@ public class GroupRemovedEvent extends InvalidationEvent implements RealmCacheIn
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
GroupRemovedEvent that = (GroupRemovedEvent) o;
return Objects.equals(groupId, that.groupId) && Objects.equals(parentId, that.parentId) && Objects.equals(realmId, that.realmId);
return realmId.equals(that.realmId) && Objects.equals(parentId, that.parentId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), groupId, parentId, realmId);
}
public static class ExternalizerImpl implements Externalizer<GroupRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, GroupRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.groupId, output);
MarshallUtil.marshallString(obj.parentId, output);
}
@Override
public GroupRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public GroupRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupRemovedEvent res = new GroupRemovedEvent();
res.realmId = MarshallUtil.unmarshallString(input);
res.groupId = MarshallUtil.unmarshallString(input);
res.parentId = MarshallUtil.unmarshallString(input);
return res;
}
int result = super.hashCode();
result = 31 * result + realmId.hashCode();
result = 31 * result + Objects.hashCode(parentId);
return result;
}
}

View file

@ -19,70 +19,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(GroupUpdatedEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.GROUP_UPDATED_EVENT)
public class GroupUpdatedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
private String groupId;
@ProtoFactory
GroupUpdatedEvent(String id) {
super(id);
}
public static GroupUpdatedEvent create(String groupId) {
GroupUpdatedEvent event = new GroupUpdatedEvent();
event.groupId = groupId;
return event;
return new GroupUpdatedEvent(groupId);
}
@Override
public String getId() {
return groupId;
}
@Override
public String toString() {
return "GroupUpdatedEvent [ " + groupId + " ]";
return "GroupUpdatedEvent [ " + getId() + " ]";
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.groupNameInvalidations(groupId, invalidations);
realmCache.groupNameInvalidations(getId(), invalidations);
}
public static class ExternalizerImpl implements Externalizer<GroupUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, GroupUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.groupId, output);
}
@Override
public GroupUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public GroupUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupUpdatedEvent res = new GroupUpdatedEvent();
res.groupId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -17,6 +17,9 @@
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.cluster.ClusterEvent;
/**
@ -24,7 +27,16 @@ import org.keycloak.cluster.ClusterEvent;
*/
public abstract class InvalidationEvent implements ClusterEvent {
public abstract String getId();
private final String id;
protected InvalidationEvent(String id) {
this.id = Objects.requireNonNull(id);
}
@ProtoField(1)
public final String getId() {
return id;
}
@Override
public int hashCode() {
@ -37,7 +49,6 @@ public abstract class InvalidationEvent implements ClusterEvent {
if (!obj.getClass().equals(this.getClass())) return false;
InvalidationEvent that = (InvalidationEvent) obj;
if (!that.getId().equals(getId())) return false;
return true;
return that.getId().equals(getId());
}
}

View file

@ -17,90 +17,30 @@
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(RealmRemovedEvent.ExternalizerImpl.class)
public class RealmRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoTypeId(Marshalling.REALM_REMOVED_EVENT)
public class RealmRemovedEvent extends BaseRealmEvent {
private String realmId;
private String realmName;
@ProtoFactory
RealmRemovedEvent(String id, String realmName) {
super(id, realmName);
}
public static RealmRemovedEvent create(String realmId, String realmName) {
RealmRemovedEvent event = new RealmRemovedEvent();
event.realmId = realmId;
event.realmName = realmName;
return event;
}
@Override
public String getId() {
return realmId;
}
@Override
public String toString() {
return String.format("RealmRemovedEvent [ realmId=%s, realmName=%s ]", realmId, realmName);
return new RealmRemovedEvent(realmId, realmName);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.realmRemoval(realmId, realmName, invalidations);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
RealmRemovedEvent that = (RealmRemovedEvent) o;
return Objects.equals(realmId, that.realmId) && Objects.equals(realmName, that.realmName);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), realmId, realmName);
}
public static class ExternalizerImpl implements Externalizer<RealmRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RealmRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.realmName, output);
}
@Override
public RealmRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RealmRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RealmRemovedEvent res = new RealmRemovedEvent();
res.realmId = MarshallUtil.unmarshallString(input);
res.realmName = MarshallUtil.unmarshallString(input);
return res;
}
realmCache.realmRemoval(getId(), realmName, invalidations);
}
}

View file

@ -17,90 +17,30 @@
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(RealmUpdatedEvent.ExternalizerImpl.class)
public class RealmUpdatedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoTypeId(Marshalling.REALM_UPDATED_EVENT)
public class RealmUpdatedEvent extends BaseRealmEvent {
private String realmId;
private String realmName;
@ProtoFactory
RealmUpdatedEvent(String id, String realmName) {
super(id, realmName);
}
public static RealmUpdatedEvent create(String realmId, String realmName) {
RealmUpdatedEvent event = new RealmUpdatedEvent();
event.realmId = realmId;
event.realmName = realmName;
return event;
}
@Override
public String getId() {
return realmId;
}
@Override
public String toString() {
return String.format("RealmUpdatedEvent [ realmId=%s, realmName=%s ]", realmId, realmName);
return new RealmUpdatedEvent(realmId, realmName);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.realmUpdated(realmId, realmName, invalidations);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
RealmUpdatedEvent that = (RealmUpdatedEvent) o;
return Objects.equals(realmId, that.realmId) && Objects.equals(realmName, that.realmName);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), realmId, realmName);
}
public static class ExternalizerImpl implements Externalizer<RealmUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RealmUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.realmName, output);
}
@Override
public RealmUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RealmUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RealmUpdatedEvent res = new RealmUpdatedEvent();
res.realmId = MarshallUtil.unmarshallString(input);
res.realmName = MarshallUtil.unmarshallString(input);
return res;
}
realmCache.realmUpdated(getId(), realmName, invalidations);
}
}

View file

@ -17,90 +17,30 @@
package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(RoleAddedEvent.ExternalizerImpl.class)
public class RoleAddedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoTypeId(Marshalling.ROLE_ADDED_EVENT)
public class RoleAddedEvent extends BaseRoleEvent {
private String roleId;
private String containerId;
@ProtoFactory
RoleAddedEvent(String id, String containerId) {
super(id, containerId);
}
public static RoleAddedEvent create(String roleId, String containerId) {
RoleAddedEvent event = new RoleAddedEvent();
event.roleId = roleId;
event.containerId = containerId;
return event;
}
@Override
public String getId() {
return roleId;
}
@Override
public String toString() {
return String.format("RoleAddedEvent [ roleId=%s, containerId=%s ]", roleId, containerId);
return new RoleAddedEvent(roleId, containerId);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.roleAdded(containerId, invalidations);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
RoleAddedEvent that = (RoleAddedEvent) o;
return Objects.equals(roleId, that.roleId) && Objects.equals(containerId, that.containerId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), roleId, containerId);
}
public static class ExternalizerImpl implements Externalizer<RoleAddedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RoleAddedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.roleId, output);
MarshallUtil.marshallString(obj.containerId, output);
}
@Override
public RoleAddedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RoleAddedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RoleAddedEvent res = new RoleAddedEvent();
res.roleId = MarshallUtil.unmarshallString(input);
res.containerId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -20,45 +20,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(RoleRemovedEvent.ExternalizerImpl.class)
public class RoleRemovedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoTypeId(Marshalling.ROLE_REMOVED_EVENT)
public class RoleRemovedEvent extends BaseRoleEvent {
private String roleId;
private String roleName;
private String containerId;
@ProtoField(3)
final String roleName;
@ProtoFactory
RoleRemovedEvent(String id, String containerId, String roleName) {
super(id, containerId);
this.roleName = Objects.requireNonNull(roleName);
}
public static RoleRemovedEvent create(String roleId, String roleName, String containerId) {
RoleRemovedEvent event = new RoleRemovedEvent();
event.roleId = roleId;
event.roleName = roleName;
event.containerId = containerId;
return event;
}
@Override
public String getId() {
return roleId;
}
@Override
public String toString() {
return String.format("RoleRemovedEvent [ roleId=%s, containerId=%s ]", roleId, containerId);
return new RoleRemovedEvent(roleId, containerId, roleName);
}
@Override
public void addInvalidations(RealmCacheManager realmCache, Set<String> invalidations) {
realmCache.roleRemoval(roleId, roleName, containerId, invalidations);
realmCache.roleRemoval(getId(), roleName, containerId, invalidations);
}
@Override
@ -66,45 +55,15 @@ public class RoleRemovedEvent extends InvalidationEvent implements RealmCacheInv
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
RoleRemovedEvent that = (RoleRemovedEvent) o;
return Objects.equals(roleId, that.roleId) && Objects.equals(roleName, that.roleName) && Objects.equals(containerId, that.containerId);
return roleName.equals(that.roleName);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), roleId, roleName, containerId);
}
public static class ExternalizerImpl implements Externalizer<RoleRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RoleRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.roleId, output);
MarshallUtil.marshallString(obj.roleName, output);
MarshallUtil.marshallString(obj.containerId, output);
}
@Override
public RoleRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RoleRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RoleRemovedEvent res = new RoleRemovedEvent();
res.roleId = MarshallUtil.unmarshallString(input);
res.roleName = MarshallUtil.unmarshallString(input);
res.containerId = MarshallUtil.unmarshallString(input);
return res;
}
int result = super.hashCode();
result = 31 * result + roleName.hashCode();
return result;
}
}

View file

@ -20,40 +20,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.RealmCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(RoleUpdatedEvent.ExternalizerImpl.class)
public class RoleUpdatedEvent extends InvalidationEvent implements RealmCacheInvalidationEvent {
@ProtoTypeId(Marshalling.ROLE_UPDATED_EVENT)
public class RoleUpdatedEvent extends BaseRoleEvent {
private String roleId;
private String roleName;
private String containerId;
@ProtoField(3)
final String roleName;
public static RoleUpdatedEvent create(String roleId, String roleName, String containerId) {
RoleUpdatedEvent event = new RoleUpdatedEvent();
event.roleId = roleId;
event.roleName = roleName;
event.containerId = containerId;
return event;
@ProtoFactory
RoleUpdatedEvent(String id, String containerId, String roleName) {
super(id, containerId);
this.roleName = Objects.requireNonNull(roleName);
}
@Override
public String getId() {
return roleId;
public static RoleUpdatedEvent create(String roleId, String roleName, String containerId) {
return new RoleUpdatedEvent(roleId, containerId, roleName);
}
@Override
public String toString() {
return String.format("RoleUpdatedEvent [ roleId=%s, roleName=%s, containerId=%s ]", roleId, roleName, containerId);
return String.format("RoleUpdatedEvent [ roleId=%s, roleName=%s, containerId=%s ]", getId(), roleName, containerId);
}
@Override
@ -66,45 +60,15 @@ public class RoleUpdatedEvent extends InvalidationEvent implements RealmCacheInv
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
RoleUpdatedEvent that = (RoleUpdatedEvent) o;
return Objects.equals(roleId, that.roleId) && Objects.equals(roleName, that.roleName) && Objects.equals(containerId, that.containerId);
return roleName.equals(that.roleName);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), roleId, roleName, containerId);
}
public static class ExternalizerImpl implements Externalizer<RoleUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RoleUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.roleId, output);
MarshallUtil.marshallString(obj.roleName, output);
MarshallUtil.marshallString(obj.containerId, output);
}
@Override
public RoleUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RoleUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RoleUpdatedEvent res = new RoleUpdatedEvent();
res.roleId = MarshallUtil.unmarshallString(input);
res.roleName = MarshallUtil.unmarshallString(input);
res.containerId = MarshallUtil.unmarshallString(input);
return res;
}
int result = super.hashCode();
result = 31 * result + roleName.hashCode();
return result;
}
}

View file

@ -19,69 +19,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(UserCacheRealmInvalidationEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.USER_CACHE_REALM_INVALIDATION_EVENT)
public class UserCacheRealmInvalidationEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String realmId;
public static UserCacheRealmInvalidationEvent create(String realmId) {
UserCacheRealmInvalidationEvent event = new UserCacheRealmInvalidationEvent();
event.realmId = realmId;
return event;
private UserCacheRealmInvalidationEvent(String id) {
super(id);
}
@Override
public String getId() {
return realmId; // Just a placeholder
@ProtoFactory
public static UserCacheRealmInvalidationEvent create(String id) {
return new UserCacheRealmInvalidationEvent(id);
}
@Override
public String toString() {
return String.format("UserCacheRealmInvalidationEvent [ realmId=%s ]", realmId);
return String.format("UserCacheRealmInvalidationEvent [ realmId=%s ]", getId());
}
@Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.invalidateRealmUsers(realmId, invalidations);
userCache.invalidateRealmUsers(getId(), invalidations);
}
public static class ExternalizerImpl implements Externalizer<UserCacheRealmInvalidationEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserCacheRealmInvalidationEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public UserCacheRealmInvalidationEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserCacheRealmInvalidationEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserCacheRealmInvalidationEvent res = new UserCacheRealmInvalidationEvent();
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -19,69 +19,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(UserConsentsUpdatedEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.USER_CONSENTS_UPDATED_EVENT)
public class UserConsentsUpdatedEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId;
public static UserConsentsUpdatedEvent create(String userId) {
UserConsentsUpdatedEvent event = new UserConsentsUpdatedEvent();
event.userId = userId;
return event;
private UserConsentsUpdatedEvent(String id) {
super(id);
}
@Override
public String getId() {
return userId;
@ProtoFactory
public static UserConsentsUpdatedEvent create(String id) {
return new UserConsentsUpdatedEvent(id);
}
@Override
public String toString() {
return String.format("UserConsentsUpdatedEvent [ userId=%s ]", userId);
return String.format("UserConsentsUpdatedEvent [ userId=%s ]", getId());
}
@Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.consentInvalidation(userId, invalidations);
userCache.consentInvalidation(getId(), invalidations);
}
public static class ExternalizerImpl implements Externalizer<UserConsentsUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserConsentsUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
}
@Override
public UserConsentsUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserConsentsUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserConsentsUpdatedEvent res = new UserConsentsUpdatedEvent();
res.userId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -20,62 +20,65 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(UserFederationLinkRemovedEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.USER_FEDERATION_LINK_REMOVED_EVENT)
public class UserFederationLinkRemovedEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId;
private String realmId;
private String identityProviderId;
private String socialUserId;
final String realmId;
final String identityProviderId;
final String socialUserId;
private UserFederationLinkRemovedEvent(String id, String realmId, String identityProviderId, String socialUserId) {
super(id);
this.realmId = Objects.requireNonNull(realmId);
// may be null
this.identityProviderId = identityProviderId;
this.socialUserId = socialUserId;
}
public static UserFederationLinkRemovedEvent create(String userId, String realmId, FederatedIdentityModel socialLink) {
UserFederationLinkRemovedEvent event = new UserFederationLinkRemovedEvent();
event.userId = userId;
event.realmId = realmId;
if (socialLink != null) {
event.identityProviderId = socialLink.getIdentityProvider();
event.socialUserId = socialLink.getUserId();
}
return event;
String identityProviderId = socialLink == null ? null : socialLink.getIdentityProvider();
String socialUserId = socialLink == null ? null : socialLink.getUserId();
return new UserFederationLinkRemovedEvent(userId, realmId, identityProviderId, socialUserId);
}
@Override
public String getId() {
return userId;
@ProtoFactory
static UserFederationLinkRemovedEvent protoFactory(String id, String realmId, String identityProviderId, String socialUserId) {
return new UserFederationLinkRemovedEvent(id, realmId, Marshalling.emptyStringToNull(identityProviderId), Marshalling.emptyStringToNull(socialUserId));
}
@ProtoField(2)
public String getRealmId() {
return realmId;
}
@ProtoField(3)
public String getIdentityProviderId() {
return identityProviderId;
}
@ProtoField(4)
public String getSocialUserId() {
return socialUserId;
}
@Override
public String toString() {
return String.format("UserFederationLinkRemovedEvent [ userId=%s, identityProviderId=%s, socialUserId=%s ]", userId, identityProviderId, socialUserId);
return String.format("UserFederationLinkRemovedEvent [ userId=%s, identityProviderId=%s, socialUserId=%s ]", getId(), identityProviderId, socialUserId);
}
@Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.federatedIdentityLinkRemovedInvalidation(userId, realmId, identityProviderId, socialUserId, invalidations);
userCache.federatedIdentityLinkRemovedInvalidation(getId(), realmId, identityProviderId, socialUserId, invalidations);
}
@Override
@ -84,46 +87,12 @@ public class UserFederationLinkRemovedEvent extends InvalidationEvent implements
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
UserFederationLinkRemovedEvent that = (UserFederationLinkRemovedEvent) o;
return Objects.equals(userId, that.userId) && Objects.equals(realmId, that.realmId) && Objects.equals(identityProviderId, that.identityProviderId) && Objects.equals(socialUserId, that.socialUserId);
return Objects.equals(realmId, that.realmId) && Objects.equals(identityProviderId, that.identityProviderId) && Objects.equals(socialUserId, that.socialUserId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), userId, realmId, identityProviderId, socialUserId);
return Objects.hash(super.hashCode(), realmId, identityProviderId, socialUserId);
}
public static class ExternalizerImpl implements Externalizer<UserFederationLinkRemovedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserFederationLinkRemovedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
MarshallUtil.marshallString(obj.realmId, output);
MarshallUtil.marshallString(obj.identityProviderId, output);
MarshallUtil.marshallString(obj.socialUserId, output);
}
@Override
public UserFederationLinkRemovedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserFederationLinkRemovedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserFederationLinkRemovedEvent res = new UserFederationLinkRemovedEvent();
res.userId = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
res.identityProviderId = MarshallUtil.unmarshallString(input);
res.socialUserId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -18,69 +18,34 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(UserFederationLinkUpdatedEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.USER_FEDERATION_LINK_UPDATED_EVENT)
public class UserFederationLinkUpdatedEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId;
public static UserFederationLinkUpdatedEvent create(String userId) {
UserFederationLinkUpdatedEvent event = new UserFederationLinkUpdatedEvent();
event.userId = userId;
return event;
private UserFederationLinkUpdatedEvent(String id) {
super(id);
}
@Override
public String getId() {
return userId;
@ProtoFactory
public static UserFederationLinkUpdatedEvent create(String id) {
return new UserFederationLinkUpdatedEvent(id);
}
@Override
public String toString() {
return String.format("UserFederationLinkUpdatedEvent [ userId=%s ]", userId);
return String.format("UserFederationLinkUpdatedEvent [ userId=%s ]", getId());
}
@Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.federatedIdentityLinkUpdatedInvalidation(userId, invalidations);
userCache.federatedIdentityLinkUpdatedInvalidation(getId(), invalidations);
}
public static class ExternalizerImpl implements Externalizer<UserFederationLinkUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserFederationLinkUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
}
@Override
public UserFederationLinkUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserFederationLinkUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserFederationLinkUpdatedEvent res = new UserFederationLinkUpdatedEvent();
res.userId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -21,54 +21,56 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.cache.infinispan.UserCacheManager;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.cache.infinispan.UserCacheManager;
/**
* Used when user added/removed
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(UserFullInvalidationEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.USER_FULL_INVALIDATION_EVENT)
public class UserFullInvalidationEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId;
private String username;
private String email;
private String realmId;
private boolean identityFederationEnabled;
private Map<String, String> federatedIdentities;
@ProtoField(2)
final String username;
@ProtoField(3)
final String email;
@ProtoField(4)
final String realmId;
@ProtoField(5)
final boolean identityFederationEnabled;
@ProtoField(value = 6, mapImplementation = HashMap.class)
final Map<String, String> federatedIdentities;
public static UserFullInvalidationEvent create(String userId, String username, String email, String realmId, boolean identityFederationEnabled, Stream<FederatedIdentityModel> federatedIdentities) {
UserFullInvalidationEvent event = new UserFullInvalidationEvent();
event.userId = userId;
event.username = username;
event.email = email;
event.realmId = realmId;
event.identityFederationEnabled = identityFederationEnabled;
if (identityFederationEnabled) {
event.federatedIdentities = federatedIdentities.collect(Collectors.toMap(socialLink -> socialLink.getIdentityProvider(),
socialLink -> socialLink.getUserId()));
}
return event;
private UserFullInvalidationEvent(String id, String username, String email, String realmId, boolean identityFederationEnabled, Map<String, String> federatedIdentities) {
super(id);
this.username = Objects.requireNonNull(username);
this.email = email;
this.realmId = Objects.requireNonNull(realmId);
this.federatedIdentities = federatedIdentities;
this.identityFederationEnabled = identityFederationEnabled;
}
@Override
public String getId() {
return userId;
public static UserFullInvalidationEvent create(String userId, String username, String email, String realmId, boolean identityFederationEnabled, Stream<FederatedIdentityModel> federatedIdentities) {
Map<String, String> federatedIdentitiesMap = null;
if (identityFederationEnabled) {
federatedIdentitiesMap = federatedIdentities.collect(Collectors.toMap(FederatedIdentityModel::getIdentityProvider,
FederatedIdentityModel::getUserId));
}
return new UserFullInvalidationEvent(userId, username, email, realmId, identityFederationEnabled, federatedIdentitiesMap);
}
@ProtoFactory
static UserFullInvalidationEvent protoFactory(String id, String username, String email, String realmId, boolean identityFederationEnabled, Map<String, String> federatedIdentities) {
return new UserFullInvalidationEvent(id, username, Marshalling.emptyStringToNull(email), realmId, identityFederationEnabled, federatedIdentities);
}
public Map<String, String> getFederatedIdentities() {
@ -77,12 +79,12 @@ public class UserFullInvalidationEvent extends InvalidationEvent implements User
@Override
public String toString() {
return String.format("UserFullInvalidationEvent [ userId=%s, username=%s, email=%s ]", userId, username, email);
return String.format("UserFullInvalidationEvent [ userId=%s, username=%s, email=%s ]", getId(), username, email);
}
@Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.fullUserInvalidation(userId, username, email, realmId, identityFederationEnabled, federatedIdentities, invalidations);
userCache.fullUserInvalidation(getId(), username, email, realmId, identityFederationEnabled, federatedIdentities, invalidations);
}
@Override
@ -91,50 +93,12 @@ public class UserFullInvalidationEvent extends InvalidationEvent implements User
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
UserFullInvalidationEvent that = (UserFullInvalidationEvent) o;
return identityFederationEnabled == that.identityFederationEnabled && Objects.equals(userId, that.userId) && Objects.equals(username, that.username) && Objects.equals(email, that.email) && Objects.equals(realmId, that.realmId) && Objects.equals(federatedIdentities, that.federatedIdentities);
return identityFederationEnabled == that.identityFederationEnabled && Objects.equals(username, that.username) && Objects.equals(email, that.email) && Objects.equals(realmId, that.realmId) && Objects.equals(federatedIdentities, that.federatedIdentities);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), userId, username, email, realmId, identityFederationEnabled, federatedIdentities);
return Objects.hash(super.hashCode(), username, email, realmId, identityFederationEnabled, federatedIdentities);
}
public static class ExternalizerImpl implements Externalizer<UserFullInvalidationEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserFullInvalidationEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
MarshallUtil.marshallString(obj.username, output);
MarshallUtil.marshallString(obj.email, output);
MarshallUtil.marshallString(obj.realmId, output);
output.writeBoolean(obj.identityFederationEnabled);
KeycloakMarshallUtil.writeMap(obj.federatedIdentities, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
}
@Override
public UserFullInvalidationEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserFullInvalidationEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserFullInvalidationEvent res = new UserFullInvalidationEvent();
res.userId = MarshallUtil.unmarshallString(input);
res.username = MarshallUtil.unmarshallString(input);
res.email = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
res.identityFederationEnabled = input.readBoolean();
res.federatedIdentities = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, HashMap::new);
return res;
}
}
}

View file

@ -20,47 +20,49 @@ package org.keycloak.models.cache.infinispan.events;
import java.util.Objects;
import java.util.Set;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.UserCacheManager;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(UserUpdatedEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.USER_UPDATED_EVENT)
public class UserUpdatedEvent extends InvalidationEvent implements UserCacheInvalidationEvent {
private String userId;
private String username;
private String email;
private String realmId;
@ProtoField(2)
final String username;
@ProtoField(3)
final String email;
@ProtoField(4)
final String realmId;
public static UserUpdatedEvent create(String userId, String username, String email, String realmId) {
UserUpdatedEvent event = new UserUpdatedEvent();
event.userId = userId;
event.username = username;
event.email = email;
event.realmId = realmId;
return event;
private UserUpdatedEvent(String id, String username, String email, String realmId) {
super(id);
this.username = Objects.requireNonNull(username);
this.email = email;
this.realmId = Objects.requireNonNull(realmId);
}
@Override
public String getId() {
return userId;
public static UserUpdatedEvent create(String id, String username, String email, String realmId) {
return new UserUpdatedEvent(id, username, email, realmId);
}
@ProtoFactory
static UserUpdatedEvent protoFactory(String id, String username, String email, String realmId) {
return new UserUpdatedEvent(id, username, Marshalling.emptyStringToNull(email), realmId);
}
@Override
public String toString() {
return String.format("UserUpdatedEvent [ userId=%s, username=%s, email=%s ]", userId, username, email);
return String.format("UserUpdatedEvent [ userId=%s, username=%s, email=%s ]", getId(), username, email);
}
@Override
public void addInvalidations(UserCacheManager userCache, Set<String> invalidations) {
userCache.userUpdatedInvalidations(userId, username, email, realmId, invalidations);
userCache.userUpdatedInvalidations(getId(), username, email, realmId, invalidations);
}
@Override
@ -69,46 +71,12 @@ public class UserUpdatedEvent extends InvalidationEvent implements UserCacheInva
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
UserUpdatedEvent that = (UserUpdatedEvent) o;
return Objects.equals(userId, that.userId) && Objects.equals(username, that.username) && Objects.equals(email, that.email) && Objects.equals(realmId, that.realmId);
return Objects.equals(username, that.username) && Objects.equals(email, that.email) && Objects.equals(realmId, that.realmId);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), userId, username, email, realmId);
return Objects.hash(super.hashCode(), username, email, realmId);
}
public static class ExternalizerImpl implements Externalizer<UserUpdatedEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, UserUpdatedEvent obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.userId, output);
MarshallUtil.marshallString(obj.username, output);
MarshallUtil.marshallString(obj.email, output);
MarshallUtil.marshallString(obj.realmId, output);
}
@Override
public UserUpdatedEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserUpdatedEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
UserUpdatedEvent res = new UserUpdatedEvent();
res.userId = MarshallUtil.unmarshallString(input);
res.username = MarshallUtil.unmarshallString(input);
res.email = MarshallUtil.unmarshallString(input);
res.realmId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -1,24 +1,20 @@
package org.keycloak.models.cache.infinispan.stream;
import org.keycloak.models.cache.infinispan.entities.GroupListQuery;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.cache.infinispan.entities.GroupListQuery;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@SerializeWith(GroupListPredicate.ExternalizerImpl.class)
public class GroupListPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
@ProtoTypeId(Marshalling.GROUP_LIST_PREDICATE)
public class GroupListPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String realm;
public static GroupListPredicate create() {
@ -30,43 +26,18 @@ public class GroupListPredicate implements Predicate<Map.Entry<String, Revisione
return this;
}
@ProtoField(1)
String getRealm() {
return realm;
}
void setRealm(String realm) {
this.realm = realm;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (value instanceof GroupListQuery) {
GroupListQuery groupList = (GroupListQuery)value;
if (groupList.getRealm().equals(realm)) return true;
}
return false;
return entry.getValue() instanceof GroupListQuery groupList && groupList.getRealm().equals(realm);
}
public static class ExternalizerImpl implements Externalizer<GroupListPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, GroupListPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realm, output);
}
@Override
public GroupListPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public GroupListPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
GroupListPredicate res = new GroupListPredicate();
res.realm = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -1,28 +1,25 @@
package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.CachedClient;
import org.keycloak.models.cache.infinispan.entities.CachedClientScope;
import org.keycloak.models.cache.infinispan.entities.CachedGroup;
import org.keycloak.models.cache.infinispan.entities.CachedRole;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.models.cache.infinispan.entities.RoleQuery;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@SerializeWith(HasRolePredicate.ExternalizerImpl.class)
public class HasRolePredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
@ProtoTypeId(Marshalling.HAS_ROLE_PREDICATE)
public class HasRolePredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String role;
public static HasRolePredicate create() {
@ -34,61 +31,23 @@ public class HasRolePredicate implements Predicate<Map.Entry<String, Revisioned>
return this;
}
@ProtoField(1)
String getRole() {
return role;
}
void setRole(String role) {
this.role = role;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (value instanceof CachedRole) {
CachedRole cachedRole = (CachedRole)value;
if (cachedRole.getComposites().contains(role)) return true;
}
if (value instanceof CachedGroup) {
CachedGroup cachedRole = (CachedGroup)value;
if (cachedRole.getRoleMappings(null).contains(role)) return true;
}
if (value instanceof RoleQuery) {
RoleQuery roleQuery = (RoleQuery)value;
if (roleQuery.getRoles().contains(role)) return true;
}
if (value instanceof CachedClient) {
CachedClient cachedClient = (CachedClient)value;
if (cachedClient.getScope().contains(role)) return true;
}
if (value instanceof CachedClientScope) {
CachedClientScope cachedClientScope = (CachedClientScope)value;
if (cachedClientScope.getScope().contains(role)) return true;
}
return false;
return (value instanceof CachedRole cachedRole && cachedRole.getComposites().contains(role)) ||
(value instanceof CachedGroup cachedGroup && cachedGroup.getRoleMappings(null).contains(role)) ||
(value instanceof RoleQuery roleQuery && roleQuery.getRoles().contains(role)) ||
(value instanceof CachedClient cachedClient && cachedClient.getScope().contains(role)) ||
(value instanceof CachedClientScope cachedClientScope && cachedClientScope.getScope().contains(role));
}
public static class ExternalizerImpl implements Externalizer<HasRolePredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, HasRolePredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.role, output);
}
@Override
public HasRolePredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public HasRolePredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
HasRolePredicate res = new HasRolePredicate();
res.role = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -1,24 +1,21 @@
package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.InClient;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@SerializeWith(InClientPredicate.ExternalizerImpl.class)
public class InClientPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
@ProtoTypeId(Marshalling.IN_CLIENT_PREDICATE)
public class InClientPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String clientId;
public static InClientPredicate create() {
@ -30,41 +27,18 @@ public class InClientPredicate implements Predicate<Map.Entry<String, Revisioned
return this;
}
@ProtoField(1)
String getClientId() {
return clientId;
}
void setClientId(String clientId) {
this.clientId = clientId;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (!(value instanceof InClient)) return false;
return clientId.equals(((InClient)value).getClientId());
return entry.getValue() instanceof InClient inClient && clientId.equals(inClient.getClientId());
}
public static class ExternalizerImpl implements Externalizer<InClientPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InClientPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.clientId, output);
}
@Override
public InClientPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InClientPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InClientPredicate res = new InClientPredicate();
res.clientId = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -17,21 +17,18 @@
package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.GroupNameQuery;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
@SerializeWith(InGroupPredicate.ExternalizerImpl.class)
public class InGroupPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
@ProtoTypeId(Marshalling.IN_GROUP_PREDICATE)
public class InGroupPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String group;
public static InGroupPredicate create() {
@ -43,41 +40,19 @@ public class InGroupPredicate implements Predicate<Map.Entry<String, Revisioned>
return this;
}
@ProtoField(1)
String getGroup() {
return group;
}
void setGroup(String group) {
this.group = group;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (!(value instanceof GroupNameQuery)) return false;
return entry.getValue() instanceof GroupNameQuery groupNameQuery && group.equals(groupNameQuery.getGroupId());
return group.equals(((GroupNameQuery)value).getGroupId());
}
public static class ExternalizerImpl implements Externalizer<InGroupPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InGroupPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.group, output);
}
@Override
public InGroupPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InGroupPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InGroupPredicate res = new InGroupPredicate();
res.group = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -1,24 +1,20 @@
package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.InIdentityProvider;
import org.keycloak.models.cache.infinispan.entities.InRealm;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@SerializeWith(InIdentityProviderPredicate.ExternalizerImpl.class)
public class InIdentityProviderPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
@ProtoTypeId(Marshalling.IN_IDENTITY_PROVIDER_PREDICATE)
public class InIdentityProviderPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String id;
public static InIdentityProviderPredicate create() {
@ -30,41 +26,18 @@ public class InIdentityProviderPredicate implements Predicate<Map.Entry<String,
return this;
}
@ProtoField(1)
String getId() {
return id;
}
void setId(String id) {
this.id = id;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (!(value instanceof InIdentityProvider)) return false;
return ((InIdentityProvider)value).contains(id);
return entry.getValue() instanceof InIdentityProvider provider && provider.contains(id);
}
public static class ExternalizerImpl implements Externalizer<InIdentityProviderPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InIdentityProviderPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.id, output);
}
@Override
public InIdentityProviderPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InIdentityProviderPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InIdentityProviderPredicate res = new InIdentityProviderPredicate();
res.id = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -1,24 +1,21 @@
package org.keycloak.models.cache.infinispan.stream;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.cache.infinispan.entities.InRealm;
import org.keycloak.models.cache.infinispan.entities.Revisioned;
import org.keycloak.marshalling.Marshalling;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.Map;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@SerializeWith(InRealmPredicate.ExternalizerImpl.class)
public class InRealmPredicate implements Predicate<Map.Entry<String, Revisioned>>, Serializable {
@ProtoTypeId(Marshalling.IN_REALM_PREDICATE)
public class InRealmPredicate implements Predicate<Map.Entry<String, Revisioned>> {
private String realm;
public static InRealmPredicate create() {
@ -30,41 +27,19 @@ public class InRealmPredicate implements Predicate<Map.Entry<String, Revisioned>
return this;
}
@ProtoField(1)
String getRealm() {
return realm;
}
void setRealm(String realm) {
this.realm = realm;
}
@Override
public boolean test(Map.Entry<String, Revisioned> entry) {
Object value = entry.getValue();
if (value == null) return false;
if (!(value instanceof InRealm)) return false;
return entry.getValue() instanceof InRealm inRealm && realm.equals(inRealm.getRealm());
return realm.equals(((InRealm)value).getRealm());
}
public static class ExternalizerImpl implements Externalizer<InRealmPredicate> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, InRealmPredicate obj) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(obj.realm, output);
}
@Override
public InRealmPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public InRealmPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
InRealmPredicate res = new InRealmPredicate();
res.realm = MarshallUtil.unmarshallString(input);
return res;
}
}
}

View file

@ -23,7 +23,6 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.infinispan.Cache;
import org.jboss.logging.Logger;
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.common.util.Time;
@ -34,7 +33,7 @@ import org.keycloak.models.cache.infinispan.events.AuthenticationSessionAuthNote
import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.stream.RootAuthenticationSessionPredicate;
import org.keycloak.models.sessions.infinispan.stream.SessionPredicate;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.models.utils.SessionExpiration;
import org.keycloak.sessions.AuthenticationSessionCompoundId;
@ -120,7 +119,7 @@ public class InfinispanAuthenticationSessionProvider implements AuthenticationSe
Iterator<Map.Entry<String, RootAuthenticationSessionEntity>> itr = CacheDecorators.localCache(cache)
.entrySet()
.stream()
.filter(RootAuthenticationSessionPredicate.create(realmId))
.filter(SessionPredicate.create(realmId))
.iterator();
while (itr.hasNext()) {
@ -149,7 +148,7 @@ public class InfinispanAuthenticationSessionProvider implements AuthenticationSe
ClusterProvider cluster = session.getProvider(ClusterProvider.class);
cluster.notify(
InfinispanAuthenticationSessionProviderFactory.AUTHENTICATION_SESSION_EVENTS,
AuthenticationSessionAuthNoteUpdateEvent.create(compoundId.getRootSessionId(), compoundId.getTabId(), compoundId.getClientUUID(), authNotesFragment),
AuthenticationSessionAuthNoteUpdateEvent.create(compoundId.getRootSessionId(), compoundId.getTabId(), authNotesFragment),
true,
ClusterProvider.DCNotify.ALL_BUT_LOCAL_DC
);

View file

@ -35,7 +35,7 @@ import org.keycloak.models.sessions.infinispan.events.RemoveAllUserLoginFailures
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.stream.Mappers;
import org.keycloak.models.sessions.infinispan.stream.UserLoginFailurePredicate;
import org.keycloak.models.sessions.infinispan.stream.SessionWrapperPredicate;
import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
@ -125,7 +125,7 @@ public class InfinispanUserLoginFailureProvider implements UserLoginFailureProvi
localCacheStoreIgnore
.entrySet()
.stream()
.filter(UserLoginFailurePredicate.create(realmId))
.filter(SessionWrapperPredicate.create(realmId))
.map(Mappers.loginFailureId())
.forEach(loginFailureKey -> {
// Remove loginFailure from remoteCache too. Use removeAsync for better perf

View file

@ -24,12 +24,13 @@ import org.keycloak.Config;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserLoginFailureProvider;
import org.keycloak.models.UserLoginFailureProviderFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
@ -40,15 +41,14 @@ import org.keycloak.models.sessions.infinispan.events.AbstractUserSessionCluster
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveAllUserLoginFailuresEvent;
import org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer;
import org.keycloak.models.sessions.infinispan.initializer.InitializerState;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionsLoader;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.PostMigrationEvent;
import java.io.Serializable;
import java.util.Set;
import static org.keycloak.models.sessions.infinispan.InfinispanAuthenticationSessionProviderFactory.PROVIDER_PRIORITY;
@ -195,7 +195,7 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
@Override
public void run(KeycloakSession session) {
InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class);
Cache<String, Serializable> workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME);
Cache<String, InitializerState> workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME);
int defaultStateTransferTimeout = (int) (connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME)
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);

View file

@ -17,53 +17,6 @@
package org.keycloak.models.sessions.infinispan;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.commons.api.BasicCache;
import org.infinispan.context.Flag;
import org.infinispan.stream.CacheCollectors;
import org.jboss.logging.Logger;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time;
import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.OfflineUserSessionModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.session.UserSessionPersisterProvider;
import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey;
import org.keycloak.models.sessions.infinispan.changes.Tasks;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction;
import org.keycloak.models.sessions.infinispan.changes.SessionUpdateTask;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.stream.Mappers;
import org.keycloak.models.sessions.infinispan.stream.SessionPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.light.LightweightUserAdapter;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
@ -85,6 +38,55 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.commons.api.BasicCache;
import org.infinispan.commons.util.concurrent.CompletionStages;
import org.infinispan.context.Flag;
import org.infinispan.stream.CacheCollectors;
import org.jboss.logging.Logger;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.OfflineUserSessionModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.light.LightweightUserAdapter;
import org.keycloak.models.session.UserSessionPersisterProvider;
import org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction;
import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.changes.SessionUpdateTask;
import org.keycloak.models.sessions.infinispan.changes.Tasks;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.stream.Mappers;
import org.keycloak.models.sessions.infinispan.stream.SessionWrapperPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import static org.keycloak.models.Constants.SESSION_NOTE_LIGHTWEIGHT_USER;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
@ -270,6 +272,16 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
return getUserSession(realm, id, false);
}
@Override
public void migrate(String modelVersion) {
// Changed encoding from JBoss Marshalling to ProtoStream.
// Unable to read the cached data.
if ("26.0.0".equals(modelVersion)) {
log.debug("Clear caches to migrate to Infinispan Protostream");
CompletionStages.join(session.getProvider(InfinispanConnectionProvider.class).migrateToProtostream());
}
}
protected UserSessionAdapter getUserSession(RealmModel realm, String id, boolean offline) {
UserSessionEntity userSessionEntityFromCache = getUserSessionEntity(realm, id, offline);
@ -660,7 +672,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider, Sessi
localCacheStoreIgnore
.entrySet()
.stream()
.filter(SessionPredicate.create(realmId))
.filter(SessionWrapperPredicate.create(realmId))
.map(Mappers.userSessionEntity())
.forEach(new Consumer<UserSessionEntity>() {

View file

@ -17,6 +17,14 @@
package org.keycloak.models.sessions.infinispan;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.persistence.remote.RemoteStore;
@ -27,6 +35,7 @@ import org.keycloak.common.Profile;
import org.keycloak.common.util.Environment;
import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
@ -35,15 +44,14 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.UserSessionProviderFactory;
import org.keycloak.models.sessions.infinispan.changes.PersistentSessionsWorker;
import org.keycloak.models.sessions.infinispan.changes.PersistentUpdate;
import org.keycloak.models.sessions.infinispan.changes.SerializeExecutionsByKey;
import org.keycloak.models.sessions.infinispan.changes.PersistentSessionsWorker;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStoreFactory;
import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore;
import org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStoreFactory;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
@ -51,10 +59,11 @@ import org.keycloak.models.sessions.infinispan.events.AbstractUserSessionCluster
import org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent;
import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.initializer.InfinispanCacheInitializer;
import org.keycloak.models.sessions.infinispan.initializer.InitializerState;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionListener;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheSessionsLoader;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.PostMigrationEvent;
@ -65,15 +74,6 @@ import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener;
import org.keycloak.provider.ServerInfoAwareProviderFactory;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import static org.keycloak.models.sessions.infinispan.InfinispanAuthenticationSessionProviderFactory.PROVIDER_PRIORITY;
public class InfinispanUserSessionProviderFactory implements UserSessionProviderFactory, ServerInfoAwareProviderFactory {
@ -398,7 +398,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
@Override
public void run(KeycloakSession session) {
InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class);
Cache<String, Serializable> workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME);
Cache<String, InitializerState> workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME);
int defaultStateTransferTimeout = (int) (connections.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME)
.getCacheConfiguration().clustering().stateTransfer().timeout() / 1000);

View file

@ -17,12 +17,31 @@
package org.keycloak.models.sessions.infinispan;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import io.reactivex.rxjava3.core.Flowable;
import org.infinispan.Cache;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.exceptions.HotRodClientException;
import org.infinispan.commons.api.BasicCache;
import org.infinispan.commons.util.ByRef;
import org.infinispan.commons.util.concurrent.CompletionStages;
import org.infinispan.context.Flag;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.persistence.manager.PersistenceManager;
@ -32,8 +51,8 @@ import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.migration.ModelVersion;
import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
@ -67,7 +86,7 @@ import org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent;
import org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction;
import org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker;
import org.keycloak.models.sessions.infinispan.stream.Mappers;
import org.keycloak.models.sessions.infinispan.stream.SessionPredicate;
import org.keycloak.models.sessions.infinispan.stream.SessionWrapperPredicate;
import org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate;
import org.keycloak.models.sessions.infinispan.util.FuturesHelper;
import org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator;
@ -75,24 +94,6 @@ import org.keycloak.models.sessions.infinispan.util.SessionTimeouts;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.UserModelDelegate;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.keycloak.models.Constants.SESSION_NOTE_LIGHTWEIGHT_USER;
import static org.keycloak.utils.StreamsUtil.paginatedStream;
@ -559,7 +560,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
sessions
.entrySet()
.stream()
.filter(SessionPredicate.create(realmId))
.filter(SessionWrapperPredicate.create(realmId))
.map(Mappers.userSessionEntity())
.forEach((Consumer<UserSessionEntity>) userSessionEntity -> {
userSessionsSize.incrementAndGet();
@ -586,7 +587,7 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
sessions
.entrySet()
.stream()
.filter(SessionPredicate.create(realmId))
.filter(UserSessionPredicate.create(realmId))
.map(Mappers.userSessionEntity())
.forEach((Consumer<UserSessionEntity>) userSessionEntity -> {
userSessionsSize.incrementAndGet();
@ -1013,8 +1014,11 @@ public class PersistentUserSessionProvider implements UserSessionProvider, Sessi
@Override
public void migrate(String modelVersion) {
if (new ModelVersion(modelVersion).equals(new ModelVersion("25.0.0"))) {
migrateNonPersistentSessionsToPersistentSessions();
// Changed encoding from JBoss Marshalling to ProtoStream.
// Unable to read the cached data.
if ("26.0.0".equals(modelVersion)) {
log.debug("Clear caches to migrate to Infinispan Protostream");
CompletionStages.join(session.getProvider(InfinispanConnectionProvider.class).migrateToProtostream());
}
}

View file

@ -10,6 +10,9 @@ import java.util.function.BiFunction;
import org.infinispan.commons.marshall.AdvancedExternalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
@ -19,13 +22,13 @@ import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
* @param <K> The Infinispan key type.
* @param <T> The Infinispan value type (Keycloak entity)
*/
@ProtoTypeId(Marshalling.REPLACE_FUNCTION)
public class ReplaceFunction<K, T extends SessionEntity> implements BiFunction<K, SessionEntityWrapper<T>, SessionEntityWrapper<T>> {
@SuppressWarnings({"removal", "rawtypes"})
public static final AdvancedExternalizer<ReplaceFunction> INSTANCE = new Externalizer();
private final UUID expectedVersion;
private final SessionEntityWrapper<T> newValue;
@ProtoFactory
public ReplaceFunction(UUID expectedVersion, SessionEntityWrapper<T> newValue) {
this.expectedVersion = Objects.requireNonNull(expectedVersion);
this.newValue = Objects.requireNonNull(newValue);
@ -37,37 +40,13 @@ public class ReplaceFunction<K, T extends SessionEntity> implements BiFunction<K
return expectedVersion.equals(currentValue.getVersion()) ? newValue : currentValue;
}
@SuppressWarnings({"removal", "rawtypes"})
private static class Externalizer implements AdvancedExternalizer<ReplaceFunction> {
@ProtoField(1)
UUID getExpectedVersion() {
return expectedVersion;
}
private static final SessionEntityWrapper.ExternalizerImpl EXTERNALIZER = new SessionEntityWrapper.ExternalizerImpl();
private static final byte VERSION_1 = 1;
@Override
public Set<Class<? extends ReplaceFunction>> getTypeClasses() {
return Set.of(ReplaceFunction.class);
}
@Override
public Integer getId() {
return Marshalling.REPLACE_FUNCTION_ID;
}
@Override
public void writeObject(ObjectOutput output, ReplaceFunction object) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallUUID(object.expectedVersion, output, false);
EXTERNALIZER.writeObject(output, object.newValue);
}
@Override
public ReplaceFunction<?,?> readObject(ObjectInput input) throws IOException, ClassNotFoundException {
var version = input.readByte();
if (version != VERSION_1) {
throw new IOException("Invalid version: " + version);
}
//noinspection unchecked
return new ReplaceFunction<Object, SessionEntity>(MarshallUtil.unmarshallUUID(input, false), EXTERNALIZER.readObject(input));
}
@ProtoField(2)
SessionEntityWrapper<T> getNewValue() {
return newValue;
}
}

View file

@ -17,32 +17,27 @@
package org.keycloak.models.sessions.infinispan.changes;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.protostream.WrappedMessage;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import java.util.HashMap;
import org.jboss.logging.Logger;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(SessionEntityWrapper.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.SESSION_ENTITY_WRAPPER)
public class SessionEntityWrapper<S extends SessionEntity> {
private static final Logger log = Logger.getLogger(SessionEntityWrapper.class);
private final UUID version;
private final S entity;
private final Map<String, String> localMetadata;
@ -87,6 +82,7 @@ public class SessionEntityWrapper<S extends SessionEntity> {
return this.version == null;
}
@ProtoField(1)
public UUID getVersion() {
return version;
}
@ -95,6 +91,26 @@ public class SessionEntityWrapper<S extends SessionEntity> {
return entity;
}
@ProtoField(2)
WrappedMessage getEntityPS() {
return new WrappedMessage(getEntity());
}
@ProtoField(value = 3, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getLocalMetadata() {
return localMetadata;
}
@ProtoFactory
static <T extends SessionEntity> SessionEntityWrapper<T> create(UUID version, WrappedMessage entityPS, Map<String, String> localMetadata) {
assert entityPS != null;
T entity = (T) entityPS.getValue();
if (version == null) {
return new SessionEntityWrapper<>(entity);
}
return new SessionEntityWrapper<>(version, localMetadata, entity);
}
public ClientModel getClientIfNeeded(RealmModel realm) {
if (entity instanceof AuthenticatedClientSessionEntity) {
String clientId = ((AuthenticatedClientSessionEntity) entity).getClientId();
@ -124,24 +140,19 @@ public class SessionEntityWrapper<S extends SessionEntity> {
localMetadata.put(key, String.valueOf(value));
}
public Map<String, String> getLocalMetadata() {
return localMetadata;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SessionEntityWrapper)) return false;
SessionEntityWrapper that = (SessionEntityWrapper) o;
if (!Objects.equals(version, that.version)) {
if (this == o) {
return true;
}
if (!(o instanceof SessionEntityWrapper)) {
return false;
}
return Objects.equals(entity, that.entity);
}
SessionEntityWrapper<?> that = (SessionEntityWrapper<?>) o;
return Objects.equals(version, that.version) && Objects.equals(entity, that.entity);
}
@Override
public int hashCode() {
@ -154,53 +165,4 @@ public class SessionEntityWrapper<S extends SessionEntity> {
return "SessionEntityWrapper{" + "version=" + version + ", entity=" + entity + ", localMetadata=" + localMetadata + '}';
}
public static class ExternalizerImpl implements Externalizer<SessionEntityWrapper> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, SessionEntityWrapper obj) throws IOException {
output.writeByte(VERSION_1);
final boolean forTransport = obj.isForTransport();
output.writeBoolean(forTransport);
if (! forTransport) {
output.writeLong(obj.getVersion().getMostSignificantBits());
output.writeLong(obj.getVersion().getLeastSignificantBits());
MarshallUtil.marshallMap(obj.localMetadata, output);
}
output.writeObject(obj.entity);
}
@Override
public SessionEntityWrapper readObject(ObjectInput input) throws IOException, ClassNotFoundException {
byte version = input.readByte();
if (version != VERSION_1) {
throw new IOException("Invalid version: " + version);
}
final boolean forTransport = input.readBoolean();
if (forTransport) {
final SessionEntity entity = (SessionEntity) input.readObject();
final SessionEntityWrapper res = new SessionEntityWrapper(entity);
if (log.isTraceEnabled()) {
log.tracef("Loaded entity from remote store: %s, version=%s, metadata=%s", entity, res.version, res.localMetadata);
}
return res;
} else {
UUID sessionVersion = new UUID(input.readLong(), input.readLong());
HashMap<String, String> map = MarshallUtil.<String, String, HashMap<String, String>>unmarshallMap(input, HashMap::new);
final SessionEntity entity = (SessionEntity) input.readObject();
if (log.isTraceEnabled()) {
log.tracef("Found entity locally: entity=%s, version=%s, metadata=%s", entity, sessionVersion, map);
}
return new SessionEntityWrapper(sessionVersion, map, entity);
}
}
}
}

View file

@ -66,8 +66,8 @@ public class CrossDCLastSessionRefreshListener implements ClusterListener {
lastSessionRefreshes.entrySet().stream().forEach((entry) -> {
String sessionId = entry.getKey();
String realmId = entry.getValue().getRealmId();
int lastSessionRefresh = entry.getValue().getLastSessionRefresh();
String realmId = entry.getValue().realmId();
int lastSessionRefresh = entry.getValue().lastSessionRefresh();
// All nodes will receive the message. So ensure that each node updates just lastSessionRefreshes owned by him.
if (shouldUpdateLocalCache(sessionId)) {

View file

@ -17,30 +17,29 @@
package org.keycloak.models.sessions.infinispan.changes.sessions;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.marshalling.Marshalling;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.cluster.ClusterEvent;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(LastSessionRefreshEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.LAST_SESSION_REFRESH_EVENT)
public class LastSessionRefreshEvent implements ClusterEvent {
private final Map<String, SessionData> lastSessionRefreshes;
@ProtoFactory
public LastSessionRefreshEvent(Map<String, SessionData> lastSessionRefreshes) {
this.lastSessionRefreshes = lastSessionRefreshes;
}
@ProtoField(value = 1, mapImplementation = HashMap.class)
public Map<String, SessionData> getLastSessionRefreshes() {
return lastSessionRefreshes;
}
@ -55,29 +54,4 @@ public class LastSessionRefreshEvent implements ClusterEvent {
return 1;
}
public static class ExternalizerImpl implements Externalizer<LastSessionRefreshEvent> {
@Override
public void writeObject(ObjectOutput output, LastSessionRefreshEvent obj) throws IOException {
MarshallUtil.marshallMap(obj.lastSessionRefreshes, output);
}
@Override
public LastSessionRefreshEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
Map<String, SessionData> map = MarshallUtil.unmarshallMap(input, new MarshallUtil.MapBuilder<String, SessionData, Map<String, SessionData>>() {
@Override
public Map<String, SessionData> build(int size) {
return new HashMap<>(size);
}
});
LastSessionRefreshEvent event = new LastSessionRefreshEvent(map);
return event;
}
}
}

View file

@ -51,7 +51,7 @@ public class PersisterLastSessionRefreshStore extends AbstractLastSessionRefresh
protected void sendMessage(KeycloakSession kcSession, Map<String, SessionData> refreshesToSend) {
Map<String, Set<String>> sessionIdsByRealm =
refreshesToSend.entrySet().stream().collect(
Collectors.groupingBy(entry -> entry.getValue().getRealmId(),
Collectors.groupingBy(entry -> entry.getValue().realmId(),
Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));
// Update DB with a bit lower value than current time to ensure 'revokeRefreshToken' will work correctly taking server

View file

@ -17,59 +17,17 @@
package org.keycloak.models.sessions.infinispan.changes.sessions;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import org.infinispan.protostream.annotations.Proto;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(SessionData.ExternalizerImpl.class)
public class SessionData {
@ProtoTypeId(Marshalling.SESSION_DATA)
@Proto
public record SessionData(String realmId, int lastSessionRefresh) {
private final String realmId;
private final int lastSessionRefresh;
public SessionData(String realmId, int lastSessionRefresh) {
this.realmId = realmId;
this.lastSessionRefresh = lastSessionRefresh;
}
public String getRealmId() {
return realmId;
}
public int getLastSessionRefresh() {
return lastSessionRefresh;
}
@Override
public String toString() {
return String.format("realmId: %s, lastSessionRefresh: %d", realmId, lastSessionRefresh);
}
public static class ExternalizerImpl implements Externalizer<SessionData> {
@Override
public void writeObject(ObjectOutput output, SessionData obj) throws IOException {
MarshallUtil.marshallString(obj.realmId, output);
KeycloakMarshallUtil.marshall(obj.lastSessionRefresh, output);
}
@Override
public SessionData readObject(ObjectInput input) throws IOException, ClassNotFoundException {
String realmId = MarshallUtil.unmarshallString(input);
int lastSessionRefresh = KeycloakMarshallUtil.unmarshallInteger(input);
return new SessionData(realmId, lastSessionRefresh);
}
}
}

View file

@ -17,26 +17,24 @@
package org.keycloak.models.sessions.infinispan.entities;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.jboss.logging.Logger;
import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(AuthenticatedClientSessionEntity.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.AUTHENTICATED_CLIENT_SESSION_ENTITY)
public class AuthenticatedClientSessionEntity extends SessionEntity {
public static final Logger logger = Logger.getLogger(AuthenticatedClientSessionEntity.class);
@ -60,6 +58,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.id = id;
}
@ProtoField(2)
public String getAuthMethod() {
return authMethod;
}
@ -68,6 +67,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.authMethod = authMethod;
}
@ProtoField(3)
public String getRedirectUri() {
return redirectUri;
}
@ -76,6 +76,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.redirectUri = redirectUri;
}
@ProtoField(4)
public int getTimestamp() {
return timestamp;
}
@ -106,6 +107,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
getNotes().put(CLIENT_ID_NOTE, clientId);
}
@ProtoField(value = 5)
public String getAction() {
return action;
}
@ -114,6 +116,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.action = action;
}
@ProtoField(value = 6, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getNotes() {
return notes;
}
@ -122,6 +125,7 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
this.notes = notes;
}
@ProtoField(7)
public UUID getId() {
return id;
}
@ -133,14 +137,26 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof AuthenticatedClientSessionEntity)) return false;
if (this == o) {
return true;
}
if (!(o instanceof AuthenticatedClientSessionEntity that)) {
return false;
}
AuthenticatedClientSessionEntity that = (AuthenticatedClientSessionEntity) o;
return Objects.equals(id, that.id);
}
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
// factory method required because of final fields
@ProtoFactory
AuthenticatedClientSessionEntity(String realmId, String authMethod, String redirectUri, int timestamp, String action, Map<String, String> notes, UUID id) {
super(realmId);
this.authMethod = authMethod;
this.redirectUri = redirectUri;
this.timestamp = timestamp;
this.action = action;
this.notes = notes;
this.id = id;
}
@Override
@ -180,42 +196,4 @@ public class AuthenticatedClientSessionEntity extends SessionEntity {
public void setUserSessionId(String userSessionId) {
this.userSessionId = userSessionId;
}
public static class ExternalizerImpl implements Externalizer<AuthenticatedClientSessionEntity> {
@Override
public void writeObject(ObjectOutput output, AuthenticatedClientSessionEntity session) throws IOException {
MarshallUtil.marshallUUID(session.id, output, false);
MarshallUtil.marshallString(session.getRealmId(), output);
MarshallUtil.marshallString(session.getAuthMethod(), output);
MarshallUtil.marshallString(session.getRedirectUri(), output);
KeycloakMarshallUtil.marshall(session.getTimestamp(), output);
MarshallUtil.marshallString(session.getAction(), output);
Map<String, String> notes = session.getNotes();
KeycloakMarshallUtil.writeMap(notes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
}
@Override
public AuthenticatedClientSessionEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
AuthenticatedClientSessionEntity sessionEntity = new AuthenticatedClientSessionEntity(MarshallUtil.unmarshallUUID(input, false));
sessionEntity.setRealmId(MarshallUtil.unmarshallString(input));
sessionEntity.setAuthMethod(MarshallUtil.unmarshallString(input));
sessionEntity.setRedirectUri(MarshallUtil.unmarshallString(input));
sessionEntity.setTimestamp(KeycloakMarshallUtil.unmarshallInteger(input));
sessionEntity.setAction(MarshallUtil.unmarshallString(input));
Map<String, String> notes = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT,
new KeycloakMarshallUtil.ConcurrentHashMapBuilder<>());
sessionEntity.setNotes(notes);
return sessionEntity;
}
}
}

View file

@ -16,34 +16,35 @@
*/
package org.keycloak.models.sessions.infinispan.entities;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.BiConsumer;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
/**
*
* @author hmlnarik
*/
@SerializeWith(AuthenticatedClientSessionStore.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.AUTHENTICATED_CLIENT_SESSION_STORE)
public class AuthenticatedClientSessionStore {
/**
* Maps client UUID to client session ID.
*/
private final ConcurrentHashMap<String, UUID> authenticatedClientSessionIds;
private final ConcurrentMap<String, UUID> authenticatedClientSessionIds;
public AuthenticatedClientSessionStore() {
authenticatedClientSessionIds = new ConcurrentHashMap<>();
}
private AuthenticatedClientSessionStore(ConcurrentHashMap<String, UUID> authenticatedClientSessionIds) {
@ProtoFactory
AuthenticatedClientSessionStore(ConcurrentMap<String, UUID> authenticatedClientSessionIds) {
this.authenticatedClientSessionIds = authenticatedClientSessionIds;
}
@ -79,37 +80,14 @@ public class AuthenticatedClientSessionStore {
return authenticatedClientSessionIds.size();
}
@ProtoField(value = 1, mapImplementation = ConcurrentHashMap.class)
ConcurrentMap<String, UUID> getAuthenticatedClientSessionIds() {
return authenticatedClientSessionIds;
}
@Override
public String toString() {
return this.authenticatedClientSessionIds.toString();
}
public static class ExternalizerImpl implements Externalizer<AuthenticatedClientSessionStore> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, AuthenticatedClientSessionStore obj) throws IOException {
output.writeByte(VERSION_1);
KeycloakMarshallUtil.writeMap(obj.authenticatedClientSessionIds, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.UUID_EXT, output);
}
@Override
public AuthenticatedClientSessionStore readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public AuthenticatedClientSessionStore readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
AuthenticatedClientSessionStore res = new AuthenticatedClientSessionStore(
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.UUID_EXT, ConcurrentHashMap::new)
);
return res;
}
}
}

View file

@ -17,17 +17,12 @@
package org.keycloak.models.sessions.infinispan.entities;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.sessions.CommonClientSessionModel.ExecutionStatus;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@ -35,8 +30,8 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(AuthenticationSessionEntity.ExternalizerImpl.class)
public class AuthenticationSessionEntity implements Serializable {
@ProtoTypeId(Marshalling.AUTHENTICATION_SESSION_ENTITY)
public class AuthenticationSessionEntity {
private String clientUUID;
@ -60,12 +55,12 @@ public class AuthenticationSessionEntity implements Serializable {
}
public AuthenticationSessionEntity(
String clientUUID,
String authUserId,
int timestamp,
String redirectUri, String action, Set<String> clientScopes,
Map<String, AuthenticationSessionModel.ExecutionStatus> executionStatus, String protocol,
Map<String, String> clientNotes, Map<String, String> authNotes, Set<String> requiredActions, Map<String, String> userSessionNotes) {
String clientUUID,
String authUserId,
int timestamp,
String redirectUri, String action, Set<String> clientScopes,
Map<String, AuthenticationSessionModel.ExecutionStatus> executionStatus, String protocol,
Map<String, String> clientNotes, Map<String, String> authNotes, Set<String> requiredActions, Map<String, String> userSessionNotes) {
this(clientUUID, authUserId, redirectUri, action, clientScopes, executionStatus, protocol, clientNotes, authNotes, requiredActions, userSessionNotes);
this.timestamp = timestamp;
}
@ -93,6 +88,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.userSessionNotes = userSessionNotes;
}
@ProtoField(1)
public String getClientUUID() {
return clientUUID;
}
@ -101,6 +97,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.clientUUID = clientUUID;
}
@ProtoField(2)
public String getAuthUserId() {
return authUserId;
}
@ -109,6 +106,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.authUserId = authUserId;
}
@ProtoField(3)
public int getTimestamp() {
return timestamp;
}
@ -117,6 +115,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.timestamp = timestamp;
}
@ProtoField(4)
public String getRedirectUri() {
return redirectUri;
}
@ -125,6 +124,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.redirectUri = redirectUri;
}
@ProtoField(5)
public String getAction() {
return action;
}
@ -133,6 +133,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.action = action;
}
@ProtoField(value = 6, collectionImplementation = HashSet.class)
public Set<String> getClientScopes() {
return clientScopes;
}
@ -141,6 +142,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.clientScopes = clientScopes;
}
@ProtoField(value = 7, mapImplementation = ConcurrentHashMap.class)
public Map<String, AuthenticationSessionModel.ExecutionStatus> getExecutionStatus() {
return executionStatus;
}
@ -149,6 +151,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.executionStatus = executionStatus;
}
@ProtoField(8)
public String getProtocol() {
return protocol;
}
@ -157,6 +160,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.protocol = protocol;
}
@ProtoField(value = 9, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getClientNotes() {
return clientNotes;
}
@ -165,6 +169,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.clientNotes = clientNotes;
}
@ProtoField(value = 10, collectionImplementation = HashSet.class)
public Set<String> getRequiredActions() {
return requiredActions;
}
@ -173,6 +178,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.requiredActions = requiredActions;
}
@ProtoField(value = 11, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getUserSessionNotes() {
return userSessionNotes;
}
@ -181,6 +187,7 @@ public class AuthenticationSessionEntity implements Serializable {
this.userSessionNotes = userSessionNotes;
}
@ProtoField(value = 12, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getAuthNotes() {
return authNotes;
}
@ -188,109 +195,4 @@ public class AuthenticationSessionEntity implements Serializable {
public void setAuthNotes(Map<String, String> authNotes) {
this.authNotes = authNotes;
}
public static class ExternalizerImpl implements Externalizer<AuthenticationSessionEntity> {
private static final int VERSION_1 = 1;
private static final int VERSION_2 = 2;
public static final ExternalizerImpl INSTANCE = new ExternalizerImpl();
private static AuthenticationSessionModel.ExecutionStatus fromOrdinal(int ordinal) {
ExecutionStatus[] values = AuthenticationSessionModel.ExecutionStatus.values();
return (ordinal < 0 || ordinal >= values.length)
? null
: values[ordinal];
}
public static final Externalizer<AuthenticationSessionModel.ExecutionStatus> EXECUTION_STATUS_EXT = new Externalizer<AuthenticationSessionModel.ExecutionStatus>() {
@Override
public void writeObject(ObjectOutput output, AuthenticationSessionModel.ExecutionStatus e) throws IOException {
MarshallUtil.marshallEnum(e, output);
}
@Override
public AuthenticationSessionModel.ExecutionStatus readObject(ObjectInput input) throws IOException, ClassNotFoundException {
return MarshallUtil.unmarshallEnum(input, ExternalizerImpl::fromOrdinal);
}
};
@Override
public void writeObject(ObjectOutput output, AuthenticationSessionEntity value) throws IOException {
output.writeByte(VERSION_2);
MarshallUtil.marshallString(value.clientUUID, output);
MarshallUtil.marshallString(value.authUserId, output);
output.writeInt(value.timestamp);
MarshallUtil.marshallString(value.redirectUri, output);
MarshallUtil.marshallString(value.action, output);
KeycloakMarshallUtil.writeCollection(value.clientScopes, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeMap(value.executionStatus, KeycloakMarshallUtil.STRING_EXT, EXECUTION_STATUS_EXT, output);
MarshallUtil.marshallString(value.protocol, output);
KeycloakMarshallUtil.writeMap(value.clientNotes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeMap(value.authNotes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeCollection(value.requiredActions, KeycloakMarshallUtil.STRING_EXT, output);
KeycloakMarshallUtil.writeMap(value.userSessionNotes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
}
@Override
public AuthenticationSessionEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
case VERSION_2:
return readObjectVersion2(input);
default:
throw new IOException("Unknown version");
}
}
public AuthenticationSessionEntity readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
return new AuthenticationSessionEntity(
MarshallUtil.unmarshallString(input), // clientUUID
MarshallUtil.unmarshallString(input), // authUserId
MarshallUtil.unmarshallString(input), // redirectUri
MarshallUtil.unmarshallString(input), // action
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet), // clientScopes
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, EXECUTION_STATUS_EXT, size -> new ConcurrentHashMap<>(size)), // executionStatus
MarshallUtil.unmarshallString(input), // protocol
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)), // clientNotes
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)), // authNotes
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet), // requiredActions
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)) // userSessionNotes
);
}
public AuthenticationSessionEntity readObjectVersion2(ObjectInput input) throws IOException, ClassNotFoundException {
return new AuthenticationSessionEntity(
MarshallUtil.unmarshallString(input), // clientUUID
MarshallUtil.unmarshallString(input), // authUserId
input.readInt(), // timestamp
MarshallUtil.unmarshallString(input), // redirectUri
MarshallUtil.unmarshallString(input), // action
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet), // clientScopes
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, EXECUTION_STATUS_EXT, size -> new ConcurrentHashMap<>(size)), // executionStatus
MarshallUtil.unmarshallString(input), // protocol
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)), // clientNotes
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)), // authNotes
KeycloakMarshallUtil.readCollection(input, KeycloakMarshallUtil.STRING_EXT, ConcurrentHashMap::newKeySet), // requiredActions
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, size -> new ConcurrentHashMap<>(size)) // userSessionNotes
);
}
}
}

View file

@ -17,17 +17,16 @@
package org.keycloak.models.sessions.infinispan.entities;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import java.util.Objects;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@SerializeWith(LoginFailureEntity.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.LOGIN_FAILURE_ENTITY)
public class LoginFailureEntity extends SessionEntity {
private String userId;
@ -51,6 +50,7 @@ public class LoginFailureEntity extends SessionEntity {
this.lastIPFailure = lastIPFailure;
}
@ProtoField(2)
public String getUserId() {
return userId;
}
@ -59,6 +59,7 @@ public class LoginFailureEntity extends SessionEntity {
this.userId = userId;
}
@ProtoField(3)
public int getFailedLoginNotBefore() {
return failedLoginNotBefore;
}
@ -69,6 +70,7 @@ public class LoginFailureEntity extends SessionEntity {
}
}
@ProtoField(4)
public int getNumFailures() {
return numFailures;
}
@ -77,6 +79,7 @@ public class LoginFailureEntity extends SessionEntity {
this.numFailures = numFailures;
}
@ProtoField(5)
public int getNumTemporaryLockouts() {
return numTemporaryLockouts;
}
@ -85,6 +88,7 @@ public class LoginFailureEntity extends SessionEntity {
this.numTemporaryLockouts = numTemporaryLockouts;
}
@ProtoField(6)
public long getLastFailure() {
return lastFailure;
}
@ -95,6 +99,7 @@ public class LoginFailureEntity extends SessionEntity {
}
}
@ProtoField(7)
public String getLastIPFailure() {
return lastIPFailure;
}
@ -113,16 +118,17 @@ public class LoginFailureEntity extends SessionEntity {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof LoginFailureEntity)) return false;
if (this == o) {
return true;
}
if (!(o instanceof LoginFailureEntity that)) {
return false;
}
LoginFailureEntity that = (LoginFailureEntity) o;
if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
if (getRealmId() != null ? !getRealmId().equals(that.getRealmId()) : that.getRealmId() != null) return false;
return true;
if (!Objects.equals(userId, that.userId)) {
return false;
}
return getRealmId() != null ? getRealmId().equals(that.getRealmId()) : that.getRealmId() == null;
}
@Override
@ -137,43 +143,4 @@ public class LoginFailureEntity extends SessionEntity {
return String.format("LoginFailureEntity [ userId=%s, realm=%s, numFailures=%d ]", userId, getRealmId(), numFailures);
}
public static class ExternalizerImpl implements Externalizer<LoginFailureEntity> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, LoginFailureEntity value) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(value.getRealmId(), output);
MarshallUtil.marshallString(value.userId, output);
output.writeInt(value.failedLoginNotBefore);
output.writeInt(value.numFailures);
output.writeInt(value.numTemporaryLockouts);
output.writeLong(value.lastFailure);
MarshallUtil.marshallString(value.lastIPFailure, output);
}
@Override
public LoginFailureEntity readObject(ObjectInput input) throws IOException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public LoginFailureEntity readObjectVersion1(ObjectInput input) throws IOException {
return new LoginFailureEntity(
MarshallUtil.unmarshallString(input),
MarshallUtil.unmarshallString(input),
input.readInt(),
input.readInt(),
input.readInt(),
input.readLong(),
MarshallUtil.unmarshallString(input)
);
}
}
}

View file

@ -17,77 +17,14 @@
package org.keycloak.models.sessions.infinispan.entities;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.Proto;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@SerializeWith(LoginFailureKey.ExternalizerImpl.class)
public class LoginFailureKey {
private final String realmId;
private final String userId;
public LoginFailureKey(String realmId, String userId) {
this.realmId = realmId;
this.userId = userId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LoginFailureKey key = (LoginFailureKey) o;
if (realmId != null ? !realmId.equals(key.realmId) : key.realmId != null) return false;
if (userId != null ? !userId.equals(key.userId) : key.userId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = realmId != null ? realmId.hashCode() : 0;
result = 31 * result + (userId != null ? userId.hashCode() : 0);
return result;
}
@Override
public String toString() {
return String.format("LoginFailureKey [ realmId=%s. userId=%s ]", realmId, userId);
}
public static class ExternalizerImpl implements Externalizer<LoginFailureKey> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, LoginFailureKey value) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(value.realmId, output);
MarshallUtil.marshallString(value.userId, output);
}
@Override
public LoginFailureKey readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public LoginFailureKey readObjectVersion1(ObjectInput input) throws IOException {
return new LoginFailureKey(MarshallUtil.unmarshallString(input), MarshallUtil.unmarshallString(input));
}
}
@ProtoTypeId(Marshalling.LOGIN_FAILURE_KEY)
@Proto
public record LoginFailureKey(String realmId, String userId) {
}

View file

@ -17,20 +17,19 @@
package org.keycloak.models.sessions.infinispan.entities;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(RootAuthenticationSessionEntity.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.ROOT_AUTHENTICATION_SESSION_ENTITY)
public class RootAuthenticationSessionEntity extends SessionEntity {
private final String id;
@ -48,10 +47,17 @@ public class RootAuthenticationSessionEntity extends SessionEntity {
this.authenticationSessions = authenticationSessions;
}
@ProtoFactory
static RootAuthenticationSessionEntity protoFactory(String realmId, String id, int timestamp, Map<String, AuthenticationSessionEntity> authenticationSessions) {
return new RootAuthenticationSessionEntity(realmId, id, timestamp, authenticationSessions);
}
@ProtoField(2)
public String getId() {
return id;
}
@ProtoField(3)
public int getTimestamp() {
return timestamp;
}
@ -60,6 +66,7 @@ public class RootAuthenticationSessionEntity extends SessionEntity {
this.timestamp = timestamp;
}
@ProtoField(value = 4, mapImplementation = ConcurrentHashMap.class)
public Map<String, AuthenticationSessionEntity> getAuthenticationSessions() {
return authenticationSessions;
}
@ -70,14 +77,12 @@ public class RootAuthenticationSessionEntity extends SessionEntity {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RootAuthenticationSessionEntity)) return false;
if (this == o) {
return true;
}
return o instanceof RootAuthenticationSessionEntity that &&
Objects.equals(id, that.id);
RootAuthenticationSessionEntity that = (RootAuthenticationSessionEntity) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
}
@Override
@ -90,41 +95,4 @@ public class RootAuthenticationSessionEntity extends SessionEntity {
return String.format("RootAuthenticationSessionEntity [ id=%s, realm=%s ]", getId(), getRealmId());
}
public static class ExternalizerImpl implements Externalizer<RootAuthenticationSessionEntity> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RootAuthenticationSessionEntity value) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(value.getRealmId(), output);
MarshallUtil.marshallString(value.id, output);
output.writeInt(value.timestamp);
KeycloakMarshallUtil.writeMap(value.authenticationSessions, KeycloakMarshallUtil.STRING_EXT, AuthenticationSessionEntity.ExternalizerImpl.INSTANCE, output);
}
@Override
public RootAuthenticationSessionEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RootAuthenticationSessionEntity readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
return new RootAuthenticationSessionEntity(
MarshallUtil.unmarshallString(input), // realmId
MarshallUtil.unmarshallString(input), // id
input.readInt(), // timestamp
KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, AuthenticationSessionEntity.ExternalizerImpl.INSTANCE, size -> new ConcurrentHashMap<>(size)) // authenticationSessions
);
}
}
}

View file

@ -17,8 +17,7 @@
package org.keycloak.models.sessions.infinispan.entities;
import java.io.Serializable;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.common.Profile;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
@ -30,7 +29,7 @@ import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
*
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public abstract class SessionEntity implements Serializable {
public abstract class SessionEntity {
private String realmId;
private boolean isOffline;
@ -39,6 +38,7 @@ public abstract class SessionEntity implements Serializable {
* Returns realmId ID.
* @return
*/
@ProtoField(1)
public String getRealmId() {
return realmId;
}
@ -60,7 +60,7 @@ public abstract class SessionEntity implements Serializable {
} else {
return new SessionEntityWrapper<>(localEntityWrapper.getLocalMetadata(), this);
}
};
}
@Override
public abstract boolean equals(Object obj);

View file

@ -16,28 +16,40 @@
*/
package org.keycloak.models.sessions.infinispan.entities;
import org.keycloak.models.SingleUseObjectValueModel;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.io.*;
import java.util.*;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.SingleUseObjectValueModel;
/**
* @author hmlnarik
*/
@SerializeWith(SingleUseObjectValueEntity.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.SINGLE_USE_OBJECT_VALUE_ENTITY)
public class SingleUseObjectValueEntity implements SingleUseObjectValueModel {
private final Map<String, String> notes;
@ProtoFactory
public SingleUseObjectValueEntity(Map<String, String> notes) {
this.notes = notes == null ? Collections.EMPTY_MAP : new HashMap<>(notes);
if (notes == null || notes.isEmpty()) {
this.notes = Map.of();
return;
}
var copy = new HashMap<>(notes);
// protostream does not support null values for primitive types as string
copy.values().removeIf(Objects::isNull);
this.notes = Map.copyOf(copy);
}
@ProtoField(value = 1, mapImplementation = HashMap.class)
@Override
public Map<String, String> getNotes() {
return Collections.unmodifiableMap(notes);
return notes;
}
@Override
@ -50,32 +62,4 @@ public class SingleUseObjectValueEntity implements SingleUseObjectValueModel {
return String.format("SingleUseObjectValueEntity [ notes=%s ]", notes.toString());
}
public static class ExternalizerImpl implements Externalizer<SingleUseObjectValueEntity> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, SingleUseObjectValueEntity t) throws IOException {
output.writeByte(VERSION_1);
output.writeBoolean(t.notes.isEmpty());
if (! t.notes.isEmpty()) {
output.writeObject(t.notes);
}
}
@Override
public SingleUseObjectValueEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
byte version = input.readByte();
if (version != VERSION_1) {
throw new IOException("Invalid version: " + version);
}
boolean notesEmpty = input.readBoolean();
Map<String, String> notes = notesEmpty ? Collections.EMPTY_MAP : (Map<String, String>) input.readObject();
return new SingleUseObjectValueEntity(notes);
}
}
}

View file

@ -17,29 +17,23 @@
package org.keycloak.models.sessions.infinispan.entities;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith;
import org.jboss.logging.Logger;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UserSessionModel.State;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.jboss.logging.Logger;
import org.keycloak.marshalling.Marshalling;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@SerializeWith(UserSessionEntity.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.USER_SESSION_ENTITY)
public class UserSessionEntity extends SessionEntity {
public static final Logger logger = Logger.getLogger(UserSessionEntity.class);
@ -72,6 +66,26 @@ public class UserSessionEntity extends SessionEntity {
this.id = id;
}
@ProtoFactory
static UserSessionEntity protoFactory(String realmId, String id, String user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, int started, int lastSessionRefresh, Map<String, String> notes, AuthenticatedClientSessionStore authenticatedClientSessions, UserSessionModel.State state, String brokerSessionId, String brokerUserId) {
var entity = new UserSessionEntity(id);
entity.setRealmId(realmId);
entity.setUser(user);
entity.setLoginUsername(loginUsername);
entity.setIpAddress(ipAddress);
entity.setAuthMethod(authMethod);
entity.setRememberMe(rememberMe);
entity.setStarted(started);
entity.setLastSessionRefresh(lastSessionRefresh);
entity.setBrokerSessionId(brokerSessionId);
entity.setBrokerUserId(brokerUserId);
entity.setState(state);
entity.setNotes(notes);
entity.setAuthenticatedClientSessions(authenticatedClientSessions);
return entity;
}
@ProtoField(2)
public String getId() {
return id;
}
@ -80,6 +94,7 @@ public class UserSessionEntity extends SessionEntity {
private AuthenticatedClientSessionStore authenticatedClientSessions = new AuthenticatedClientSessionStore();
@ProtoField(3)
public String getUser() {
return user;
}
@ -88,6 +103,7 @@ public class UserSessionEntity extends SessionEntity {
this.user = user;
}
@ProtoField(4)
public String getLoginUsername() {
return loginUsername;
}
@ -96,6 +112,7 @@ public class UserSessionEntity extends SessionEntity {
this.loginUsername = loginUsername;
}
@ProtoField(5)
public String getIpAddress() {
return ipAddress;
}
@ -104,6 +121,7 @@ public class UserSessionEntity extends SessionEntity {
this.ipAddress = ipAddress;
}
@ProtoField(6)
public String getAuthMethod() {
return authMethod;
}
@ -112,6 +130,7 @@ public class UserSessionEntity extends SessionEntity {
this.authMethod = authMethod;
}
@ProtoField(7)
public boolean isRememberMe() {
return rememberMe;
}
@ -120,6 +139,7 @@ public class UserSessionEntity extends SessionEntity {
this.rememberMe = rememberMe;
}
@ProtoField(8)
public int getStarted() {
return started;
}
@ -128,6 +148,7 @@ public class UserSessionEntity extends SessionEntity {
this.started = started;
}
@ProtoField(9)
public int getLastSessionRefresh() {
return lastSessionRefresh;
}
@ -136,6 +157,7 @@ public class UserSessionEntity extends SessionEntity {
this.lastSessionRefresh = lastSessionRefresh;
}
@ProtoField(value = 10, mapImplementation = ConcurrentHashMap.class)
public Map<String, String> getNotes() {
return notes;
}
@ -144,6 +166,7 @@ public class UserSessionEntity extends SessionEntity {
this.notes = notes;
}
@ProtoField(11)
public AuthenticatedClientSessionStore getAuthenticatedClientSessions() {
return authenticatedClientSessions;
}
@ -152,6 +175,7 @@ public class UserSessionEntity extends SessionEntity {
this.authenticatedClientSessions = authenticatedClientSessions;
}
@ProtoField(value = 12)
public UserSessionModel.State getState() {
return state;
}
@ -160,6 +184,7 @@ public class UserSessionEntity extends SessionEntity {
this.state = state;
}
@ProtoField(13)
public String getBrokerSessionId() {
return brokerSessionId;
}
@ -168,6 +193,7 @@ public class UserSessionEntity extends SessionEntity {
this.brokerSessionId = brokerSessionId;
}
@ProtoField(14)
public String getBrokerUserId() {
return brokerUserId;
}
@ -178,14 +204,12 @@ public class UserSessionEntity extends SessionEntity {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof UserSessionEntity)) return false;
if (this == o) {
return true;
}
return o instanceof UserSessionEntity that &&
Objects.equals(id, that.id);
UserSessionEntity that = (UserSessionEntity) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
}
@Override
@ -224,88 +248,4 @@ public class UserSessionEntity extends SessionEntity {
return entityWrapper;
}
public static class ExternalizerImpl implements Externalizer<UserSessionEntity> {
private static final int VERSION_1 = 1;
private static final EnumMap<UserSessionModel.State, Integer> STATE_TO_ID = new EnumMap<>(UserSessionModel.State.class);
private static final Map<Integer, UserSessionModel.State> ID_TO_STATE = new HashMap<>();
static {
STATE_TO_ID.put(State.LOGGED_IN, 1);
STATE_TO_ID.put(State.LOGGED_OUT, 2);
STATE_TO_ID.put(State.LOGGING_OUT, 3);
for (Entry<State, Integer> entry : STATE_TO_ID.entrySet()) {
ID_TO_STATE.put(entry.getValue(), entry.getKey());
}
}
@Override
public void writeObject(ObjectOutput output, UserSessionEntity session) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(session.getAuthMethod(), output);
MarshallUtil.marshallString(session.getBrokerSessionId(), output);
MarshallUtil.marshallString(session.getBrokerUserId(), output);
MarshallUtil.marshallString(session.getId(), output);
MarshallUtil.marshallString(session.getIpAddress(), output);
MarshallUtil.marshallString(session.getLoginUsername(), output);
MarshallUtil.marshallString(session.getRealmId(), output);
MarshallUtil.marshallString(session.getUser(), output);
KeycloakMarshallUtil.marshall(session.getLastSessionRefresh(), output);
KeycloakMarshallUtil.marshall(session.getStarted(), output);
output.writeBoolean(session.isRememberMe());
int state = session.getState() == null ? 0 : STATE_TO_ID.get(session.getState());
output.writeInt(state);
Map<String, String> notes = session.getNotes();
KeycloakMarshallUtil.writeMap(notes, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, output);
output.writeObject(session.getAuthenticatedClientSessions());
}
@Override
public UserSessionEntity readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public UserSessionEntity readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
String authMethod = MarshallUtil.unmarshallString(input);
String brokerSessionId = MarshallUtil.unmarshallString(input);
String brokerUserId = MarshallUtil.unmarshallString(input);
UserSessionEntity sessionEntity = new UserSessionEntity(MarshallUtil.unmarshallString(input));
sessionEntity.setAuthMethod(authMethod);
sessionEntity.setBrokerSessionId(brokerSessionId);
sessionEntity.setBrokerUserId(brokerUserId);
sessionEntity.setIpAddress(MarshallUtil.unmarshallString(input));
sessionEntity.setLoginUsername(MarshallUtil.unmarshallString(input));
sessionEntity.setRealmId(MarshallUtil.unmarshallString(input));
sessionEntity.setUser(MarshallUtil.unmarshallString(input));
sessionEntity.setLastSessionRefresh(KeycloakMarshallUtil.unmarshallInteger(input));
sessionEntity.setStarted(KeycloakMarshallUtil.unmarshallInteger(input));
sessionEntity.setRememberMe(input.readBoolean());
sessionEntity.setState(ID_TO_STATE.get(input.readInt()));
Map<String, String> notes = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT,
new KeycloakMarshallUtil.ConcurrentHashMapBuilder<>());
sessionEntity.setNotes(notes);
AuthenticatedClientSessionStore authSessions = (AuthenticatedClientSessionStore) input.readObject();
sessionEntity.setAuthenticatedClientSessions(authSessions);
return sessionEntity;
}
}
}

View file

@ -17,45 +17,13 @@
package org.keycloak.models.sessions.infinispan.events;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(RealmRemovedSessionEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.REALM_REMOVED_SESSION_EVENT)
public class RealmRemovedSessionEvent extends SessionClusterEvent {
public static class ExternalizerImpl implements Externalizer<RealmRemovedSessionEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RealmRemovedSessionEvent obj) throws IOException {
output.writeByte(VERSION_1);
obj.marshallTo(output);
}
@Override
public RealmRemovedSessionEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RealmRemovedSessionEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RealmRemovedSessionEvent res = new RealmRemovedSessionEvent();
res.unmarshallFrom(input);
return res;
}
}
}

View file

@ -17,45 +17,13 @@
package org.keycloak.models.sessions.infinispan.events;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(RemoveAllUserLoginFailuresEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.REMOVE_ALL_USER_LOGIN_FAILURES_EVENT)
public class RemoveAllUserLoginFailuresEvent extends SessionClusterEvent {
public static class ExternalizerImpl implements Externalizer<RemoveAllUserLoginFailuresEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RemoveAllUserLoginFailuresEvent obj) throws IOException {
output.writeByte(VERSION_1);
obj.marshallTo(output);
}
@Override
public RemoveAllUserLoginFailuresEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RemoveAllUserLoginFailuresEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RemoveAllUserLoginFailuresEvent res = new RemoveAllUserLoginFailuresEvent();
res.unmarshallFrom(input);
return res;
}
}
}

View file

@ -17,45 +17,13 @@
package org.keycloak.models.sessions.infinispan.events;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.keycloak.marshalling.Marshalling;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@SerializeWith(RemoveUserSessionsEvent.ExternalizerImpl.class)
@ProtoTypeId(Marshalling.REMOVE_ALL_USER_SESSIONS_EVENT)
public class RemoveUserSessionsEvent extends SessionClusterEvent {
public static class ExternalizerImpl implements Externalizer<RemoveUserSessionsEvent> {
private static final int VERSION_1 = 1;
@Override
public void writeObject(ObjectOutput output, RemoveUserSessionsEvent obj) throws IOException {
output.writeByte(VERSION_1);
obj.marshallTo(output);
}
@Override
public RemoveUserSessionsEvent readObject(ObjectInput input) throws IOException, ClassNotFoundException {
switch (input.readByte()) {
case VERSION_1:
return readObjectVersion1(input);
default:
throw new IOException("Unknown version");
}
}
public RemoveUserSessionsEvent readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException {
RemoveUserSessionsEvent res = new RemoveUserSessionsEvent();
res.unmarshallFrom(input);
return res;
}
}
}

View file

@ -17,16 +17,13 @@
package org.keycloak.models.sessions.infinispan.events;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.connections.infinispan.TopologyInfo;
import org.keycloak.models.KeycloakSession;
import org.keycloak.connections.infinispan.InfinispanUtil;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.protostream.annotations.ProtoField;
import org.keycloak.cluster.ClusterEvent;
import org.keycloak.connections.infinispan.InfinispanUtil;
import org.keycloak.connections.infinispan.TopologyInfo;
import org.keycloak.models.KeycloakSession;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -42,7 +39,7 @@ public abstract class SessionClusterEvent implements ClusterEvent {
public static <T extends SessionClusterEvent> T createEvent(Class<T> eventClass, String eventKey, KeycloakSession session, String realmId, boolean resendingEvent) {
try {
T event = eventClass.newInstance();
T event = eventClass.getDeclaredConstructor().newInstance();
event.setData(session, eventKey, realmId, resendingEvent);
return event;
} catch (Exception e) {
@ -61,26 +58,51 @@ public abstract class SessionClusterEvent implements ClusterEvent {
}
@ProtoField(1)
public String getRealmId() {
return realmId;
}
void setRealmId(String realmId) {
this.realmId = realmId;
}
@ProtoField(2)
public String getEventKey() {
return eventKey;
}
void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
@ProtoField(3)
public boolean isResendingEvent() {
return resendingEvent;
}
void setResendingEvent(boolean resendingEvent) {
this.resendingEvent = resendingEvent;
}
@ProtoField(4)
public String getSiteId() {
return siteId;
}
void setSiteId(String siteId) {
this.siteId = siteId;
}
@ProtoField(5)
public String getNodeId() {
return nodeId;
}
void setNodeId(String nodeId) {
this.nodeId = nodeId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -99,40 +121,4 @@ public abstract class SessionClusterEvent implements ClusterEvent {
String simpleClassName = getClass().getSimpleName();
return String.format("%s [ realmId=%s ]", simpleClassName, realmId);
}
// Infinispan marshalling support for child classes
private static final int VERSION_1 = 1;
protected void marshallTo(ObjectOutput output) throws IOException {
output.writeByte(VERSION_1);
MarshallUtil.marshallString(realmId, output);
MarshallUtil.marshallString(eventKey, output);
output.writeBoolean(resendingEvent);
MarshallUtil.marshallString(siteId, output);
MarshallUtil.marshallString(nodeId, output);
}
/**
* Sets the properties of this object from the input stream.
* @param input
* @throws IOException
*/
protected void unmarshallFrom(ObjectInput input) throws IOException {
switch (input.readByte()) {
case VERSION_1:
unmarshallFromVersion1(input);
break;
default:
throw new IOException("Unknown version");
}
}
private void unmarshallFromVersion1(ObjectInput input) throws IOException {
this.realmId = MarshallUtil.unmarshallString(input);
this.eventKey = MarshallUtil.unmarshallString(input);
this.resendingEvent = input.readBoolean();
this.siteId = MarshallUtil.unmarshallString(input);
this.nodeId = MarshallUtil.unmarshallString(input);
}
}

View file

@ -23,8 +23,6 @@ import org.infinispan.lifecycle.ComponentStatus;
import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSessionFactory;
import java.io.Serializable;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@ -35,11 +33,11 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
private static final Logger log = Logger.getLogger(BaseCacheInitializer.class);
protected final KeycloakSessionFactory sessionFactory;
protected final Cache<String, Serializable> workCache;
protected final Cache<String, InitializerState> workCache;
protected final SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader;
protected final String stateKey;
public BaseCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, Serializable> workCache, SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader, String stateKeySuffix) {
public BaseCacheInitializer(KeycloakSessionFactory sessionFactory, Cache<String, InitializerState> workCache, SessionLoader<SessionLoader.LoaderContext, SessionLoader.WorkerContext, SessionLoader.WorkerResult> sessionLoader, String stateKeySuffix) {
this.sessionFactory = sessionFactory;
this.workCache = workCache;
this.sessionLoader = sessionLoader;
@ -67,7 +65,7 @@ public abstract class BaseCacheInitializer extends CacheInitializer {
protected InitializerState getStateFromCache() {
// We ignore cacheStore for now, so that in Cross-DC scenario (with RemoteStore enabled) is the remoteStore ignored.
return (InitializerState) workCache.getAdvancedCache()
return workCache.getAdvancedCache()
.withFlags(Flag.SKIP_CACHE_STORE, Flag.SKIP_CACHE_LOAD)
.get(stateKey);
}

Some files were not shown because too many files have changed in this diff Show more