Skip to content

Instantly share code, notes, and snippets.

@magro
Last active December 21, 2015 21:48
Show Gist options
  • Save magro/6370466 to your computer and use it in GitHub Desktop.
Save magro/6370466 to your computer and use it in GitHub Desktop.
A custom kryo serializer for the Spring Security User class - for memcached-session-manager's kryo serialization. Can be registered as customConverter in the msm config (see https://code.google.com/p/memcached-session-manager/wiki/SetupAndConfiguration), s.th. like: <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" ... tra…
package de.javakaffee.web.msm.serializer.kryo;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.serialize.IntSerializer;
import com.esotericsoftware.kryo.serialize.SimpleSerializer;
import com.esotericsoftware.kryo.serialize.StringSerializer;
/**
* Provides a custom kryo serializer for the Spring Security User class.
* <p>
* This is needed because the User class internally contains a collection
* of {@link GrantedAuthority}, which is actually a TreeSet with a
* Comparator. During deserialization kryo creates a TreeSet *without*
* any comparator and therefore expects that the contained items are
* Comparable, which is not the case for SimpleGrantedAuthority - ClassCastException.
* </p>
* <p>
* Motivated by <a href="http://code.google.com/p/memcached-session-manager/issues/detail?id=145">
* issue #145: Deserialization fails on ConcurrentHashMap in Spring User object
* </a>.
* </p>
* @author Martin Grotzke
*/
public class SpringSecurityUserRegistration implements KryoCustomization {
@Override
public void customize(final Kryo kryo) {
kryo.register( User.class, new SpringSecurityUserSerializer( kryo ) );
}
static class SpringSecurityUserSerializer extends SimpleSerializer<User> {
private final Kryo _kryo;
public SpringSecurityUserSerializer(final Kryo kryo) {
_kryo = kryo;
}
@Override
public User read(final ByteBuffer buffer) {
final String password = StringSerializer.get(buffer);
final String username = StringSerializer.get(buffer);
final int size = IntSerializer.get(buffer, true);
final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(size);
for (int i = 0; i < size; i++) {
authorities.add((GrantedAuthority)_kryo.readClassAndObject(buffer));
}
final boolean accountNonExpired = buffer.get() == 1;
final boolean accountNonLocked = buffer.get() == 1;
final boolean credentialsNonExpired = buffer.get() == 1;
final boolean enabled = buffer.get() == 1;
return new User(username, password, enabled, accountNonExpired, credentialsNonExpired,
accountNonLocked, authorities);
}
@Override
public void write(final ByteBuffer buffer, final User user) {
StringSerializer.put(buffer, user.getPassword());
StringSerializer.put(buffer, user.getUsername());
final Collection<GrantedAuthority> authorities = user.getAuthorities();
IntSerializer.put(buffer, authorities.size(), true);
for (final GrantedAuthority item : authorities) {
_kryo.writeClassAndObject(buffer, item);
}
put(buffer, user.isAccountNonExpired());
put(buffer, user.isAccountNonLocked());
put(buffer, user.isCredentialsNonExpired());
put(buffer, user.isEnabled());
}
private void put(final ByteBuffer buffer, final boolean value) {
buffer.put(value ? (byte)1 : (byte)0);
}
}
}
@wsdflink
Copy link

wsdflink commented Jul 3, 2015

Hi, Martin, i add config transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
customConverter="de.javakaffee.web.msm.serializer.kryo.SpringSecurityUserRegistration"
in tomcat config,and i get this error.
INFO: Could not store session 5E8DA4A26B75BE055E19E55CF6DC64E7-n1 in memcached.
java.util.concurrent.ExecutionException: com.esotericsoftware.kryo.SerializationException: Unable to serialize object of type: java.util.concurrent.ConcurrentHashMap
at de.javakaffee.web.msm.BackupSessionService$SynchronousExecutorService.submit(BackupSessionService.java:348)
at de.javakaffee.web.msm.BackupSessionService.backupSession(BackupSessionService.java:205)
at de.javakaffee.web.msm.MemcachedSessionService.backupSession(MemcachedSessionService.java:1040)
at de.javakaffee.web.msm.RequestTrackingHostValve.backupSession(RequestTrackingHostValve.java:230)
at de.javakaffee.web.msm.RequestTrackingHostValve.invoke(RequestTrackingHostValve.java:159)
at de.javakaffee.web.msm.RequestTrackingHostValve.invoke(RequestTrackingHostValve.java:124)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2442)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2431)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: com.esotericsoftware.kryo.SerializationException: Unable to serialize object of type: java.util.concurrent.ConcurrentHashMap
at com.esotericsoftware.kryo.Kryo.writeObject(Kryo.java:524)
at com.esotericsoftware.kryo.ObjectBuffer.writeObject(ObjectBuffer.java:251)
at de.javakaffee.web.msm.serializer.kryo.KryoTranscoder.serializeAttributes(KryoTranscoder.java:303)
at de.javakaffee.web.msm.TranscoderService.serializeAttributes(TranscoderService.java:155)
at de.javakaffee.web.msm.BackupSessionTask.serializeAttributes(BackupSessionTask.java:176)
at de.javakaffee.web.msm.BackupSessionTask.call(BackupSessionTask.java:110)
at de.javakaffee.web.msm.BackupSessionTask.call(BackupSessionTask.java:51)
at de.javakaffee.web.msm.BackupSessionService$SynchronousExecutorService.submit(BackupSessionService.java:346)
... 17 more
Caused by: com.esotericsoftware.kryo.SerializationException: Unable to serialize object of type: org.springframework.security.core.context.SecurityContextImpl
at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:493)
at com.esotericsoftware.kryo.serialize.MapSerializer.writeObjectData(MapSerializer.java:104)
at de.javakaffee.kryoserializers.CopyForIterateMapSerializer.writeObjectData(CopyForIterateMapSerializer.java:56)
at com.esotericsoftware.kryo.Serializer.writeObject(Serializer.java:43)
at com.esotericsoftware.kryo.Kryo.writeObject(Kryo.java:520)
... 24 more
Caused by: com.esotericsoftware.kryo.SerializationException: Serialization trace:
principal (org.springframework.security.authentication.UsernamePasswordAuthenticationToken)
authentication (org.springframework.security.core.context.SecurityContextImpl)
at com.esotericsoftware.kryo.serialize.FieldSerializer.writeObjectData(FieldSerializer.java:191)
at com.esotericsoftware.kryo.serialize.ReferenceFieldSerializer.writeObjectData(ReferenceFieldSerializer.java:52)
at com.esotericsoftware.kryo.serialize.FieldSerializer.writeObjectData(FieldSerializer.java:175)
at com.esotericsoftware.kryo.serialize.ReferenceFieldSerializer.writeObjectData(ReferenceFieldSerializer.java:52)
at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:489)
... 28 more
Caused by: java.lang.NullPointerException
at com.esotericsoftware.kryo.serialize.StringSerializer.put(StringSerializer.java:29)
at de.javakaffee.web.msm.serializer.kryo.SpringSecurityUserRegistration$SpringSecurityUserSerializer.write(SpringSecurityUserRegistration.java:68)
at de.javakaffee.web.msm.serializer.kryo.SpringSecurityUserRegistration$SpringSecurityUserSerializer.write(SpringSecurityUserRegistration.java:39)
at com.esotericsoftware.kryo.serialize.SimpleSerializer.writeObjectData(SimpleSerializer.java:17)
at com.esotericsoftware.kryo.serialize.FieldSerializer.writeObjectData(FieldSerializer.java:175)
... 32 more
Could you help me ? thx.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment