Hello again,
I am not aware how to continue - because Java says it is not Serializable:
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.Object] to type [byte[]] for value 'org.springframework.security.core.context.SecurityContextImpl@e22bf567: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@e22bf567: Principal: com.temenos.payrep.authmanager.UserDetailsImpl@9dc76c3; Credentials: [PROTECTED]; Authenticated: true; Details: com.temenos.payrep.authmanager.CaptchaAuthenticationDetails@7f8e1da9; Granted Authorities: WRITE_ACCESS, READ_ACCESS'; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.io.NotSerializableException: org.springframework.dao.support.PersistenceExceptionTranslationInterceptor
org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:191)
org.springframework.session.jdbc.JdbcOperationsSessionRepository.serialize(JdbcOperationsSessionRepository.java:671)
The interfaces and classes that you have referred are as you point out, but they don't get treated as Serializable (maby something breaks the property along the chain ?):
@Component
public class UserDetailsImpl implements UserDetails {
/**
*
*/
private static final long serialVersionUID = 4358276832183116476L;
public interface UserDetails extends Serializable {
public class SecurityContextImpl implements SecurityContext {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
public interface SecurityContext extends Serializable {
public class CaptchaDAOAuthProvider extends DaoAuthenticationProvider implements Serializable {
/**
*
*/
private static final long serialVersionUID = -734845793362862112L;
Is this framework production grade or just testing out concepts ? (a.k.a.: Can it attain at least WordPress performance at first untouched deployment ?)
Because the other default "Thread Local" SessionRepositoryImpl assigns the last logged in user as the Principal of all sessions ? I wonder how NetFlix copes with that - or is this the reason behind movie piracy - the fact I can automagically become owner of the other sessions.
If you need more details, I should be able to provide limited feedback, mostly related to the framework itself not to the product being developed, according to the agreements in place.
Best regards, Dan Ștefan Stroe
Originally posted by @ssgen in https://github.com/spring-projects/spring-security/issues/7108#issuecomment-512170544
Comment From: ssgen
I've just noticed the following:
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
So, it clearly has passed the instanceof test - Java just bails out into internal method:
objectOutputStream.writeObject(object);
Another issue regarding the subject is that even if I add a special Converter
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new SecurityContextImplToByteArrayConverter());
registry.addConverter(new ByteArrayToSecurityContextImplConverter());
}
it does not get picked up by the JdbcOperationsSessionRepository at runtime init, so it is required to inject it later:
@Autowired
private JdbcOperationsSessionRepository jdbcOpSessRep;
[...]
GenericConversionService converter = new GenericConversionService();
converter.addConverter(new SecurityContextImplToByteArrayConverter());
converter.addConverter(new ByteArrayToSecurityContextImplConverter());
converter.addConverter(Object.class, byte[].class,
new SerializingConverter());
converter.addConverter(byte[].class, Object.class,
new DeserializingConverter());
this.jdbcOpSessRep.setConversionService(converter);
and even if I did that, it is useless because serialize casts it to Object and uses the generic converter regardless:
private byte[] serialize(Object object) {
return (byte[]) this.conversionService.convert(object,
TypeDescriptor.valueOf(Object.class),
TypeDescriptor.valueOf(byte[].class));
And as a final note, even the "custom" converter injected with hardships with javassist into the beautiful modular spring framework:
CtMethod goodSerializeMeth = CtNewMethod.make("private byte[] serialize(Object object) {" + System.getProperty("line.separator") +
" if (object.getClass() == org.springframework.security.core.context.SecurityContextImpl.class) {" + System.getProperty("line.separator") +
" return this.conversionService.convert((org.springframework.security.core.context.SecurityContextImpl)object," + System.getProperty("line.separator") +
" org.springframework.core.convert.TypeDescriptor.valueOf(object.getClass())," + System.getProperty("line.separator") +
" org.springframework.core.convert.TypeDescriptor.valueOf(byte[].class));" + System.getProperty("line.separator") +
" }" + System.getProperty("line.separator") +
" return (byte[]) this.conversionService.convert(object," + System.getProperty("line.separator") +
" org.springframework.core.convert.TypeDescriptor.valueOf(Object.class)," + System.getProperty("line.separator") +
" org.springframework.core.convert.TypeDescriptor.valueOf(byte[].class));" + System.getProperty("line.separator") +
"}",
overrideJdbcOperationsSessionRepository);
defined as:
public class SecurityContextImplToByteArrayConverter
implements Converter<SecurityContextImpl, byte[]> {
@Override
public byte[] convert(SecurityContextImpl source) {
return SerializationUtils.serialize(source);
}
}
errors in same ways at:
/**
* Serialize the given object to a byte array.
* @param object the object to serialize
* @return an array of bytes representing the object in a portable fashion
*/
@Nullable
public static byte[] serialize(@Nullable Object object) {
if (object == null) {
return null;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(object);
oos.flush();
}
catch (IOException ex) {
throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex);
}
return baos.toByteArray();
}
Best regards,
Comment From: ssgen
I have found the culprit that cannot be serialized :
@Autowired private UserRepository userRepo;
that is of type:
public interface UserRepository extends CrudRepository<User,Integer>
present in UserDetailsImpl of UserDetails interface.
Any idea how to get the user from database without including any reference to the CrudRepository in the class ?
Comment From: ssgen
Performed & closed.
It would be nice if the whatnots were documented and not explored by debug.
Best regards
Comment From: Luka0708
Hello, could you please tell me how you solved the issue? I have the same problem
Comment From: nelsonnetru
Hello, could you please tell me how you solved the issue? I have the same problem
Implementing the interface Serializable for your User class