3

I'm trying to rewrite some legacy code which used org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore to store the access tokens. I'm currently trying to use the RedisTokenStore instead of the previously used InMemoryTokenStore. The token gets generated and gets stored in Redis fine (Standalone redis configuration), however, deserialization of OAuth2Authentication fails with the following error:

Could not read JSON: Cannot construct instance of `org.springframework.security.oauth2.provider.OAuth2Authentication` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Since there's no default constructor for this class, the deserialization and mapping to the actual object while looking up from Redis fails.

RedisTokenStore redisTokenStore = new RedisTokenStore(jedisConnectionFactory);
redisTokenStore.setSerializationStrategy(new StandardStringSerializationStrategy() {
        @Override    
        protected <T> T deserializeInternal(byte[] bytes, Class<T> aClass) {
            return Utilities.parse(new String(bytes, StandardCharsets.UTF_8),aClass);
        }
                
        @Override    
        protected byte[] serializeInternal(Object o) {       
            return Objects.requireNonNull(Utilities.convert(o)).getBytes();
        }
});
this.tokenStore = redisTokenStore;



public static <T> T parse(String json, Class<T> clazz) {    
                try {        
                    return OBJECT_MAPPER.readValue(json, clazz);    
                } catch (IOException e) {        
                    log.error("Jackson2Json failed: " + e.getMessage());    
                }    return null;}
            
            public static String convert(Object data) {    
                try {        
                    return OBJECT_MAPPER.writeValueAsString(data);    
                } catch (JsonProcessingException e) {        
                    log.error("Conversion failed: " + e.getMessage());    
                }    
                return null;
            }

How is OAuth2Authentication object reconstructed when the token is looked up from Redis? Since it does not define a default constructor, any Jackson based serializer and object mapper won't be able to deserialize it.

Again, the serialization works great (since OAuth2Authentication implements Serializable interface) and the token gets stored fine in Redis. It just fails when the /oauth/check_token is called.

What am I missing and how is this problem dealt with while storing access token in Redis?

Addle Pate
  • 41
  • 1
  • 3

1 Answers1

1

I solved the issue by writing custom deserializer. It looks like this:

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.security.oauth2.core.AuthorizationGrantType;

import java.io.IOException;

public class AuthorizationGrantTypeCustomDeserializer extends JsonDeserializer<AuthorizationGrantType> {

    @Override
    public AuthorizationGrantType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
        Root root = p.readValueAs(Root.class);
        return root != null ?  new AuthorizationGrantType(root.value) : new AuthorizationGrantType("");
    }

    private static class Root {
        public String value;
    }

    public static SimpleModule generateModule() {
        SimpleModule authGrantModule = new SimpleModule();
        authGrantModule.addDeserializer(AuthorizationGrantType.class, new AuthorizationGrantTypeCustomDeserializer());
        return authGrantModule;
    }
}

Then I registered deserializer in objectMapper which is later used by jackson API

 ObjectMapper mapper = new ObjectMapper()
                .registerModule(AuthorizationGrantTypeCustomDeserializer.generateModule());
pokemzok
  • 1,659
  • 1
  • 19
  • 29