From d4d807237064b754f030cd8268cef50aacd811ab Mon Sep 17 00:00:00 2001 From: David Byron Date: Mon, 23 May 2022 15:48:46 -0700 Subject: [PATCH] Treat a SerializationException retrieving a session as though there were no session. This makes zero-downtime / seamless upgrades possible in more cases. Currently, upgrading spring-security across versions that change SpringSecurityCoreVersion.SERIAL_VERSION_ID requires manual deletion of cached sessions. --- .../data/redis/RedisIndexedSessionRepository.java | 13 +++++++++++-- .../redis/RedisIndexedSessionRepositoryTests.java | 12 +++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java b/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java index 19f3e0a25..421e1ddee 100644 --- a/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java +++ b/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2021 the original author or authors. + * Copyright 2014-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; import org.springframework.data.redis.util.ByteUtils; import org.springframework.session.DelegatingIndexResolver; import org.springframework.session.FindByIndexNameSessionRepository; @@ -454,7 +455,15 @@ public Map findByIndexNameAndIndexValue(String indexName, * @return the Redis session */ private RedisSession getSession(String id, boolean allowExpired) { - Map entries = getSessionBoundHashOperations(id).entries(); + Map entries; + try { + entries = getSessionBoundHashOperations(id).entries(); + } + catch (SerializationException ex) { + // An error deserializing is equivalent to not having any information at all. + logger.warn("exception getting session " + id, ex); + return null; + } if (entries.isEmpty()) { return null; } diff --git a/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryTests.java b/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryTests.java index 73e1f690d..890c3d5fd 100644 --- a/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryTests.java +++ b/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 the original author or authors. + * Copyright 2014-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,6 +43,7 @@ import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.session.FlushMode; import org.springframework.session.MapSession; @@ -394,6 +395,15 @@ void getSessionExpired() { assertThat(this.redisRepository.findById(expiredId)).isNull(); } + @Test + void getSessionIncompatible() { + String incompatibleId = "incompatible"; + + given(this.redisOperations.boundHashOps(getKey(incompatibleId))).willReturn(this.boundHashOperations); + given(this.boundHashOperations.entries()).willThrow(new SerializationException("arbitrary exception")); + assertThat(this.redisRepository.findById(incompatibleId)).isNull(); + } + @Test @SuppressWarnings("unchecked") void findByPrincipalNameExpired() {