diff --git a/docs/documentation/release_notes/topics/26_0_0.adoc b/docs/documentation/release_notes/topics/26_0_0.adoc index bc17cc2984..d155c749ce 100644 --- a/docs/documentation/release_notes/topics/26_0_0.adoc +++ b/docs/documentation/release_notes/topics/26_0_0.adoc @@ -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. diff --git a/docs/documentation/upgrading/topics/changes/changes-26_0_0.adoc b/docs/documentation/upgrading/topics/changes/changes-26_0_0.adoc new file mode 100644 index 0000000000..cba1d84cc7 --- /dev/null +++ b/docs/documentation/upgrading/topics/changes/changes-26_0_0.adoc @@ -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. diff --git a/docs/documentation/upgrading/topics/changes/changes.adoc b/docs/documentation/upgrading/topics/changes/changes.adoc index e4ac65ff95..943b4a7a2a 100644 --- a/docs/documentation/upgrading/topics/changes/changes.adoc +++ b/docs/documentation/upgrading/topics/changes/changes.adoc @@ -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] diff --git a/model/infinispan/pom.xml b/model/infinispan/pom.xml index 1deb2ac0e5..e69e12541a 100755 --- a/model/infinispan/pom.xml +++ b/model/infinispan/pom.xml @@ -67,7 +67,23 @@ org.infinispan - infinispan-jboss-marshalling + infinispan-component-annotations + provided + + + + org.infinispan.protostream + protostream + + + org.infinispan.protostream + protostream-types + + + org.infinispan.protostream + protostream-processor + + provided diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/CrossDCAwareCacheFactory.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/CrossDCAwareCacheFactory.java index 65ca09d98e..546b9de395 100644 --- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/CrossDCAwareCacheFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/CrossDCAwareCacheFactory.java @@ -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 getCache(); + abstract BasicCache getCache(); - static CrossDCAwareCacheFactory getFactory(Cache workCache, Set remoteStores) { + static CrossDCAwareCacheFactory getFactory(Cache workCache, Set 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 workCache; + private final Cache workCache; - InfinispanCacheWrapperFactory(Cache workCache) { + InfinispanCacheWrapperFactory(Cache workCache) { this.workCache = workCache; } @Override - BasicCache getCache() { + BasicCache 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 remoteCache; + private final RemoteCache remoteCache; - RemoteCacheWrapperFactory(RemoteCache remoteCache) { + RemoteCacheWrapperFactory(RemoteCache remoteCache) { this.remoteCache = remoteCache; } @Override - BasicCache getCache() { + BasicCache getCache() { // Flags are per-invocation! return remoteCache.withFlags(Flag.FORCE_RETURN_VALUE); } diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProvider.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProvider.java index 6c257454db..a99d466741 100644 --- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProvider.java @@ -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; } diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java index 39433acc5b..65c9630944 100644 --- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanClusterProviderFactory.java @@ -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 workCache; + private volatile Cache 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 putIfAbsentWithRetries(CrossDCAwareCacheFactory crossDCAwareCacheFactory, String key, V value, int taskTimeoutInSeconds) { + static V putIfAbsentWithRetries(CrossDCAwareCacheFactory crossDCAwareCacheFactory, String key, V value, int taskTimeoutInSeconds) { AtomicReference resultRef = new AtomicReference<>(); Retry.executeWithBackoff(iteration -> { diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanNotificationsManager.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanNotificationsManager.java index d0907221d9..96d4147a37 100644 --- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanNotificationsManager.java +++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/InfinispanNotificationsManager.java @@ -75,7 +75,7 @@ public class InfinispanNotificationsManager { private final ConcurrentMap taskCallbacks = new ConcurrentHashMap<>(); - private final Cache workCache; + private final Cache workCache; private final RemoteCache workRemoteCache; @@ -85,7 +85,7 @@ public class InfinispanNotificationsManager { private final ExecutorService listenersExecutor; - protected InfinispanNotificationsManager(Cache workCache, RemoteCache workRemoteCache, String myAddress, String mySite, ExecutorService listenersExecutor) { + protected InfinispanNotificationsManager(Cache workCache, RemoteCache 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 workCache, String myAddress, String mySite, Set remoteStores) { + public static InfinispanNotificationsManager create(KeycloakSession session, Cache workCache, String myAddress, String mySite, Set remoteStores) { RemoteCache 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 event) { + public void cacheEntryCreated(CacheEntryCreatedEvent event) { eventReceived(event.getKey(), event.getValue()); } @CacheEntryModified - public void cacheEntryModified(CacheEntryModifiedEvent event) { + public void cacheEntryModified(CacheEntryModifiedEvent event) { eventReceived(event.getKey(), event.getNewValue()); } @CacheEntryRemoved - public void cacheEntryRemoved(CacheEntryRemovedEvent event) { + public void cacheEntryRemoved(CacheEntryRemovedEvent 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(); diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/LockEntry.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/LockEntry.java index bbc2127a34..e5cfa235fc 100644 --- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/LockEntry.java +++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/LockEntry.java @@ -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 Marek Posolda */ -@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 { - - 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) { } diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/LockEntryPredicate.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/LockEntryPredicate.java index b7a10c33c4..1f839656b0 100644 --- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/LockEntryPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/LockEntryPredicate.java @@ -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 Marek Posolda */ -@SerializeWith(LockEntryPredicate.ExternalizerImpl.class) -public class LockEntryPredicate implements Predicate> { +@ProtoTypeId(Marshalling.LOCK_ENTRY_PREDICATE) +public class LockEntryPredicate implements Predicate> { private final Set removedNodesAddresses; + @ProtoFactory public LockEntryPredicate(Set removedNodesAddresses) { this.removedNodesAddresses = removedNodesAddresses; } + @ProtoField(value = 1, collectionImplementation = HashSet.class) + Set getRemovedNodesAddresses() { + return removedNodesAddresses; + } + @Override - public boolean test(Map.Entry entry) { - if (!(entry.getValue() instanceof LockEntry)) { - return false; - } + public boolean test(Map.Entry 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 { - - 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) - ); - } - } - } diff --git a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/WrapperClusterEvent.java b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/WrapperClusterEvent.java index ef287461a2..0c3663153b 100644 --- a/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/WrapperClusterEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/cluster/infinispan/WrapperClusterEvent.java @@ -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 Marek Posolda */ -@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 { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java index 6e4ab512c3..ce14336a70 100644 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProvider.java @@ -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 Stian Thorgersen @@ -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 clearPersistenceManager(PersistenceManager persistenceManager) { + return persistenceManager.clearAllStores(PersistenceManager.AccessMode.BOTH); + } + @Override public Cache getCache(String name, boolean createIfAbsent) { return cacheManager.getCache(name, createIfAbsent); @@ -51,6 +64,19 @@ public class DefaultInfinispanConnectionProvider implements InfinispanConnection return topologyInfo; } + @Override + public CompletionStage 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() { } diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java index 6d38256a6a..ad2cff47a5 100755 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java @@ -180,11 +180,11 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon if (providers.hasNext()) { ManagedCacheManagerProvider provider = providers.next(); - + if (providers.hasNext()) { throw new RuntimeException("Multiple " + org.keycloak.cluster.ManagedCacheManagerProvider.class + " providers found."); } - + managedCacheManager = provider.getEmbeddedCacheManager(config); } @@ -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(); diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java index 1f0747efc0..bb6d0c06d5 100755 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java @@ -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 migrateToProtostream(); + } diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanUtil.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanUtil.java index 95e901a330..d5e5ce7dcf 100644 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanUtil.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanUtil.java @@ -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); + } } } } diff --git a/model/infinispan/src/main/java/org/keycloak/keys/infinispan/PublicKeyStorageInvalidationEvent.java b/model/infinispan/src/main/java/org/keycloak/keys/infinispan/PublicKeyStorageInvalidationEvent.java index 0f292c6208..8c8426940b 100644 --- a/model/infinispan/src/main/java/org/keycloak/keys/infinispan/PublicKeyStorageInvalidationEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/keys/infinispan/PublicKeyStorageInvalidationEvent.java @@ -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 Marek Posolda */ -@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 { - - 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() + " ]"; } } diff --git a/model/infinispan/src/main/java/org/keycloak/keys/infinispan/PublicKeysEntry.java b/model/infinispan/src/main/java/org/keycloak/keys/infinispan/PublicKeysEntry.java index a26f4b46d1..dddc4a2f54 100644 --- a/model/infinispan/src/main/java/org/keycloak/keys/infinispan/PublicKeysEntry.java +++ b/model/infinispan/src/main/java/org/keycloak/keys/infinispan/PublicKeysEntry.java @@ -17,13 +17,12 @@ package org.keycloak.keys.infinispan; -import java.io.Serializable; import org.keycloak.crypto.PublicKeysWrapper; /** * @author Marek Posolda */ -public class PublicKeysEntry implements Serializable { +public class PublicKeysEntry { private final int lastRequestTime; diff --git a/model/infinispan/src/main/java/org/keycloak/marshalling/KeycloakModelSchema.java b/model/infinispan/src/main/java/org/keycloak/marshalling/KeycloakModelSchema.java new file mode 100644 index 0000000000..ba64805f80 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/marshalling/KeycloakModelSchema.java @@ -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(); + + +} diff --git a/model/infinispan/src/main/java/org/keycloak/marshalling/Marshalling.java b/model/infinispan/src/main/java/org/keycloak/marshalling/Marshalling.java index e710f09def..ada0fd3833 100644 --- a/model/infinispan/src/main/java/org/keycloak/marshalling/Marshalling.java +++ b/model/infinispan/src/main/java/org/keycloak/marshalling/Marshalling.java @@ -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. + *

+ * Read careful the following warning to ensure compatibility when updating schemas. + *

+ * 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. + *

+ * 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) + *

+ * Docs: Language Guide (proto 3) + */ 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; + } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java index 63c615eaa8..a0d1dc8a1b 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java @@ -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; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java index 1937268fbd..4eab3786a0 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheManager.java @@ -62,7 +62,7 @@ public class StoreFactoryCacheManager extends CacheManager { public void resourceServerRemoval(String id, Set 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 invalidations) { @@ -74,7 +74,7 @@ public class StoreFactoryCacheManager extends CacheManager { public void scopeRemoval(String id, String name, String serverId, Set 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 uris, Set scopes, String serverId, String owner, Set 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 uris, String owner, Set scopes, String serverId, Set 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 resources, Set resourceTypes, Set scopes, String serverId, Set invalidations) { diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java index 02d00da7ac..7c3894ee53 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/StoreFactoryCacheSession.java @@ -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 resources, Set 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); diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BasePolicyEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BasePolicyEvent.java new file mode 100644 index 0000000000..16ec87e9bb --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BasePolicyEvent.java @@ -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 resources; + @ProtoField(value = 4, collectionImplementation = HashSet.class) + final Set resourceTypes; + @ProtoField(value = 5, collectionImplementation = HashSet.class) + final Set scopes; + @ProtoField(6) + final String serverId; + + BasePolicyEvent(String id, String name, Set resources, Set resourceTypes, Set 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); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BaseResourceEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BaseResourceEvent.java new file mode 100644 index 0000000000..3f756f137c --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BaseResourceEvent.java @@ -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 uris; + @ProtoField(value = 7, collectionImplementation = HashSet.class) + final Set scopes; + + BaseResourceEvent(String id, String name, String owner, String serverId, String type, Set uris, Set 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); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BaseResourceServerEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BaseResourceServerEvent.java new file mode 100644 index 0000000000..3833b7ad78 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BaseResourceServerEvent.java @@ -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()); + } + +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BaseScopeEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BaseScopeEvent.java new file mode 100644 index 0000000000..1ffbf4348a --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/BaseScopeEvent.java @@ -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); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketRemovedEvent.java index 4f5f938d3d..49e81eb8da 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketRemovedEvent.java @@ -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 invalidations) { - cache.permissionTicketRemoval(id, owner, requester, resource, resourceName, scope, serverId, invalidations); + cache.permissionTicketRemoval(getId(), owner, requester, resource, resourceName, scope, serverId, invalidations); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketUpdatedEvent.java index 3158b79d17..c3e6e74e19 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PermissionTicketUpdatedEvent.java @@ -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 invalidations) { - cache.permissionTicketUpdated(id, owner, requester, resource, resourceName, scope, serverId, invalidations); + cache.permissionTicketUpdated(getId(), owner, requester, resource, resourceName, scope, serverId, invalidations); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java index 58f0006295..a72e7320a9 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyRemovedEvent.java @@ -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 Marek Posolda */ -@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 resources; - private Set resourceTypes; - private Set scopes; - private String serverId; + @ProtoFactory + PolicyRemovedEvent(String id, String name, Set resources, Set resourceTypes, Set scopes, String serverId) { + super(id, name, resources, resourceTypes, scopes, serverId); + } public static PolicyRemovedEvent create(String id, String name, Set resources, Set resourceTypes, Set 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 invalidations) { - cache.policyRemoval(id, name, resources, resourceTypes, scopes, serverId, invalidations); - } - - public static class ExternalizerImpl implements Externalizer { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java index e3ac21899a..df5e80abf7 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/PolicyUpdatedEvent.java @@ -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 Marek Posolda */ -@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 resources; - private Set resourceTypes; - private Set scopes; - private String serverId; + @ProtoFactory + PolicyUpdatedEvent(String id, String name, Set resources, Set resourceTypes, Set scopes, String serverId) { + super(id, name, resources, resourceTypes, scopes, serverId); + } public static PolicyUpdatedEvent create(String id, String name, Set resources, Set resourceTypes, Set 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 invalidations) { - cache.policyUpdated(id, name, resources, resourceTypes, scopes, serverId, invalidations); - } - - public static class ExternalizerImpl implements Externalizer { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java index 8514ba3e9c..61a4ab9ed1 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceRemovedEvent.java @@ -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 Marek Posolda */ -@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 uris; - private Set scopes; + @ProtoFactory + static ResourceRemovedEvent protoFactory(String id, String name, String owner, String serverId, String type, Set uris, Set 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 uris, Set scopes) { + super(id, name, owner, serverId, type, uris, scopes); + } public static ResourceRemovedEvent create(String id, String name, String type, Set uris, String owner, Set 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 invalidations) { - cache.resourceRemoval(id, name, type, uris, owner, scopes, serverId, invalidations); - } - - public static class ExternalizerImpl implements Externalizer { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java index d6724a78a7..7db29bda2a 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerRemovedEvent.java @@ -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 Marek Posolda */ -@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 invalidations) { - cache.resourceServerRemoval(id, invalidations); - } - - public static class ExternalizerImpl implements Externalizer { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java index f46611bd74..f6a41f8257 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceServerUpdatedEvent.java @@ -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 Marek Posolda */ -@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 invalidations) { - cache.resourceServerUpdated(id, invalidations); - } - - public static class ExternalizerImpl implements Externalizer { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java index c313f6c5df..78e578641e 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ResourceUpdatedEvent.java @@ -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 Marek Posolda */ -@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 uris; - private Set scopes; - private String owner; - - public static ResourceUpdatedEvent create(String id, String name, String type, Set uris, Set 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 uris, Set 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 uris, Set 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 uris, String owner, Set scopes, String serverId) { + return new ResourceUpdatedEvent(id, name, owner, serverId, type, uris, scopes); } @Override public void addInvalidations(StoreFactoryCacheManager cache, Set 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java index a75852e356..5564fdb6a2 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeRemovedEvent.java @@ -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 Marek Posolda */ -@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 invalidations) { - cache.scopeRemoval(id, name, serverId, invalidations); - } - - public static class ExternalizerImpl implements Externalizer { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java index 5e594d9747..35eb4d36a7 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/events/ScopeUpdatedEvent.java @@ -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 Marek Posolda */ -@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 invalidations) { - cache.scopeUpdated(id, name, serverId, invalidations); - } - - public static class ExternalizerImpl implements Externalizer { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourcePredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourcePredicate.java index b4c7c1c022..cff9e1316a 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourcePredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourcePredicate.java @@ -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 Pedro Igor */ -@SerializeWith(InResourcePredicate.ExternalizerImpl.class) -public class InResourcePredicate implements Predicate>, Serializable { +@ProtoTypeId(Marshalling.IN_RESOURCE_PREDICATE) +public class InResourcePredicate implements Predicate> { - 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 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java index 2a0b6cf80c..671f391fe3 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InResourceServerPredicate.java @@ -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 Bill Burke * @version $Revision: 1 $ */ -@SerializeWith(InResourceServerPredicate.ExternalizerImpl.class) -public class InResourceServerPredicate implements Predicate>, Serializable { - private String serverId; +@ProtoTypeId(Marshalling.IN_RESOURCE_SERVER_PREDICATE) +public class InResourceServerPredicate implements Predicate> { + 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 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InScopePredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InScopePredicate.java index 1c6bced8c0..16c54be17f 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InScopePredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/authorization/stream/InScopePredicate.java @@ -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 Bill Burke * @version $Revision: 1 $ */ -@SerializeWith(InScopePredicate.ExternalizerImpl.class) -public class InScopePredicate implements Predicate>, Serializable { - private String scopeId; +@ProtoTypeId(Marshalling.IN_SCOPE_PREDICATE) +public class InScopePredicate implements Predicate> { + 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 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/AbstractRevisioned.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/AbstractRevisioned.java index 8c88df774f..bf6cbeb7c7 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/AbstractRevisioned.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/AbstractRevisioned.java @@ -9,8 +9,8 @@ import java.io.Serializable; * @author Bill Burke * @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(); diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java index ca331e7729..67bd1d130f 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java @@ -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 requiredCredentials; - protected MultivaluedHashMap componentsByParent = new MultivaluedHashMap<>(); - protected MultivaluedHashMap componentsByParentAndType = new MultivaluedHashMap<>(); + protected MultivaluedMap componentsByParent = new MultivaluedHashMap<>(); + protected MultivaluedMap componentsByParentAndType = new ConcurrentMultivaluedHashMap<>(); protected Map components; protected List identityProviders; @@ -417,11 +419,11 @@ public class CachedRealm extends AbstractExtendableRevisioned { public boolean isVerifyEmail() { return verifyEmail; } - + public boolean isLoginWithEmailAllowed() { return loginWithEmailAllowed; } - + public boolean isDuplicateEmailsAllowed() { return duplicateEmailsAllowed; } @@ -650,7 +652,7 @@ public class CachedRealm extends AbstractExtendableRevisioned { public AuthenticationExecutionModel getAuthenticationExecutionByFlowId(String flowId) { return executionsByFlowId.get(flowId); } - + public Map getExecutionsById() { return executionsById; } @@ -723,11 +725,11 @@ public class CachedRealm extends AbstractExtendableRevisioned { return requiredActionProviderList; } - public MultivaluedHashMap getComponentsByParent() { + public MultivaluedMap getComponentsByParent() { return componentsByParent; } - public MultivaluedHashMap getComponentsByParentAndType() { + public MultivaluedMap getComponentsByParentAndType() { return componentsByParentAndType; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/AuthenticationSessionAuthNoteUpdateEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/AuthenticationSessionAuthNoteUpdateEvent.java index 8135efee38..621b9b534a 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/AuthenticationSessionAuthNoteUpdateEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/AuthenticationSessionAuthNoteUpdateEvent.java @@ -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 authNotesFragment; - private Map authNotesFragment; + private AuthenticationSessionAuthNoteUpdateEvent(Map 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 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 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 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 { - - 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.>unmarshallMap(input, HashMap::new) - ); - } - - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseClientEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseClientEvent.java new file mode 100644 index 0000000000..2db14d7ddc --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseClientEvent.java @@ -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()); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseClientScopeEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseClientScopeEvent.java new file mode 100644 index 0000000000..3da959b859 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseClientScopeEvent.java @@ -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); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseRealmEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseRealmEvent.java new file mode 100644 index 0000000000..a709544914 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseRealmEvent.java @@ -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); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseRoleEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseRoleEvent.java new file mode 100644 index 0000000000..05e8736afd --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/BaseRoleEvent.java @@ -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); + } +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientAddedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientAddedEvent.java index 570fbdaf48..9195a4e0e7 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientAddedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientAddedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientRemovedEvent.java index 0319ad3085..77d3217374 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientRemovedEvent.java @@ -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 Marek Posolda */ -@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 clientRoles; - private static final Logger log = Logger.getLogger(ClientRemovedEvent.class); + @ProtoField(4) + final Map clientRoles; + + @ProtoFactory + ClientRemovedEvent(String id, String realmId, String clientId, Map 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 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 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 { - - 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; } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientScopeAddedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientScopeAddedEvent.java index 848533ee47..d6a3629f45 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientScopeAddedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientScopeAddedEvent.java @@ -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 invalidations) { realmCache.clientScopeAdded(realmId, invalidations); } - - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientScopeRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientScopeRemovedEvent.java index b660557c74..e8ab31458f 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientScopeRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientScopeRemovedEvent.java @@ -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 invalidations) { realmCache.clientScopeRemoval(realmId, invalidations); } - - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientTemplateEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientTemplateEvent.java deleted file mode 100644 index 1f06de09df..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientTemplateEvent.java +++ /dev/null @@ -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 Marek Posolda - */ -@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 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 { - - 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; - } - } -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientUpdatedEvent.java index 27501c74fa..eef30622f9 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/ClientUpdatedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupAddedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupAddedEvent.java index a6cd2f67f7..79df2f671d 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupAddedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupAddedEvent.java @@ -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 Marek Posolda */ -@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 { - - 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; } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupMovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupMovedEvent.java index f2e1ac10fa..6e2ee7df9a 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupMovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupMovedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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; } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupRemovedEvent.java index 76e25ff154..9f914b8dc3 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupRemovedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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; } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupUpdatedEvent.java index eced20a473..27e4375da6 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/GroupUpdatedEvent.java @@ -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 Marek Posolda */ -@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 invalidations) { - realmCache.groupNameInvalidations(groupId, invalidations); + realmCache.groupNameInvalidations(getId(), invalidations); } - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/InvalidationEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/InvalidationEvent.java index ea59ff5f1f..64478e4146 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/InvalidationEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/InvalidationEvent.java @@ -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()); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RealmRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RealmRemovedEvent.java index 211547d914..6bb0700fd6 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RealmRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RealmRemovedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RealmUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RealmUpdatedEvent.java index 693b6d07f0..1130d4fa14 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RealmUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RealmUpdatedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleAddedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleAddedEvent.java index 661bb96908..d780006e66 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleAddedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleAddedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleRemovedEvent.java index 1af41f0b0f..d4c861633c 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleRemovedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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; } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleUpdatedEvent.java index 97ece52522..5803617640 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/RoleUpdatedEvent.java @@ -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 Marek Posolda */ -@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 { - - 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; } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserCacheRealmInvalidationEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserCacheRealmInvalidationEvent.java index 2f144d2371..f5550ccb35 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserCacheRealmInvalidationEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserCacheRealmInvalidationEvent.java @@ -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 Marek Posolda */ -@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 invalidations) { - userCache.invalidateRealmUsers(realmId, invalidations); + userCache.invalidateRealmUsers(getId(), invalidations); } - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserConsentsUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserConsentsUpdatedEvent.java index 1d4b93d6c2..dfa341d24a 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserConsentsUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserConsentsUpdatedEvent.java @@ -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 Marek Posolda */ -@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 invalidations) { - userCache.consentInvalidation(userId, invalidations); + userCache.consentInvalidation(getId(), invalidations); } - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFederationLinkRemovedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFederationLinkRemovedEvent.java index 8b749130a2..b8b7e42bb0 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFederationLinkRemovedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFederationLinkRemovedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFederationLinkUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFederationLinkUpdatedEvent.java index 692915bffd..ed4954f1a9 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFederationLinkUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFederationLinkUpdatedEvent.java @@ -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 Marek Posolda */ -@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 invalidations) { - userCache.federatedIdentityLinkUpdatedInvalidation(userId, invalidations); + userCache.federatedIdentityLinkUpdatedInvalidation(getId(), invalidations); } - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFullInvalidationEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFullInvalidationEvent.java index a64126c861..7babc97eee 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFullInvalidationEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserFullInvalidationEvent.java @@ -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 Marek Posolda */ -@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 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 federatedIdentities; - public static UserFullInvalidationEvent create(String userId, String username, String email, String realmId, boolean identityFederationEnabled, Stream 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 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 federatedIdentities) { + Map 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 federatedIdentities) { + return new UserFullInvalidationEvent(id, username, Marshalling.emptyStringToNull(email), realmId, identityFederationEnabled, federatedIdentities); } public Map 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 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserUpdatedEvent.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserUpdatedEvent.java index 85df9e8852..9626e13209 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserUpdatedEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/events/UserUpdatedEvent.java @@ -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 Marek Posolda */ -@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 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupListPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupListPredicate.java index c89c44bb74..ed39b5a9d4 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupListPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/GroupListPredicate.java @@ -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 Bill Burke * @version $Revision: 1 $ */ -@SerializeWith(GroupListPredicate.ExternalizerImpl.class) -public class GroupListPredicate implements Predicate>, Serializable { +@ProtoTypeId(Marshalling.GROUP_LIST_PREDICATE) +public class GroupListPredicate implements Predicate> { private String realm; public static GroupListPredicate create() { @@ -30,43 +26,18 @@ public class GroupListPredicate implements Predicate 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java index 2523dc9b26..e55bb7fe5a 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/HasRolePredicate.java @@ -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 Bill Burke * @version $Revision: 1 $ */ -@SerializeWith(HasRolePredicate.ExternalizerImpl.class) -public class HasRolePredicate implements Predicate>, Serializable { +@ProtoTypeId(Marshalling.HAS_ROLE_PREDICATE) +public class HasRolePredicate implements Predicate> { private String role; public static HasRolePredicate create() { @@ -34,61 +31,23 @@ public class HasRolePredicate implements Predicate return this; } + @ProtoField(1) + String getRole() { + return role; + } + + void setRole(String role) { + this.role = role; + } + @Override public boolean test(Map.Entry 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java index 3837c71cba..d24acb3bc3 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InClientPredicate.java @@ -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 Bill Burke * @version $Revision: 1 $ */ -@SerializeWith(InClientPredicate.ExternalizerImpl.class) -public class InClientPredicate implements Predicate>, Serializable { +@ProtoTypeId(Marshalling.IN_CLIENT_PREDICATE) +public class InClientPredicate implements Predicate> { private String clientId; public static InClientPredicate create() { @@ -30,41 +27,18 @@ public class InClientPredicate implements Predicate 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InGroupPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InGroupPredicate.java index eae8f18442..568d96cf05 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InGroupPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InGroupPredicate.java @@ -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>, Serializable { +@ProtoTypeId(Marshalling.IN_GROUP_PREDICATE) +public class InGroupPredicate implements Predicate> { private String group; public static InGroupPredicate create() { @@ -43,41 +40,19 @@ public class InGroupPredicate implements Predicate return this; } + @ProtoField(1) + String getGroup() { + return group; + } + + void setGroup(String group) { + this.group = group; + } + @Override public boolean test(Map.Entry 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 { - - 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; - } - } } \ No newline at end of file diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InIdentityProviderPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InIdentityProviderPredicate.java index aef0b488fc..cba44bc2ab 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InIdentityProviderPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InIdentityProviderPredicate.java @@ -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 Pedro Igor */ -@SerializeWith(InIdentityProviderPredicate.ExternalizerImpl.class) -public class InIdentityProviderPredicate implements Predicate>, Serializable { +@ProtoTypeId(Marshalling.IN_IDENTITY_PROVIDER_PREDICATE) +public class InIdentityProviderPredicate implements Predicate> { private String id; public static InIdentityProviderPredicate create() { @@ -30,41 +26,18 @@ public class InIdentityProviderPredicate implements Predicate 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java index 7144d613b8..dd0071ef86 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/stream/InRealmPredicate.java @@ -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 Bill Burke * @version $Revision: 1 $ */ -@SerializeWith(InRealmPredicate.ExternalizerImpl.class) -public class InRealmPredicate implements Predicate>, Serializable { +@ProtoTypeId(Marshalling.IN_REALM_PREDICATE) +public class InRealmPredicate implements Predicate> { private String realm; public static InRealmPredicate create() { @@ -30,41 +27,19 @@ public class InRealmPredicate implements Predicate return this; } + @ProtoField(1) + String getRealm() { + return realm; + } + + void setRealm(String realm) { + this.realm = realm; + } + @Override public boolean test(Map.Entry 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 { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java index ca9f981876..f8daf9c627 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java @@ -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> 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 ); diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserLoginFailureProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserLoginFailureProvider.java index c51f2363ca..161a4637a7 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserLoginFailureProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserLoginFailureProvider.java @@ -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 diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserLoginFailureProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserLoginFailureProviderFactory.java index 79b16bb9d0..21b0cca50d 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserLoginFailureProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserLoginFailureProviderFactory.java @@ -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 workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME); + Cache workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME); int defaultStateTransferTimeout = (int) (connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME) .getCacheConfiguration().clustering().stateTransfer().timeout() / 1000); diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java index db20044ee4..817df0671b 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java @@ -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() { diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java index f6246ccbd2..f5bbd76e72 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java @@ -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 workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME); + Cache workCache = connections.getCache(InfinispanConnectionProvider.WORK_CACHE_NAME); int defaultStateTransferTimeout = (int) (connections.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME) .getCacheConfiguration().clustering().stateTransfer().timeout() / 1000); diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/PersistentUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/PersistentUserSessionProvider.java index bb6f499d79..e1d5837e9d 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/PersistentUserSessionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/PersistentUserSessionProvider.java @@ -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 -> { 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 -> { 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()); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/ReplaceFunction.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/ReplaceFunction.java index 10aad03433..9fff0b89e2 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/ReplaceFunction.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/ReplaceFunction.java @@ -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 The Infinispan key type. * @param The Infinispan value type (Keycloak entity) */ +@ProtoTypeId(Marshalling.REPLACE_FUNCTION) public class ReplaceFunction implements BiFunction, SessionEntityWrapper> { - @SuppressWarnings({"removal", "rawtypes"}) - public static final AdvancedExternalizer INSTANCE = new Externalizer(); private final UUID expectedVersion; private final SessionEntityWrapper newValue; + @ProtoFactory public ReplaceFunction(UUID expectedVersion, SessionEntityWrapper newValue) { this.expectedVersion = Objects.requireNonNull(expectedVersion); this.newValue = Objects.requireNonNull(newValue); @@ -37,37 +40,13 @@ public class ReplaceFunction implements BiFunction { + @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> 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(MarshallUtil.unmarshallUUID(input, false), EXTERNALIZER.readObject(input)); - } + @ProtoField(2) + SessionEntityWrapper getNewValue() { + return newValue; } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionEntityWrapper.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionEntityWrapper.java index 13b92b4f4b..e3c1487721 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionEntityWrapper.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/SessionEntityWrapper.java @@ -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 Marek Posolda */ -@SerializeWith(SessionEntityWrapper.ExternalizerImpl.class) +@ProtoTypeId(Marshalling.SESSION_ENTITY_WRAPPER) public class SessionEntityWrapper { - private static final Logger log = Logger.getLogger(SessionEntityWrapper.class); - private final UUID version; private final S entity; private final Map localMetadata; @@ -87,6 +82,7 @@ public class SessionEntityWrapper { return this.version == null; } + @ProtoField(1) public UUID getVersion() { return version; } @@ -95,6 +91,26 @@ public class SessionEntityWrapper { return entity; } + @ProtoField(2) + WrappedMessage getEntityPS() { + return new WrappedMessage(getEntity()); + } + + @ProtoField(value = 3, mapImplementation = ConcurrentHashMap.class) + public Map getLocalMetadata() { + return localMetadata; + } + + @ProtoFactory + static SessionEntityWrapper create(UUID version, WrappedMessage entityPS, Map 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 { localMetadata.put(key, String.valueOf(value)); } - public Map 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 { return "SessionEntityWrapper{" + "version=" + version + ", entity=" + entity + ", localMetadata=" + localMetadata + '}'; } - public static class ExternalizerImpl implements Externalizer { - - 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 map = MarshallUtil.>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); - } - } - - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/CrossDCLastSessionRefreshListener.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/CrossDCLastSessionRefreshListener.java index 7108f48d3d..e395ae660b 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/CrossDCLastSessionRefreshListener.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/CrossDCLastSessionRefreshListener.java @@ -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)) { diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshEvent.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshEvent.java index 42d0db70e4..a917f1e7d6 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/LastSessionRefreshEvent.java @@ -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 Marek Posolda */ -@SerializeWith(LastSessionRefreshEvent.ExternalizerImpl.class) +@ProtoTypeId(Marshalling.LAST_SESSION_REFRESH_EVENT) public class LastSessionRefreshEvent implements ClusterEvent { private final Map lastSessionRefreshes; + @ProtoFactory public LastSessionRefreshEvent(Map lastSessionRefreshes) { this.lastSessionRefreshes = lastSessionRefreshes; } + @ProtoField(value = 1, mapImplementation = HashMap.class) public Map getLastSessionRefreshes() { return lastSessionRefreshes; } @@ -55,29 +54,4 @@ public class LastSessionRefreshEvent implements ClusterEvent { return 1; } - public static class ExternalizerImpl implements Externalizer { - - - @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 map = MarshallUtil.unmarshallMap(input, new MarshallUtil.MapBuilder>() { - - @Override - public Map build(int size) { - return new HashMap<>(size); - } - - }); - - LastSessionRefreshEvent event = new LastSessionRefreshEvent(map); - return event; - } - - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/PersisterLastSessionRefreshStore.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/PersisterLastSessionRefreshStore.java index efb1865a93..d89b6bfdf6 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/PersisterLastSessionRefreshStore.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/PersisterLastSessionRefreshStore.java @@ -51,7 +51,7 @@ public class PersisterLastSessionRefreshStore extends AbstractLastSessionRefresh protected void sendMessage(KeycloakSession kcSession, Map refreshesToSend) { Map> 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 diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/SessionData.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/SessionData.java index c2e6c86f87..168753e64f 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/SessionData.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/changes/sessions/SessionData.java @@ -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 Marek Posolda */ -@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 { - - - @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); - } - - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java index 411adf36f5..2d43cfae43 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionEntity.java @@ -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 Marek Posolda */ -@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 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 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 { - - @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 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 notes = KeycloakMarshallUtil.readMap(input, KeycloakMarshallUtil.STRING_EXT, KeycloakMarshallUtil.STRING_EXT, - new KeycloakMarshallUtil.ConcurrentHashMapBuilder<>()); - sessionEntity.setNotes(notes); - - return sessionEntity; - } - - } - } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionStore.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionStore.java index ebf946e295..0f87aabc1d 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionStore.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticatedClientSessionStore.java @@ -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 authenticatedClientSessionIds; + private final ConcurrentMap authenticatedClientSessionIds; public AuthenticatedClientSessionStore() { authenticatedClientSessionIds = new ConcurrentHashMap<>(); } - private AuthenticatedClientSessionStore(ConcurrentHashMap authenticatedClientSessionIds) { + @ProtoFactory + AuthenticatedClientSessionStore(ConcurrentMap authenticatedClientSessionIds) { this.authenticatedClientSessionIds = authenticatedClientSessionIds; } @@ -79,37 +80,14 @@ public class AuthenticatedClientSessionStore { return authenticatedClientSessionIds.size(); } + @ProtoField(value = 1, mapImplementation = ConcurrentHashMap.class) + ConcurrentMap getAuthenticatedClientSessionIds() { + return authenticatedClientSessionIds; + } + @Override public String toString() { return this.authenticatedClientSessionIds.toString(); } - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java index 22f5f647ec..0e3ea65b25 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java @@ -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 Marek Posolda */ -@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 clientScopes, - Map executionStatus, String protocol, - Map clientNotes, Map authNotes, Set requiredActions, Map userSessionNotes) { + String clientUUID, + String authUserId, + int timestamp, + String redirectUri, String action, Set clientScopes, + Map executionStatus, String protocol, + Map clientNotes, Map authNotes, Set requiredActions, Map 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 getClientScopes() { return clientScopes; } @@ -141,6 +142,7 @@ public class AuthenticationSessionEntity implements Serializable { this.clientScopes = clientScopes; } + @ProtoField(value = 7, mapImplementation = ConcurrentHashMap.class) public Map 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 getClientNotes() { return clientNotes; } @@ -165,6 +169,7 @@ public class AuthenticationSessionEntity implements Serializable { this.clientNotes = clientNotes; } + @ProtoField(value = 10, collectionImplementation = HashSet.class) public Set getRequiredActions() { return requiredActions; } @@ -173,6 +178,7 @@ public class AuthenticationSessionEntity implements Serializable { this.requiredActions = requiredActions; } + @ProtoField(value = 11, mapImplementation = ConcurrentHashMap.class) public Map getUserSessionNotes() { return userSessionNotes; } @@ -181,6 +187,7 @@ public class AuthenticationSessionEntity implements Serializable { this.userSessionNotes = userSessionNotes; } + @ProtoField(value = 12, mapImplementation = ConcurrentHashMap.class) public Map getAuthNotes() { return authNotes; } @@ -188,109 +195,4 @@ public class AuthenticationSessionEntity implements Serializable { public void setAuthNotes(Map authNotes) { this.authNotes = authNotes; } - - public static class ExternalizerImpl implements Externalizer { - - 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 EXECUTION_STATUS_EXT = new Externalizer() { - - @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 - ); - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java index fdb02b668d..730bc62732 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java @@ -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 Stian Thorgersen */ -@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 { - - 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) - ); - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java index 484aec71fe..bcafcaeef2 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java @@ -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 Stian Thorgersen */ -@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 { - - 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) { } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/RootAuthenticationSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/RootAuthenticationSessionEntity.java index f6173082bf..b1c3d23858 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/RootAuthenticationSessionEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/RootAuthenticationSessionEntity.java @@ -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 Marek Posolda */ -@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 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 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 { - - 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 - ); - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java index 0a46f792db..426ac2f3d4 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SessionEntity.java @@ -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 Stian Thorgersen */ -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); diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SingleUseObjectValueEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SingleUseObjectValueEntity.java index 617c8ed614..e612dd9f96 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SingleUseObjectValueEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/SingleUseObjectValueEntity.java @@ -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 notes; + @ProtoFactory public SingleUseObjectValueEntity(Map 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 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 { - - 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 notes = notesEmpty ? Collections.EMPTY_MAP : (Map) input.readObject(); - - return new SingleUseObjectValueEntity(notes); - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java index 3b2ce2b787..e923f9ed98 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java @@ -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 Stian Thorgersen */ -@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 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 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 { - - private static final int VERSION_1 = 1; - - private static final EnumMap STATE_TO_ID = new EnumMap<>(UserSessionModel.State.class); - private static final Map 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 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 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 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; - } - - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RealmRemovedSessionEvent.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RealmRemovedSessionEvent.java index 011f725c3e..10f2cfb063 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RealmRemovedSessionEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RealmRemovedSessionEvent.java @@ -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 Marek Posolda */ -@SerializeWith(RealmRemovedSessionEvent.ExternalizerImpl.class) +@ProtoTypeId(Marshalling.REALM_REMOVED_SESSION_EVENT) public class RealmRemovedSessionEvent extends SessionClusterEvent { - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } - } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RemoveAllUserLoginFailuresEvent.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RemoveAllUserLoginFailuresEvent.java index 5b5a589e9c..1903ca8c0a 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RemoveAllUserLoginFailuresEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RemoveAllUserLoginFailuresEvent.java @@ -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 Marek Posolda */ -@SerializeWith(RemoveAllUserLoginFailuresEvent.ExternalizerImpl.class) +@ProtoTypeId(Marshalling.REMOVE_ALL_USER_LOGIN_FAILURES_EVENT) public class RemoveAllUserLoginFailuresEvent extends SessionClusterEvent { - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } - } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RemoveUserSessionsEvent.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RemoveUserSessionsEvent.java index 091d3510c1..1a324c0003 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RemoveUserSessionsEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/RemoveUserSessionsEvent.java @@ -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 Marek Posolda */ -@SerializeWith(RemoveUserSessionsEvent.ExternalizerImpl.class) +@ProtoTypeId(Marshalling.REMOVE_ALL_USER_SESSIONS_EVENT) public class RemoveUserSessionsEvent extends SessionClusterEvent { - public static class ExternalizerImpl implements Externalizer { - - 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; - } - } - } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/SessionClusterEvent.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/SessionClusterEvent.java index 120c33ff15..330634d682 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/SessionClusterEvent.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/events/SessionClusterEvent.java @@ -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 Marek Posolda @@ -42,7 +39,7 @@ public abstract class SessionClusterEvent implements ClusterEvent { public static T createEvent(Class 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); - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/BaseCacheInitializer.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/BaseCacheInitializer.java index d18c7d19aa..696324cd60 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/BaseCacheInitializer.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/BaseCacheInitializer.java @@ -23,8 +23,6 @@ import org.infinispan.lifecycle.ComponentStatus; import org.jboss.logging.Logger; import org.keycloak.models.KeycloakSessionFactory; -import java.io.Serializable; - /** * @author Marek Posolda */ @@ -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 workCache; + protected final Cache workCache; protected final SessionLoader sessionLoader; protected final String stateKey; - public BaseCacheInitializer(KeycloakSessionFactory sessionFactory, Cache workCache, SessionLoader sessionLoader, String stateKeySuffix) { + public BaseCacheInitializer(KeycloakSessionFactory sessionFactory, Cache workCache, SessionLoader 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); } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanCacheInitializer.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanCacheInitializer.java index 6c3493ffb7..2a08148b86 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanCacheInitializer.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanCacheInitializer.java @@ -24,7 +24,6 @@ import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionTask; import org.keycloak.models.utils.KeycloakModelUtils; -import java.io.Serializable; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -45,7 +44,7 @@ public class InfinispanCacheInitializer extends BaseCacheInitializer { // Effectively no timeout private final int stalledTimeoutInSeconds; - public InfinispanCacheInitializer(KeycloakSessionFactory sessionFactory, Cache workCache, SessionLoader sessionLoader, String stateKeySuffix, int maxErrors, int stalledTimeoutInSeconds) { + public InfinispanCacheInitializer(KeycloakSessionFactory sessionFactory, Cache workCache, SessionLoader sessionLoader, String stateKeySuffix, int maxErrors, int stalledTimeoutInSeconds) { super(sessionFactory, workCache, sessionLoader, stateKeySuffix); this.maxErrors = maxErrors; this.stalledTimeoutInSeconds = stalledTimeoutInSeconds; diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InitializerState.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InitializerState.java index 3edfdb3169..2658860b69 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InitializerState.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InitializerState.java @@ -17,19 +17,17 @@ package org.keycloak.models.sessions.infinispan.initializer; +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.sessions.infinispan.entities.SessionEntity; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; import java.util.BitSet; import java.util.LinkedList; import java.util.List; import java.util.Objects; -import org.infinispan.commons.marshall.Externalizer; -import org.infinispan.commons.marshall.MarshallUtil; -import org.infinispan.commons.marshall.SerializeWith; /** * Note that this state is NOT thread safe. Currently it is only used from single thread so it's fine @@ -37,7 +35,7 @@ import org.infinispan.commons.marshall.SerializeWith; * * @author Marek Posolda */ -@SerializeWith(InitializerState.ExternalizerImpl.class) +@ProtoTypeId(Marshalling.INITIALIZER_STATE) public class InitializerState extends SessionEntity { private static final Logger log = Logger.getLogger(InitializerState.class); @@ -52,7 +50,8 @@ public class InitializerState extends SessionEntity { log.debugf("segmentsCount: %d", segmentsCount); } - private InitializerState(String realmId, int segmentsCount, BitSet segments) { + @ProtoFactory + InitializerState(String realmId, int segmentsCount, BitSet segments) { super(realmId); this.segmentsCount = segmentsCount; this.segments = segments; @@ -64,10 +63,16 @@ public class InitializerState extends SessionEntity { * Getter for the segments count. * @return The number of segments of the state */ + @ProtoField(2) public int getSegmentsCount() { return segmentsCount; } + @ProtoField(3) + BitSet getSegments() { + return segments; + } + /** Return true just if computation is entirely finished (all segments are true) */ public boolean isFinished() { return segments.cardinality() == segmentsCount; @@ -125,46 +130,8 @@ public class InitializerState extends SessionEntity { if (getClass() != obj.getClass()) { return false; } - final InitializerState other = (InitializerState) obj; - if (this.segmentsCount != other.segmentsCount) { - return false; - } - if ( ! Objects.equals(this.segments, other.segments)) { - return false; - } - return true; + InitializerState other = (InitializerState) obj; + return this.segmentsCount == other.segmentsCount && Objects.equals(this.segments, other.segments); } - public static class ExternalizerImpl implements Externalizer { - - private static final int VERSION_1 = 1; - - @Override - public void writeObject(ObjectOutput output, InitializerState value) throws IOException { - output.writeByte(VERSION_1); - - MarshallUtil.marshallString(value.getRealmId(), output); - output.writeInt(value.segmentsCount); - MarshallUtil.marshallByteArray(value.segments.toByteArray(), output); - } - - @Override - public InitializerState readObject(ObjectInput input) throws IOException, ClassNotFoundException { - switch (input.readByte()) { - case VERSION_1: - return readObjectVersion1(input); - default: - throw new IOException("Unknown version"); - } - } - - public InitializerState readObjectVersion1(ObjectInput input) throws IOException { - return new InitializerState( - MarshallUtil.unmarshallString(input), - input.readInt(), - BitSet.valueOf(MarshallUtil.unmarshallByteArray(input)) - ); - } - - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionInitializerWorker.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionInitializerWorker.java index 69c53dadaf..3a495b5ba1 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionInitializerWorker.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionInitializerWorker.java @@ -20,13 +20,12 @@ package org.keycloak.models.sessions.infinispan.initializer; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.utils.KeycloakModelUtils; -import java.io.Serializable; import java.util.function.Function; /** * @author Marek Posolda */ -public class SessionInitializerWorker implements Function, Serializable { +public class SessionInitializerWorker implements Function { private SessionLoader.LoaderContext loaderCtx; private SessionLoader.WorkerContext workerCtx; diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionLoader.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionLoader.java index be35fec980..cf66181611 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionLoader.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/SessionLoader.java @@ -17,8 +17,6 @@ package org.keycloak.models.sessions.infinispan.initializer; -import java.io.Serializable; - import org.keycloak.models.KeycloakSession; /** @@ -26,7 +24,7 @@ import org.keycloak.models.KeycloakSession; */ public interface SessionLoader extends Serializable { + WORKER_RESULT extends SessionLoader.WorkerResult> { /** @@ -69,9 +67,9 @@ public interface SessionLoaderMarek Posolda */ -public class RemoteCacheSessionsLoader implements SessionLoader, Serializable { +public class RemoteCacheSessionsLoader implements SessionLoader { private static final Logger log = Logger.getLogger(RemoteCacheSessionsLoader.class); diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/BaseRealmPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/BaseRealmPredicate.java new file mode 100644 index 0000000000..40eea82050 --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/BaseRealmPredicate.java @@ -0,0 +1,41 @@ +/* + * 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.sessions.infinispan.stream; + +import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; + +import org.infinispan.protostream.annotations.ProtoField; + +abstract class BaseRealmPredicate implements Predicate> { + + @ProtoField(1) + final String realmId; + + BaseRealmPredicate(String realmId) { + this.realmId = Objects.requireNonNull(realmId); + } + + @Override + public boolean test(Map.Entry entry) { + return realmId.equals(realmIdFrom(entry.getValue())); + } + + abstract String realmIdFrom(V value); +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java index 4343f0a60d..f86a58a41a 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java @@ -52,14 +52,14 @@ public class Mappers { } - private static class LoginFailureIdMapper implements Function>, LoginFailureKey>, Serializable { + private static class LoginFailureIdMapper implements Function>, LoginFailureKey> { @Override public LoginFailureKey apply(Map.Entry> entry) { return entry.getKey(); } } - private static class AuthClientSessionSetMapper implements Function>, Set>, Serializable { + private static class AuthClientSessionSetMapper implements Function>, Set> { @Override public Set apply(Map.Entry> entry) { diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/RootAuthenticationSessionPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/RootAuthenticationSessionPredicate.java deleted file mode 100644 index 8f3ae5d006..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/RootAuthenticationSessionPredicate.java +++ /dev/null @@ -1,100 +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.sessions.infinispan.stream; - -import java.util.Map; -import java.util.function.Predicate; - -import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity; -import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil; -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 Marek Posolda - */ -@SerializeWith(RootAuthenticationSessionPredicate.ExternalizerImpl.class) -public class RootAuthenticationSessionPredicate implements Predicate> { - - private final String realm; - - private Integer expired; - - private RootAuthenticationSessionPredicate(String realm) { - this.realm = realm; - } - - public static RootAuthenticationSessionPredicate create(String realm) { - return new RootAuthenticationSessionPredicate(realm); - } - - public RootAuthenticationSessionPredicate expired(Integer expired) { - this.expired = expired; - return this; - } - - - @Override - public boolean test(Map.Entry entry) { - RootAuthenticationSessionEntity entity = entry.getValue(); - - if (!realm.equals(entity.getRealmId())) { - return false; - } - - if (expired != null && entity.getTimestamp() > expired) { - return false; - } - - return true; - } - - public static class ExternalizerImpl implements Externalizer { - - private static final int VERSION_1 = 1; - - @Override - public void writeObject(ObjectOutput output, RootAuthenticationSessionPredicate obj) throws IOException { - output.writeByte(VERSION_1); - - MarshallUtil.marshallString(obj.realm, output); - KeycloakMarshallUtil.marshall(obj.expired, output); - - } - - @Override - public RootAuthenticationSessionPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException { - switch (input.readByte()) { - case VERSION_1: - return readObjectVersion1(input); - default: - throw new IOException("Unknown version"); - } - } - - public RootAuthenticationSessionPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException { - RootAuthenticationSessionPredicate res = new RootAuthenticationSessionPredicate(MarshallUtil.unmarshallString(input)); - res.expired(KeycloakMarshallUtil.unmarshallInteger(input)); - return res; - } - } -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java old mode 100755 new mode 100644 index b93afcd41f..455b72dd57 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java @@ -17,64 +17,28 @@ package org.keycloak.models.sessions.infinispan.stream; -import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; +import org.infinispan.protostream.annotations.ProtoFactory; +import org.infinispan.protostream.annotations.ProtoTypeId; +import org.keycloak.marshalling.Marshalling; import org.keycloak.models.sessions.infinispan.entities.SessionEntity; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -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 Stian Thorgersen + * @author Marek Posolda */ -@SerializeWith(SessionPredicate.ExternalizerImpl.class) -public class SessionPredicate implements Predicate>> { +@ProtoTypeId(Marshalling.SESSION_PREDICATE) +public class SessionPredicate extends BaseRealmPredicate { - private final String realm; - - private SessionPredicate(String realm) { - this.realm = realm; + @ProtoFactory + SessionPredicate(String realmId) { + super(realmId); } - public static SessionPredicate create(String realm) { - return new SessionPredicate(realm); + public static SessionPredicate create(String realm) { + return new SessionPredicate<>(realm); } @Override - public boolean test(Map.Entry> entry) { - return realm.equals(entry.getValue().getEntity().getRealmId()); - } - - public static class ExternalizerImpl implements Externalizer { - - private static final int VERSION_1 = 1; - - @Override - public void writeObject(ObjectOutput output, SessionPredicate obj) throws IOException { - output.writeByte(VERSION_1); - - MarshallUtil.marshallString(obj.realm, output); - - } - - @Override - public SessionPredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException { - switch (input.readByte()) { - case VERSION_1: - return readObjectVersion1(input); - default: - throw new IOException("Unknown version"); - } - } - - public SessionPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException { - SessionPredicate res = new SessionPredicate(MarshallUtil.unmarshallString(input)); - return res; - } + String realmIdFrom(V value) { + return value.getRealmId(); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionWrapperPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionWrapperPredicate.java new file mode 100755 index 0000000000..94aa4f659b --- /dev/null +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionWrapperPredicate.java @@ -0,0 +1,46 @@ +/* + * 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.sessions.infinispan.stream; + +import org.infinispan.protostream.annotations.ProtoFactory; +import org.infinispan.protostream.annotations.ProtoTypeId; +import org.keycloak.marshalling.Marshalling; +import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; +import org.keycloak.models.sessions.infinispan.entities.SessionEntity; + +/** + * @author Stian Thorgersen + */ +@ProtoTypeId(Marshalling.SESSION_WRAPPER_PREDICATE) +public class SessionWrapperPredicate extends BaseRealmPredicate> { + + @ProtoFactory + SessionWrapperPredicate(String realmId) { + super(realmId); + } + + public static SessionWrapperPredicate create(String realm) { + return new SessionWrapperPredicate<>(realm); + } + + @Override + String realmIdFrom(SessionEntityWrapper value) { + return value.getEntity().getRealmId(); + } + +} diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserLoginFailurePredicate.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserLoginFailurePredicate.java deleted file mode 100755 index 4b7ca6beea..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserLoginFailurePredicate.java +++ /dev/null @@ -1,82 +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.sessions.infinispan.stream; - -import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; -import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity; -import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey; - -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -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 Stian Thorgersen - */ -@SerializeWith(UserLoginFailurePredicate.ExternalizerImpl.class) -public class UserLoginFailurePredicate implements Predicate>> { - - private final String realm; - - private UserLoginFailurePredicate(String realm) { - this.realm = realm; - } - - public static UserLoginFailurePredicate create(String realm) { - return new UserLoginFailurePredicate(realm); - } - - @Override - public boolean test(Map.Entry> entry) { - LoginFailureEntity e = entry.getValue().getEntity(); - return realm.equals(e.getRealmId()); - } - - public static class ExternalizerImpl implements Externalizer { - - private static final int VERSION_1 = 1; - - @Override - public void writeObject(ObjectOutput output, UserLoginFailurePredicate obj) throws IOException { - output.writeByte(VERSION_1); - - MarshallUtil.marshallString(obj.realm, output); - - } - - @Override - public UserLoginFailurePredicate readObject(ObjectInput input) throws IOException, ClassNotFoundException { - switch (input.readByte()) { - case VERSION_1: - return readObjectVersion1(input); - default: - throw new IOException("Unknown version"); - } - } - - public UserLoginFailurePredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException { - UserLoginFailurePredicate res = new UserLoginFailurePredicate(MarshallUtil.unmarshallString(input)); - return res; - } - } -} diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java index c87b125f08..1e3d8dc886 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java @@ -17,25 +17,22 @@ package org.keycloak.models.sessions.infinispan.stream; +import org.infinispan.protostream.annotations.ProtoFactory; +import org.infinispan.protostream.annotations.ProtoField; +import org.infinispan.protostream.annotations.ProtoTypeId; import org.keycloak.models.UserSessionModel; +import org.keycloak.marshalling.Marshalling; import org.keycloak.models.sessions.infinispan.AuthenticatedClientSessionAdapter; import org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper; import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity; -import org.keycloak.models.sessions.infinispan.util.KeycloakMarshallUtil; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; 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 Stian Thorgersen */ -@SerializeWith(UserSessionPredicate.ExternalizerImpl.class) +@ProtoTypeId(Marshalling.USER_SESSION_PREDICATE) public class UserSessionPredicate implements Predicate>> { private final String realm; @@ -44,14 +41,6 @@ public class UserSessionPredicate implements Predicate> entry) { UserSessionEntity entity = entry.getValue().getEntity(); - if (!realm.equals(entity.getRealmId())) { - return false; - } + return realm.equals(entity.getRealmId()) && + (user == null || entity.getUser().equals(user)) && + (client == null || (entity.getAuthenticatedClientSessions() != null && entity.getAuthenticatedClientSessions().containsKey(client))) && + (brokerSessionId == null || brokerSessionId.equals(entity.getBrokerSessionId())) && + (brokerUserId == null || brokerUserId.equals(entity.getBrokerUserId())); - if (user != null && !entity.getUser().equals(user)) { - return false; - } - - if (client != null && (entity.getAuthenticatedClientSessions() == null || !entity.getAuthenticatedClientSessions().containsKey(client))) { - return false; - } - - if (brokerSessionId != null && !brokerSessionId.equals(entity.getBrokerSessionId())) { - return false; - } - - if (brokerUserId != null && !brokerUserId.equals(entity.getBrokerUserId())) { - return false; - } - - if (entity.isRememberMe()) { - if (expiredRememberMe != null && expiredRefreshRememberMe != null && entity.getStarted() > expiredRememberMe && entity.getLastSessionRefresh() > expiredRefreshRememberMe) { - return false; - } - } - else { - if (expired != null && expiredRefresh != null && entity.getStarted() > expired && entity.getLastSessionRefresh() > expiredRefresh) { - return false; - } - } - - if (expired == null && expiredRefresh != null && entity.getLastSessionRefresh() > expiredRefresh) { - return false; - } - return true; - } - - public String getClient() { - return client; } public Predicate toModelPredicate() { - return (Predicate) entity -> { - if (!realm.equals(entity.getRealm().getId())) { - return false; - } - - if (user != null && !entity.getUser().getId().equals(user)) { - return false; - } - - if (client != null && (entity.getAuthenticatedClientSessions() == null || !entity.getAuthenticatedClientSessions().containsKey(client))) { - return false; - } - - if (brokerSessionId != null && !brokerSessionId.equals(entity.getBrokerSessionId())) { - return false; - } - - if (brokerUserId != null && !brokerUserId.equals(entity.getBrokerUserId())) { - return false; - } - - if (entity.isRememberMe()) { - if (expiredRememberMe != null && expiredRefreshRememberMe != null && entity.getStarted() > expiredRememberMe && entity.getLastSessionRefresh() > expiredRefreshRememberMe) { - return false; - } - } else { - if (expired != null && expiredRefresh != null && entity.getStarted() > expired && entity.getLastSessionRefresh() > expiredRefresh) { - return false; - } - } - - if (expired == null && expiredRefresh != null && entity.getLastSessionRefresh() > expiredRefresh) { - return false; - } - return true; - }; + return (Predicate) entity -> + realm.equals(entity.getRealm().getId()) && + (user == null || entity.getUser().getId().equals(user)) && + (client == null || (entity.getAuthenticatedClientSessions() != null && entity.getAuthenticatedClientSessions().containsKey(client))) && + (brokerSessionId == null || brokerSessionId.equals(entity.getBrokerSessionId())) && + (brokerUserId == null || brokerUserId.equals(entity.getBrokerUserId())); } - public static class ExternalizerImpl implements Externalizer { - - private static final int VERSION_1 = 1; - private static final int VERSION_2 = 2; - - @Override - public void writeObject(ObjectOutput output, UserSessionPredicate obj) throws IOException { - output.writeByte(VERSION_2); - - MarshallUtil.marshallString(obj.realm, output); - MarshallUtil.marshallString(obj.user, output); - MarshallUtil.marshallString(obj.client, output); - KeycloakMarshallUtil.marshall(obj.expired, output); - KeycloakMarshallUtil.marshall(obj.expiredRefresh, output); - KeycloakMarshallUtil.marshall(obj.expiredRememberMe, output); - KeycloakMarshallUtil.marshall(obj.expiredRefreshRememberMe, output); - MarshallUtil.marshallString(obj.brokerSessionId, output); - MarshallUtil.marshallString(obj.brokerUserId, output); - - } - - @Override - public UserSessionPredicate 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 UserSessionPredicate readObjectVersion1(ObjectInput input) throws IOException, ClassNotFoundException { - UserSessionPredicate res = new UserSessionPredicate(MarshallUtil.unmarshallString(input)); - res.user(MarshallUtil.unmarshallString(input)); - res.client(MarshallUtil.unmarshallString(input)); - res.expired(KeycloakMarshallUtil.unmarshallInteger(input), KeycloakMarshallUtil.unmarshallInteger(input)); - res.brokerSessionId(MarshallUtil.unmarshallString(input)); - res.brokerUserId(MarshallUtil.unmarshallString(input)); - return res; - } - - public UserSessionPredicate readObjectVersion2(ObjectInput input) throws IOException, ClassNotFoundException { - UserSessionPredicate res = new UserSessionPredicate(MarshallUtil.unmarshallString(input)); - res.user(MarshallUtil.unmarshallString(input)); - res.client(MarshallUtil.unmarshallString(input)); - res.expired(KeycloakMarshallUtil.unmarshallInteger(input), KeycloakMarshallUtil.unmarshallInteger(input), - KeycloakMarshallUtil.unmarshallInteger(input), KeycloakMarshallUtil.unmarshallInteger(input)); - res.brokerSessionId(MarshallUtil.unmarshallString(input)); - res.brokerUserId(MarshallUtil.unmarshallString(input)); - return res; - } - } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/util/KeycloakMarshallUtil.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/util/KeycloakMarshallUtil.java deleted file mode 100644 index dbb8689adb..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/util/KeycloakMarshallUtil.java +++ /dev/null @@ -1,189 +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.sessions.infinispan.util; - -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -import org.infinispan.commons.marshall.Externalizer; -import org.infinispan.commons.marshall.MarshallUtil; -import org.jboss.logging.Logger; - -/** - * - * Helper to optimize marshalling/unmarhsalling of some types - * - * @author Marek Posolda - */ -public class KeycloakMarshallUtil { - - public static final Externalizer STRING_EXT = new StringExternalizer(); - - public static final Externalizer UUID_EXT = new Externalizer() { - @Override - public void writeObject(ObjectOutput output, UUID uuid) throws IOException { - MarshallUtil.marshallUUID(uuid, output, true); - } - - @Override - public UUID readObject(ObjectInput input) throws IOException, ClassNotFoundException { - return MarshallUtil.unmarshallUUID(input, true); - } - }; - - // MAP - - public static void writeMap(Map map, Externalizer keyExternalizer, Externalizer valueExternalizer, ObjectOutput output) throws IOException { - if (map == null) { - output.writeByte(0); - } else { - output.writeByte(1); - - // Copy the map as it can be updated concurrently - Map copy = new HashMap<>(map); - //Map copy = map; - - output.writeInt(copy.size()); - - for (Map.Entry entry : copy.entrySet()) { - keyExternalizer.writeObject(output, entry.getKey()); - valueExternalizer.writeObject(output, entry.getValue()); - } - } - } - - public static > TYPED_MAP readMap(ObjectInput input, - Externalizer keyExternalizer, Externalizer valueExternalizer, - MarshallUtil.MapBuilder mapBuilder) throws IOException, ClassNotFoundException { - byte b = input.readByte(); - if (b == 0) { - return null; - } else { - - int size = input.readInt(); - - TYPED_MAP map = mapBuilder.build(size); - - for (int i=0 ; i void writeCollection(Collection col, Externalizer valueExternalizer, ObjectOutput output) throws IOException { - if (col == null) { - output.writeByte(0); - } else { - output.writeByte(1); - - // Copy the collection as it can be updated concurrently - Collection copy = new LinkedList<>(col); - - output.writeInt(copy.size()); - - for (E entry : copy) { - valueExternalizer.writeObject(output, entry); - } - } - } - - public static > T readCollection(ObjectInput input, Externalizer valueExternalizer, - MarshallUtil.CollectionBuilder colBuilder) throws ClassNotFoundException, IOException { - byte b = input.readByte(); - if (b == 0) { - return null; - } else { - - int size = input.readInt(); - - T col = colBuilder.build(size); - - for (int i=0 ; i implements MarshallUtil.MapBuilder> { - - @Override - public ConcurrentHashMap build(int size) { - return new ConcurrentHashMap<>(size); - } - - } - - - private static class StringExternalizer implements Externalizer { - - @Override - public void writeObject(ObjectOutput output, String str) throws IOException { - MarshallUtil.marshallString(str, output); - } - - @Override - public String readObject(ObjectInput input) throws IOException, ClassNotFoundException { - return MarshallUtil.unmarshallString(input); - } - - } - -} diff --git a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/TestCacheManagerFactory.java b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/TestCacheManagerFactory.java index 1c015c0338..7515a7995d 100644 --- a/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/TestCacheManagerFactory.java +++ b/model/infinispan/src/test/java/org/keycloak/cluster/infinispan/TestCacheManagerFactory.java @@ -22,12 +22,12 @@ import org.infinispan.configuration.cache.Configuration; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.configuration.cache.StoreConfigurationBuilder; import org.infinispan.configuration.global.GlobalConfigurationBuilder; -import org.infinispan.jboss.marshalling.core.JBossUserMarshaller; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.persistence.remote.configuration.ExhaustedAction; import org.infinispan.persistence.remote.configuration.RemoteStoreConfigurationChildBuilder; import org.keycloak.connections.infinispan.InfinispanConnectionProvider; +import org.keycloak.marshalling.Marshalling; /** * @author Marek Posolda @@ -42,10 +42,7 @@ class TestCacheManagerFactory { GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder(); gcb = gcb.clusteredDefault(); gcb.transport().clusterName("test-clustering-" + threadId); - // 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 - gcb.serialization().marshaller(new JBossUserMarshaller()); + Marshalling.configure(gcb); gcb.jmx().domain(InfinispanConnectionProvider.JMX_DOMAIN + "-" + threadId).enable(); EmbeddedCacheManager cacheManager = new DefaultCacheManager(gcb.build()); diff --git a/model/storage-private/pom.xml b/model/storage-private/pom.xml index 851e136ede..69638558fc 100644 --- a/model/storage-private/pom.xml +++ b/model/storage-private/pom.xml @@ -49,6 +49,11 @@ jboss-logging-annotations provided + + org.infinispan.protostream + protostream + provided + org.hamcrest hamcrest diff --git a/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo26_0_0.java b/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo26_0_0.java new file mode 100644 index 0000000000..265e9622b8 --- /dev/null +++ b/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo26_0_0.java @@ -0,0 +1,60 @@ +/* + * 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.migration.migrators; + + +import java.lang.invoke.MethodHandles; + +import org.jboss.logging.Logger; +import org.keycloak.migration.ModelVersion; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserSessionProvider; +import org.keycloak.representations.idm.RealmRepresentation; + +public class MigrateTo26_0_0 implements Migration { + + public static final ModelVersion VERSION = new ModelVersion("26.0.0"); + + private static final Logger LOG = Logger.getLogger(MethodHandles.lookup().lookupClass()); + + @Override + public ModelVersion getVersion() { + return VERSION; + } + + @Override + public void migrate(KeycloakSession session) { + // migrate jboss-marshalling to infinispan protostream - do this only on upgrade, not on import + UserSessionProvider userSessions = session.sessions(); + if (userSessions != null) { // can be null in the test suite. + userSessions.migrate(VERSION.toString()); + } + + session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm)); + } + + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(session, realm); + } + + private void migrateRealm(KeycloakSession session, RealmModel realm) { + } +} + diff --git a/model/storage-private/src/main/java/org/keycloak/storage/datastore/DefaultMigrationManager.java b/model/storage-private/src/main/java/org/keycloak/storage/datastore/DefaultMigrationManager.java index 04eff8e419..90f8c45bfc 100644 --- a/model/storage-private/src/main/java/org/keycloak/storage/datastore/DefaultMigrationManager.java +++ b/model/storage-private/src/main/java/org/keycloak/storage/datastore/DefaultMigrationManager.java @@ -40,6 +40,7 @@ import org.keycloak.migration.migrators.MigrateTo23_0_0; import org.keycloak.migration.migrators.MigrateTo24_0_0; import org.keycloak.migration.migrators.MigrateTo24_0_3; import org.keycloak.migration.migrators.MigrateTo25_0_0; +import org.keycloak.migration.migrators.MigrateTo26_0_0; import org.keycloak.migration.migrators.MigrateTo2_0_0; import org.keycloak.migration.migrators.MigrateTo2_1_0; import org.keycloak.migration.migrators.MigrateTo2_2_0; @@ -118,7 +119,8 @@ public class DefaultMigrationManager implements MigrationManager { new MigrateTo23_0_0(), new MigrateTo24_0_0(), new MigrateTo24_0_3(), - new MigrateTo25_0_0() + new MigrateTo25_0_0(), + new MigrateTo26_0_0(), }; private final KeycloakSession session; diff --git a/model/storage-private/src/main/java/org/keycloak/storage/managers/UserStorageSyncManager.java b/model/storage-private/src/main/java/org/keycloak/storage/managers/UserStorageSyncManager.java index 1b58186da2..c2b99b0ffa 100755 --- a/model/storage-private/src/main/java/org/keycloak/storage/managers/UserStorageSyncManager.java +++ b/model/storage-private/src/main/java/org/keycloak/storage/managers/UserStorageSyncManager.java @@ -16,6 +16,8 @@ */ package org.keycloak.storage.managers; +import org.infinispan.protostream.annotations.ProtoField; +import org.infinispan.protostream.annotations.ProtoTypeId; import org.jboss.logging.Logger; import org.keycloak.cluster.ClusterEvent; import org.keycloak.cluster.ClusterListener; @@ -355,12 +357,14 @@ public class UserStorageSyncManager { // Send to cluster during each update or remove of federationProvider, so all nodes can update sync periods + @ProtoTypeId(65540) public static class UserStorageProviderClusterEvent implements ClusterEvent { private boolean removed; private String realmId; private UserStorageProviderModel storageProvider; + @ProtoField(1) public boolean isRemoved() { return removed; } @@ -369,6 +373,7 @@ public class UserStorageSyncManager { this.removed = removed; } + @ProtoField(2) public String getRealmId() { return realmId; } @@ -377,6 +382,7 @@ public class UserStorageSyncManager { this.realmId = realmId; } + @ProtoField(3) public UserStorageProviderModel getStorageProvider() { return storageProvider; } diff --git a/model/storage/pom.xml b/model/storage/pom.xml index bbdb17870d..0823e33417 100644 --- a/model/storage/pom.xml +++ b/model/storage/pom.xml @@ -38,6 +38,11 @@ jboss-logging-annotations provided + + org.infinispan.protostream + protostream + provided + org.hamcrest hamcrest diff --git a/model/storage/src/main/java/org/keycloak/storage/UserStorageProviderModel.java b/model/storage/src/main/java/org/keycloak/storage/UserStorageProviderModel.java index e145c40225..2fa010dcb7 100755 --- a/model/storage/src/main/java/org/keycloak/storage/UserStorageProviderModel.java +++ b/model/storage/src/main/java/org/keycloak/storage/UserStorageProviderModel.java @@ -17,6 +17,7 @@ package org.keycloak.storage; +import org.infinispan.protostream.annotations.ProtoTypeId; import org.keycloak.component.ComponentModel; /** @@ -25,6 +26,7 @@ import org.keycloak.component.ComponentModel; * @author Marek Posolda * @author Bill Burke */ +@ProtoTypeId(65539) //see org.keycloak.Marshalling public class UserStorageProviderModel extends CacheableStorageProviderModel { public static final String IMPORT_ENABLED = "importEnabled"; diff --git a/quarkus/runtime/pom.xml b/quarkus/runtime/pom.xml index 6848136688..79d4b4617b 100644 --- a/quarkus/runtime/pom.xml +++ b/quarkus/runtime/pom.xml @@ -584,10 +584,6 @@ org.infinispan infinispan-core - - org.infinispan - infinispan-jboss-marshalling - jakarta.xml.bind jakarta.xml.bind-api diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/CacheManagerFactory.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/CacheManagerFactory.java index ad99c3b9ad..54766537c7 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/CacheManagerFactory.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/storage/legacy/infinispan/CacheManagerFactory.java @@ -17,14 +17,6 @@ package org.keycloak.quarkus.runtime.storage.legacy.infinispan; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - import io.micrometer.core.instrument.Metrics; import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.impl.ConfigurationProperties; @@ -53,6 +45,13 @@ import org.keycloak.marshalling.Marshalling; import org.keycloak.quarkus.runtime.configuration.Configuration; import javax.net.ssl.SSLContext; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import static org.keycloak.config.CachingOptions.CACHE_EMBEDDED_MTLS_KEYSTORE_FILE_PROPERTY; import static org.keycloak.config.CachingOptions.CACHE_EMBEDDED_MTLS_KEYSTORE_PASSWORD_PROPERTY; diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/UserSessionModelDelegate.java b/server-spi-private/src/main/java/org/keycloak/models/utils/UserSessionModelDelegate.java index fe6d8c751d..e9f328d891 100644 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/UserSessionModelDelegate.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/UserSessionModelDelegate.java @@ -43,10 +43,12 @@ public class UserSessionModelDelegate implements UserSessionModel { return delegate.getRealm(); } + @Override public String getBrokerSessionId() { return delegate.getBrokerSessionId(); } + @Override public String getBrokerUserId() { return delegate.getBrokerUserId(); } @@ -55,78 +57,97 @@ public class UserSessionModelDelegate implements UserSessionModel { return delegate.getUser(); } + @Override public String getLoginUsername() { return delegate.getLoginUsername(); } + @Override public String getIpAddress() { return delegate.getIpAddress(); } + @Override public String getAuthMethod() { return delegate.getAuthMethod(); } + @Override public boolean isRememberMe() { return delegate.isRememberMe(); } + @Override public int getStarted() { return delegate.getStarted(); } + @Override public int getLastSessionRefresh() { return delegate.getLastSessionRefresh(); } + @Override public void setLastSessionRefresh(int seconds) { delegate.setLastSessionRefresh(seconds); } + @Override public boolean isOffline() { return delegate.isOffline(); } + @Override public Map getAuthenticatedClientSessions() { return delegate.getAuthenticatedClientSessions(); } + @Override public AuthenticatedClientSessionModel getAuthenticatedClientSessionByClient(String clientUUID) { return delegate.getAuthenticatedClientSessionByClient(clientUUID); } + @Override public void removeAuthenticatedClientSessions(Collection removedClientUUIDS) { delegate.removeAuthenticatedClientSessions(removedClientUUIDS); } + @Override public String getNote(String name) { return delegate.getNote(name); } + @Override public void setNote(String name, String value) { delegate.setNote(name, value); } + @Override public void removeNote(String name) { delegate.removeNote(name); } + @Override public Map getNotes() { return delegate.getNotes(); } + @Override public UserSessionModel.State getState() { return delegate.getState(); } + @Override public void setState(UserSessionModel.State state) { delegate.setState(state); } + @Override public void restartSession(RealmModel realm, UserModel user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, String brokerSessionId, String brokerUserId) { delegate.restartSession(realm, user, loginUsername, ipAddress, authMethod, rememberMe, brokerSessionId, brokerUserId); } + @Override public UserSessionModel.SessionPersistenceState getPersistenceState() { return delegate.getPersistenceState(); } diff --git a/server-spi/pom.xml b/server-spi/pom.xml index 3bc3dcb6d9..2d8133333f 100755 --- a/server-spi/pom.xml +++ b/server-spi/pom.xml @@ -62,6 +62,12 @@ httpclient provided + + + org.infinispan.protostream + protostream + provided + junit junit diff --git a/server-spi/src/main/java/org/keycloak/component/ComponentModel.java b/server-spi/src/main/java/org/keycloak/component/ComponentModel.java index 55b42d7c24..81d742781a 100755 --- a/server-spi/src/main/java/org/keycloak/component/ComponentModel.java +++ b/server-spi/src/main/java/org/keycloak/component/ComponentModel.java @@ -17,10 +17,16 @@ package org.keycloak.component; +import org.infinispan.protostream.annotations.ProtoFactory; +import org.infinispan.protostream.annotations.ProtoField; +import org.infinispan.protostream.annotations.ProtoTypeId; import org.keycloak.common.util.MultivaluedHashMap; import java.io.Serializable; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; /** * Stored configuration of a User Storage provider instance. @@ -28,7 +34,7 @@ import java.util.concurrent.ConcurrentHashMap; * @author Marek Posolda * @author Bill Burke */ -public class ComponentModel implements Serializable { +public class ComponentModel { private String id; private String name; @@ -52,6 +58,7 @@ public class ComponentModel implements Serializable { } + @ProtoField(1) public String getId() { return id; } @@ -60,6 +67,7 @@ public class ComponentModel implements Serializable { this.id = id; } + @ProtoField(2) public String getName() { return name; } @@ -136,6 +144,7 @@ public class ComponentModel implements Serializable { notes.remove(key); } + @ProtoField(3) public String getProviderId() { return providerId; } @@ -144,6 +153,7 @@ public class ComponentModel implements Serializable { this.providerId = providerId; } + @ProtoField(4) public String getProviderType() { return providerType; } @@ -152,6 +162,7 @@ public class ComponentModel implements Serializable { this.providerType = providerType; } + @ProtoField(5) public String getParentId() { return parentId; } @@ -160,6 +171,7 @@ public class ComponentModel implements Serializable { this.parentId = parentId; } + @ProtoField(6) public String getSubType() { return subType; } @@ -167,4 +179,45 @@ public class ComponentModel implements Serializable { public void setSubType(String subType) { this.subType = subType; } + + @ProtoField(7) + public List getConfigProto() { + return config.entrySet().stream().map(MultiMapEntry::new).collect(Collectors.toList()); + } + + public void setConfigProto(List configProto) { + if (configProto != null) { + configProto.forEach(multiMapEntry -> multiMapEntry.insert(config)); + } + } + + @ProtoTypeId(65538) //see org.keycloak.Marshalling + public static final class MultiMapEntry { + private final String key; + private final List value; + + @ProtoFactory + public MultiMapEntry(String key, List value) { + this.key = key; + this.value = value; + } + + public MultiMapEntry(Map.Entry> entry) { + this(entry.getKey(), entry.getValue()); + } + + @ProtoField(1) + public String getKey() { + return key; + } + + @ProtoField(2) + public List getValue() { + return value; + } + + public void insert(MultivaluedHashMap config) { + config.put(key, value); + } + } } diff --git a/server-spi/src/main/java/org/keycloak/models/UserSessionModel.java b/server-spi/src/main/java/org/keycloak/models/UserSessionModel.java index daacab66dd..9693debbbe 100755 --- a/server-spi/src/main/java/org/keycloak/models/UserSessionModel.java +++ b/server-spi/src/main/java/org/keycloak/models/UserSessionModel.java @@ -17,10 +17,13 @@ package org.keycloak.models; +import org.infinispan.protostream.annotations.Proto; +import org.infinispan.protostream.annotations.ProtoTypeId; +import org.keycloak.util.EnumWithStableIndex; + import java.util.Collection; import java.util.Map; import java.util.Objects; -import org.keycloak.util.EnumWithStableIndex; /** * @author Stian Thorgersen @@ -77,7 +80,8 @@ public interface UserSessionModel { */ default AuthenticatedClientSessionModel getAuthenticatedClientSessionByClient(String clientUUID) { return getAuthenticatedClientSessions().get(clientUUID); - }; + } + /** * Removes authenticated client sessions for all clients whose UUID is present in {@code removedClientUUIDS} parameter. * @param removedClientUUIDS @@ -96,6 +100,8 @@ public interface UserSessionModel { // Will completely restart whole state of user session. It will just keep same ID. void restartSession(RealmModel realm, UserModel user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, String brokerSessionId, String brokerUserId); + @ProtoTypeId(65536) // see org.keycloak.Marshalling + @Proto enum State implements EnumWithStableIndex { LOGGED_IN(0), LOGGING_OUT(1), diff --git a/server-spi/src/main/java/org/keycloak/sessions/CommonClientSessionModel.java b/server-spi/src/main/java/org/keycloak/sessions/CommonClientSessionModel.java index d7a3db8a1f..90d083897b 100644 --- a/server-spi/src/main/java/org/keycloak/sessions/CommonClientSessionModel.java +++ b/server-spi/src/main/java/org/keycloak/sessions/CommonClientSessionModel.java @@ -17,12 +17,15 @@ package org.keycloak.sessions; -import java.util.Map; -import java.util.Objects; +import org.infinispan.protostream.annotations.Proto; +import org.infinispan.protostream.annotations.ProtoTypeId; import org.keycloak.models.ClientModel; import org.keycloak.models.RealmModel; import org.keycloak.util.EnumWithStableIndex; +import java.util.Map; +import java.util.Objects; + /** * Predecessor of AuthenticationSessionModel, ClientLoginSessionModel and ClientSessionModel (then action tickets). Maybe we will remove it later... * @@ -51,6 +54,8 @@ public interface CommonClientSessionModel { USER_CODE_VERIFICATION } + @ProtoTypeId(65537) // see org.keycloak.Marshalling + @Proto enum ExecutionStatus implements EnumWithStableIndex { FAILED(0), SUCCESS(1), diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json index 7943357091..664048aeca 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json @@ -176,6 +176,7 @@ "connectionsInfinispan": { "default": { "jgroupsUdpMcastAddr": "${keycloak.connectionsInfinispan.jgroupsUdpMcastAddr:234.56.78.90}", + "jgroupsBindAddr": "${keycloak.connectionsInfinispan.jgroupsBindAddr:127.0.0.1}", "nodeName": "${keycloak.connectionsInfinispan.nodeName,jboss.node.name:}", "siteName": "${keycloak.connectionsInfinispan.siteName:}", "clustered": "${keycloak.connectionsInfinispan.clustered:false}", diff --git a/testsuite/model/src/main/java/org/keycloak/testsuite/model/HotRodServerRule.java b/testsuite/model/src/main/java/org/keycloak/testsuite/model/HotRodServerRule.java index 91b1495a7c..7c674badd9 100644 --- a/testsuite/model/src/main/java/org/keycloak/testsuite/model/HotRodServerRule.java +++ b/testsuite/model/src/main/java/org/keycloak/testsuite/model/HotRodServerRule.java @@ -7,7 +7,6 @@ import org.infinispan.configuration.cache.BackupFailurePolicy; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.Configuration; import org.infinispan.configuration.cache.ConfigurationBuilder; -import org.infinispan.jboss.marshalling.commons.GenericJBossMarshaller; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.server.hotrod.HotRodServer; import org.infinispan.server.hotrod.configuration.HotRodServerConfiguration; @@ -15,6 +14,7 @@ import org.infinispan.server.hotrod.configuration.HotRodServerConfigurationBuild import org.junit.rules.ExternalResource; import org.keycloak.Config; import org.keycloak.connections.infinispan.InfinispanUtil; +import org.keycloak.marshalling.KeycloakModelSchema; import java.io.IOException; @@ -64,7 +64,7 @@ public class HotRodServerRule extends ExternalResource { // Create a Hot Rod client org.infinispan.client.hotrod.configuration.ConfigurationBuilder remoteBuilder = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder(); - remoteBuilder.marshaller(new GenericJBossMarshaller()); + remoteBuilder.addContextInitializers(KeycloakModelSchema.INSTANCE); org.infinispan.client.hotrod.configuration.Configuration cfg = remoteBuilder .addServers(hotRodServer.getHost() + ":" + hotRodServer.getPort() + ";" + hotRodServer2.getHost() + ":" + hotRodServer2.getPort()).build(); @@ -114,10 +114,7 @@ public class HotRodServerRule extends ExternalResource { public static ConfigurationBuilder createCacheConfigurationBuilder() { ConfigurationBuilder builder = new ConfigurationBuilder(); - - // need to force the encoding to application/x-jboss-marshalling to avoid unnecessary conversion of keys/values. See WFLY-14356. - builder.encoding().mediaType(MediaType.APPLICATION_JBOSS_MARSHALLING_TYPE); - + builder.encoding().mediaType(MediaType.APPLICATION_PROTOSTREAM); return builder; } diff --git a/testsuite/model/src/main/resources/hotrod/hotrod1.xml b/testsuite/model/src/main/resources/hotrod/hotrod1.xml index 7fdfcfb4a0..a44d0ddcb0 100644 --- a/testsuite/model/src/main/resources/hotrod/hotrod1.xml +++ b/testsuite/model/src/main/resources/hotrod/hotrod1.xml @@ -43,7 +43,5 @@ - - \ No newline at end of file diff --git a/testsuite/model/src/main/resources/hotrod/hotrod2.xml b/testsuite/model/src/main/resources/hotrod/hotrod2.xml index 42881a6926..365720cb27 100644 --- a/testsuite/model/src/main/resources/hotrod/hotrod2.xml +++ b/testsuite/model/src/main/resources/hotrod/hotrod2.xml @@ -43,7 +43,5 @@ - - \ No newline at end of file diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelTest.java index 7ae27f73ec..2bb90e5721 100644 --- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelTest.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/KeycloakModelTest.java @@ -392,7 +392,7 @@ public abstract class KeycloakModelTest { CountDownLatch start = new CountDownLatch(numThreads); CountDownLatch stop = new CountDownLatch(numThreads); Callable independentTask = () -> inIndependentFactory(() -> { - + LOG.infof("Started Keycloak server in thread: %s", Thread.currentThread().getName()); // use the latch to ensure that all caches are online while the transaction below runs to avoid a RemoteException start.countDown(); start.await(); @@ -486,11 +486,11 @@ public abstract class KeycloakModelTest { throw new IllegalStateException("USE_DEFAULT_FACTORY must be false to use an independent factory"); } KeycloakSessionFactory original = getFactory(); - KeycloakSessionFactory factory = createKeycloakSessionFactory(); try { - setFactory(factory); + setFactory(createKeycloakSessionFactory()); return task.call(); } catch (Exception ex) { + LOG.errorf(ex, "Exception caught while starting Keycloak server in thread %s", Thread.currentThread().getName()); throw new RuntimeException(ex); } finally { closeKeycloakSessionFactory(); diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/infinispan/CacheExpirationTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/infinispan/CacheExpirationTest.java index bb0f52a582..c91dde7aca 100644 --- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/infinispan/CacheExpirationTest.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/infinispan/CacheExpirationTest.java @@ -66,8 +66,8 @@ public class CacheExpirationTest extends KeycloakModelTest { .filter(me -> me.getValue() instanceof AuthenticationSessionAuthNoteUpdateEvent) .forEach((c, me) -> c.remove(me.getKey())); - cache.put("1-2", AuthenticationSessionAuthNoteUpdateEvent.create("g1", "p1", "r1", Collections.emptyMap()), 30, TimeUnit.SECONDS); - cache.put("1-2-3", AuthenticationSessionAuthNoteUpdateEvent.create("g2", "p2", "r2", Collections.emptyMap()), 30, TimeUnit.SECONDS); + cache.put("1-2", AuthenticationSessionAuthNoteUpdateEvent.create("g1", "p1", Collections.emptyMap()), 30, TimeUnit.SECONDS); + cache.put("1-2-3", AuthenticationSessionAuthNoteUpdateEvent.create("g2", "p2", Collections.emptyMap()), 30, TimeUnit.SECONDS); }); Instant expiryInstant = Instant.now().plusSeconds(30); diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/CrossDCInfinispan.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/CrossDCInfinispan.java index 23e0e69202..f7096a9a63 100644 --- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/CrossDCInfinispan.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/CrossDCInfinispan.java @@ -57,6 +57,7 @@ public class CrossDCInfinispan extends KeycloakModelParameters { .config("siteName", siteName(NODE_COUNTER.get())) .config("remoteStorePort", siteName(NODE_COUNTER.get()).equals("site-2") ? "11333" : "11222") .config("jgroupsUdpMcastAddr", mcastAddr(NODE_COUNTER.get())) + .config("jgroupsBindAddr", "127.0.0.1") // bind to localhost for testing .spi(UserSessionSpi.NAME) .provider(InfinispanUserSessionProviderFactory.PROVIDER_ID) .config("offlineSessionCacheEntryLifespanOverride", "43200")